Include <stdlib.h> in check for sys_errlist
[xapian.git] / xapian-core / common / errno_to_string.cc
blobbe6e19229f7ce96bf7d784d95b1bfe31e4c9acc8
1 /** @file
2 * @brief Convert errno value to std::string, thread-safely if possible
3 */
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
22 * IN THE SOFTWARE.
25 #include <config.h>
27 #include "errno_to_string.h"
29 // <cstring> doesn't give us strerror_r() with Sun C++ 5.9.
30 #include <string.h>
31 #if defined HAVE__SYS_ERRLIST_AND__SYS_NERR || \
32 defined HAVE_SYS_ERRLIST_AND_SYS_NERR
33 # include <stdio.h>
34 // Under mingw and MSVC these are in stdlib.h.
35 # include <stdlib.h>
36 #endif
38 #include "str.h"
40 using namespace std;
42 void
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
48 // 2.32.
49 const char* desc = strerrordesc_np(e);
50 if (desc) {
51 s += desc;
52 } else {
53 s += "Unknown error ";
54 s += str(e);
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]) {
59 s += _sys_errlist[e];
60 } else {
61 s += "Unknown error ";
62 s += str(e);
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]) {
67 s += sys_errlist[e];
68 } else {
69 s += "Unknown error ";
70 s += str(e);
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
80 // settings.
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
85 // alternative.
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.
96 char buf[1024];
97 # ifdef STRERROR_R_CHAR_P
98 // Returns char* pointing to string describing error.
99 s += strerror_r(e, buf, sizeof(buf));
100 # else
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
103 // errno.
104 int r = strerror_r(e, buf, sizeof(buf));
105 if (r == 0) {
106 s += buf;
107 } else {
108 s += "Unknown error ";
109 s += str(e);
111 # endif
112 #else
113 // Not thread safe.
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
117 // incorporates C99.
118 s += strerror(e);
119 #endif