[ci] Update macos jobs
[xapian.git] / xapian-core / common / errno_to_string.cc
blobd5a52609db60fd63cb9a79baaef926c7c09a84fa
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 // 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.
32 #include <errno.h>
33 // <cstring> doesn't give us strerror_r() with Sun C++ 5.9.
34 #include <string.h>
35 #if defined HAVE__SYS_ERRLIST_AND__SYS_NERR || \
36 defined HAVE_SYS_ERRLIST_AND_SYS_NERR
37 # include <stdio.h>
38 // With mingw and MSVC they're provided by <stdlib.h>.
39 # include <stdlib.h>
40 #endif
42 #include "str.h"
44 using namespace std;
46 void
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
52 // 2.32.
53 const char* desc = strerrordesc_np(e);
54 if (desc) {
55 s += desc;
56 } else {
57 s += "Unknown error ";
58 s += str(e);
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]) {
63 s += _sys_errlist[e];
64 } else {
65 s += "Unknown error ";
66 s += str(e);
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]) {
71 s += sys_errlist[e];
72 } else {
73 s += "Unknown error ";
74 s += str(e);
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
84 // settings.
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
89 // alternative.
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.
100 char buf[1024];
101 # ifdef STRERROR_R_CHAR_P
102 // Returns char* pointing to string describing error.
103 s += strerror_r(e, buf, sizeof(buf));
104 # else
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
107 // errno.
108 int r = strerror_r(e, buf, sizeof(buf));
109 if (r == 0) {
110 s += buf;
111 } else {
112 s += "Unknown error ";
113 s += str(e);
115 # endif
116 #else
117 // Not thread safe.
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
121 // incorporates C99.
122 s += strerror(e);
123 #endif