2 * @brief Convert errno value to std::string, thread-safely if possible
4 /* Copyright (C) 2014,2015,2016,2021 Olly Betts
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 #include "errno_to_string.h"
29 // <cstring> doesn't give us strerror_r() with Sun C++ 5.9.
31 #if defined HAVE__SYS_ERRLIST_AND__SYS_NERR || \
32 defined HAVE_SYS_ERRLIST_AND_SYS_NERR
34 // Under mingw and MSVC these are in stdlib.h.
43 errno_to_string(int e
, string
& s
)
45 // Use a thread-safe way to convert an errno value to a string if possible.
46 #ifdef HAVE_STRERRORDESC_NP
47 // GNU-specific replacement for sys_errlist and sys_nerr, added in glibc
49 const char* desc
= strerrordesc_np(e
);
53 s
+= "Unknown error ";
56 #elif defined HAVE__SYS_ERRLIST_AND__SYS_NERR
57 // Old-style Unix fixed array of strings.
58 if (e
>= 0 && e
< _sys_nerr
&& _sys_errlist
[e
]) {
61 s
+= "Unknown error ";
64 #elif defined HAVE_SYS_ERRLIST_AND_SYS_NERR
65 // Old-style Unix fixed array of strings.
66 if (e
>= 0 && e
< sys_nerr
&& sys_errlist
[e
]) {
69 s
+= "Unknown error ";
72 #elif HAVE_DECL_STRERROR_R
73 // POSIX specifies strerror_r() to provide a thread-safe way to translate
74 // an errno value to a string.
76 // Unhelpfully this requires us to pass in a buffer, but we don't know how
77 // big to make it to reliably be able to convert all possible errno values,
78 // and the implementation is permitted to return localised strings so the
79 // maximum possible length may vary depending on the current locale
82 // If the buffer passed is too small, then with older glibc errno gets
83 // stomped on, so growing the buffer on error and retrying isn't a great
84 // answer. Hence we only use strerror_r() if we don't have a better
87 // Another reason to have support for alternative approaches is that
88 // strerror_r() is marked as "optional" by POSIX.
90 // A further complication is there's a GNU-specific strerror_r() with a
91 // different return value type.
93 // The strerror_r(3) man page on Linux suggests a buffer size of 1024
94 // characters, noting that glibc uses this size for strerror(). The
95 // actual longest on Linux in English is EILSEQ which needs 50 bytes.
97 # ifdef STRERROR_R_CHAR_P
98 // Returns char* pointing to string describing error.
99 s
+= strerror_r(e
, buf
, sizeof(buf
));
101 // XSI-compliant strerror_r returns int: 0 means success; a positive error
102 // number should be returned on error, but glibc < 2.13 returns -1 and sets
104 int r
= strerror_r(e
, buf
, sizeof(buf
));
108 s
+= "Unknown error ";
115 // We can assume the return value is non-NULL because "C99 and POSIX.1-2008
116 // require the return value to be non-NULL" and we require C++11 which