blob: 326d4b1d17876a33240cc0d8a0f90ee3f23fe823 [file] [log] [blame]
Irina Tirdeab5f053b2012-09-08 09:17:54 +03001/* $OpenBSD: strerror_r.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
2/* Public Domain <marc@snafu.org> */
3
Elliott Hughes416d7dd2014-08-18 17:28:32 -07004// G++ automatically defines _GNU_SOURCE, which then means that <string.h>
5// gives us the GNU variant.
6#undef _GNU_SOURCE
7
8#include <string.h>
9
Irina Tirdeab5f053b2012-09-08 09:17:54 +030010#include <errno.h>
11#include <limits.h>
12#include <signal.h>
13#include <stdio.h>
Irina Tirdeab5f053b2012-09-08 09:17:54 +030014
Christopher Ferris7a3681e2017-04-24 17:48:32 -070015#include <async_safe/log.h>
16
Elliott Hughes3e898472013-02-12 16:40:24 +000017#include "private/ErrnoRestorer.h"
18
Irina Tirdeab5f053b2012-09-08 09:17:54 +030019struct Pair {
20 int code;
21 const char* msg;
22};
23
24static const char* __code_string_lookup(const Pair* strings, int code) {
Yi Kong32bc0fc2018-08-02 17:31:13 -070025 for (size_t i = 0; strings[i].msg != nullptr; ++i) {
Irina Tirdeab5f053b2012-09-08 09:17:54 +030026 if (strings[i].code == code) {
27 return strings[i].msg;
28 }
29 }
Yi Kong32bc0fc2018-08-02 17:31:13 -070030 return nullptr;
Irina Tirdeab5f053b2012-09-08 09:17:54 +030031}
32
33static const Pair _sys_error_strings[] = {
Elliott Hughes92a91162018-10-15 13:12:19 -070034 {0, "Success"},
35 {EPERM, "Operation not permitted"},
36 {ENOENT, "No such file or directory"},
37 {ESRCH, "No such process"},
38 {EINTR, "Interrupted system call"},
39 {EIO, "I/O error"},
40 {ENXIO, "No such device or address"},
41 {E2BIG, "Argument list too long"},
42 {ENOEXEC, "Exec format error"},
43 {EBADF, "Bad file descriptor"},
44 {ECHILD, "No child processes"},
45 {EAGAIN, "Try again"},
46 {ENOMEM, "Out of memory"},
47 {EACCES, "Permission denied"},
48 {EFAULT, "Bad address"},
49 {ENOTBLK, "Block device required"},
50 {EBUSY, "Device or resource busy"},
51 {EEXIST, "File exists"},
52 {EXDEV, "Cross-device link"},
53 {ENODEV, "No such device"},
54 {ENOTDIR, "Not a directory"},
55 {EISDIR, "Is a directory"},
56 {EINVAL, "Invalid argument"},
57 {ENFILE, "File table overflow"},
58 {EMFILE, "Too many open files"},
59 {ENOTTY, "Not a typewriter"},
60 {ETXTBSY, "Text file busy"},
61 {EFBIG, "File too large"},
62 {ENOSPC, "No space left on device"},
63 {ESPIPE, "Illegal seek"},
64 {EROFS, "Read-only file system"},
65 {EMLINK, "Too many links"},
66 {EPIPE, "Broken pipe"},
67 {EDOM, "Math argument out of domain of func"},
68 {ERANGE, "Math result not representable"},
69 {EDEADLK, "Resource deadlock would occur"},
70 {ENAMETOOLONG, "File name too long"},
71 {ENOLCK, "No record locks available"},
72 {ENOSYS, "Function not implemented"},
73 {ENOTEMPTY, "Directory not empty"},
74 {ELOOP, "Too many symbolic links encountered"},
75 {ENOMSG, "No message of desired type"},
76 {EIDRM, "Identifier removed"},
77 {ECHRNG, "Channel number out of range"},
78 {EL2NSYNC, "Level 2 not synchronized"},
79 {EL3HLT, "Level 3 halted"},
80 {EL3RST, "Level 3 reset"},
81 {ELNRNG, "Link number out of range"},
82 {EUNATCH, "Protocol driver not attached"},
83 {ENOCSI, "No CSI structure available"},
84 {EL2HLT, "Level 2 halted"},
85 {EBADE, "Invalid exchange"},
86 {EBADR, "Invalid request descriptor"},
87 {EXFULL, "Exchange full"},
88 {ENOANO, "No anode"},
89 {EBADRQC, "Invalid request code"},
90 {EBADSLT, "Invalid slot"},
91 {EBFONT, "Bad font file format"},
92 {ENOSTR, "Device not a stream"},
93 {ENODATA, "No data available"},
94 {ETIME, "Timer expired"},
95 {ENOSR, "Out of streams resources"},
96 {ENONET, "Machine is not on the network"},
97 {ENOPKG, "Package not installed"},
98 {EREMOTE, "Object is remote"},
99 {ENOLINK, "Link has been severed"},
100 {EADV, "Advertise error"},
101 {ESRMNT, "Srmount error"},
102 {ECOMM, "Communication error on send"},
103 {EPROTO, "Protocol error"},
104 {EMULTIHOP, "Multihop attempted"},
105 {EDOTDOT, "RFS specific error"},
106 {EBADMSG, "Not a data message"},
107 {EOVERFLOW, "Value too large for defined data type"},
108 {ENOTUNIQ, "Name not unique on network"},
109 {EBADFD, "File descriptor in bad state"},
110 {EREMCHG, "Remote address changed"},
111 {ELIBACC, "Can not access a needed shared library"},
112 {ELIBBAD, "Accessing a corrupted shared library"},
113 {ELIBSCN, ".lib section in a.out corrupted"},
114 {ELIBMAX, "Attempting to link in too many shared libraries"},
115 {ELIBEXEC, "Cannot exec a shared library directly"},
116 {EILSEQ, "Illegal byte sequence"},
117 {ERESTART, "Interrupted system call should be restarted"},
118 {ESTRPIPE, "Streams pipe error"},
119 {EUSERS, "Too many users"},
120 {ENOTSOCK, "Socket operation on non-socket"},
121 {EDESTADDRREQ, "Destination address required"},
122 {EMSGSIZE, "Message too long"},
123 {EPROTOTYPE, "Protocol wrong type for socket"},
124 {ENOPROTOOPT, "Protocol not available"},
125 {EPROTONOSUPPORT, "Protocol not supported"},
126 {ESOCKTNOSUPPORT, "Socket type not supported"},
127 {EOPNOTSUPP, "Operation not supported on transport endpoint"},
128 {EPFNOSUPPORT, "Protocol family not supported"},
129 {EAFNOSUPPORT, "Address family not supported by protocol"},
130 {EADDRINUSE, "Address already in use"},
131 {EADDRNOTAVAIL, "Cannot assign requested address"},
132 {ENETDOWN, "Network is down"},
133 {ENETUNREACH, "Network is unreachable"},
134 {ENETRESET, "Network dropped connection because of reset"},
135 {ECONNABORTED, "Software caused connection abort"},
136 {ECONNRESET, "Connection reset by peer"},
137 {ENOBUFS, "No buffer space available"},
138 {EISCONN, "Transport endpoint is already connected"},
139 {ENOTCONN, "Transport endpoint is not connected"},
140 {ESHUTDOWN, "Cannot send after transport endpoint shutdown"},
141 {ETOOMANYREFS, "Too many references: cannot splice"},
142 {ETIMEDOUT, "Connection timed out"},
143 {ECONNREFUSED, "Connection refused"},
144 {EHOSTDOWN, "Host is down"},
145 {EHOSTUNREACH, "No route to host"},
146 {EALREADY, "Operation already in progress"},
147 {EINPROGRESS, "Operation now in progress"},
148 {ESTALE, "Stale NFS file handle"},
149 {EUCLEAN, "Structure needs cleaning"},
150 {ENOTNAM, "Not a XENIX named type file"},
151 {ENAVAIL, "No XENIX semaphores available"},
152 {EISNAM, "Is a named type file"},
153 {EREMOTEIO, "Remote I/O error"},
154 {EDQUOT, "Quota exceeded"},
155 {ENOMEDIUM, "No medium found"},
156 {EMEDIUMTYPE, "Wrong medium type"},
157 {ECANCELED, "Operation Canceled"},
158 {ENOKEY, "Required key not available"},
159 {EKEYEXPIRED, "Key has expired"},
160 {EKEYREVOKED, "Key has been revoked"},
161 {EKEYREJECTED, "Key was rejected by service"},
162 {EOWNERDEAD, "Owner died"},
163 {ENOTRECOVERABLE, "State not recoverable"},
164 {ERFKILL, "Operation not possible due to RF-kill"},
165 {EHWPOISON, "Memory page has hardware error"},
166 {0, nullptr}
Irina Tirdeab5f053b2012-09-08 09:17:54 +0300167};
168
Elliott Hughes95a7a642012-09-21 18:27:40 -0700169extern "C" __LIBC_HIDDEN__ const char* __strerror_lookup(int error_number) {
Elliott Hughes4198fa42012-09-17 15:23:35 -0700170 return __code_string_lookup(_sys_error_strings, error_number);
171}
172
Irina Tirdeab5f053b2012-09-08 09:17:54 +0300173int strerror_r(int error_number, char* buf, size_t buf_len) {
Elliott Hughes3e898472013-02-12 16:40:24 +0000174 ErrnoRestorer errno_restorer;
Irina Tirdeab5f053b2012-09-08 09:17:54 +0300175 size_t length;
176
Elliott Hughes4198fa42012-09-17 15:23:35 -0700177 const char* error_name = __strerror_lookup(error_number);
Yi Kong32bc0fc2018-08-02 17:31:13 -0700178 if (error_name != nullptr) {
Elliott Hughes91570ce2014-07-10 12:34:23 -0700179 length = strlcpy(buf, error_name, buf_len);
Irina Tirdeab5f053b2012-09-08 09:17:54 +0300180 } else {
Christopher Ferris7a3681e2017-04-24 17:48:32 -0700181 length = async_safe_format_buffer(buf, buf_len, "Unknown error %d", error_number);
Irina Tirdeab5f053b2012-09-08 09:17:54 +0300182 }
183 if (length >= buf_len) {
Elliott Hughes3e898472013-02-12 16:40:24 +0000184 errno_restorer.override(ERANGE);
Irina Tirdeab5f053b2012-09-08 09:17:54 +0300185 return -1;
186 }
187
Irina Tirdeab5f053b2012-09-08 09:17:54 +0300188 return 0;
189}
190
Elliott Hughes416d7dd2014-08-18 17:28:32 -0700191extern "C" char* __gnu_strerror_r(int error_number, char* buf, size_t buf_len) {
192 ErrnoRestorer errno_restorer; // The glibc strerror_r doesn't set errno if it truncates...
193 strerror_r(error_number, buf, buf_len);
194 return buf; // ...and just returns whatever fit.
195}