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 // On Linux, sys_errlist and sys_nerr need <stdio.h>, though the man page
30 // says <errno.h>. The man page seems to match other platforms such as
31 // NetBSD, so include both headers to ensure we get them.
33 // <cstring> doesn't give us strerror_r() with Sun C++ 5.9.
35 #if defined HAVE__SYS_ERRLIST_AND__SYS_NERR || \
36 defined HAVE_SYS_ERRLIST_AND_SYS_NERR
38 // With mingw and MSVC they're provided by <stdlib.h>.
47 errno_to_string(int e
, string
& s
)
49 // Use a thread-safe way to convert an errno value to a string if possible.
50 #ifdef HAVE_STRERRORDESC_NP
51 // GNU-specific replacement for sys_errlist and sys_nerr, added in glibc
53 const char* desc
= strerrordesc_np(e
);
57 s
+= "Unknown error ";
60 #elif defined HAVE__SYS_ERRLIST_AND__SYS_NERR
61 // Old-style Unix fixed array of strings.
62 if (e
>= 0 && e
< _sys_nerr
&& _sys_errlist
[e
]) {
65 s
+= "Unknown error ";
68 #elif defined HAVE_SYS_ERRLIST_AND_SYS_NERR
69 // Old-style Unix fixed array of strings.
70 if (e
>= 0 && e
< sys_nerr
&& sys_errlist
[e
]) {
73 s
+= "Unknown error ";
76 #elif HAVE_DECL_STRERROR_R
77 // POSIX specifies strerror_r() to provide a thread-safe way to translate
78 // an errno value to a string.
80 // Unhelpfully this requires us to pass in a buffer, but we don't know how
81 // big to make it to reliably be able to convert all possible errno values,
82 // and the implementation is permitted to return localised strings so the
83 // maximum possible length may vary depending on the current locale
86 // If the buffer passed is too small, then with older glibc errno gets
87 // stomped on, so growing the buffer on error and retrying isn't a great
88 // answer. Hence we only use strerror_r() if we don't have a better
91 // Another reason to have support for alternative approaches is that
92 // strerror_r() is marked as "optional" by POSIX.
94 // A further complication is there's a GNU-specific strerror_r() with a
95 // different return value type.
97 // The strerror_r(3) man page on Linux suggests a buffer size of 1024
98 // characters, noting that glibc uses this size for strerror(). The
99 // actual longest on Linux in English is EILSEQ which needs 50 bytes.
101 # ifdef STRERROR_R_CHAR_P
102 // Returns char* pointing to string describing error.
103 s
+= strerror_r(e
, buf
, sizeof(buf
));
105 // XSI-compliant strerror_r returns int: 0 means success; a positive error
106 // number should be returned on error, but glibc < 2.13 returns -1 and sets
108 int r
= strerror_r(e
, buf
, sizeof(buf
));
112 s
+= "Unknown error ";
119 // We can assume the return value is non-NULL because "C99 and POSIX.1-2008
120 // require the return value to be non-NULL" and we require C++11 which