1 /* strerror_r.c --- POSIX compatible system error routine
3 Copyright (C) 2010-2011 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 /* Written by Bruno Haible <bruno@clisp.org>, 2010. */
22 /* Enable declaration of sys_nerr and sys_errlist in <errno.h> on NetBSD. */
23 #define _NETBSD_SOURCE 1
30 # if GNULIB_defined_ESOCK /* native Windows platforms */
32 # include <winsock2.h>
37 #if (__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__) && HAVE___XPG_STRERROR_R /* glibc >= 2.3.4, cygwin >= 1.7.9 */
39 # define USE_XPG_STRERROR_R 1
41 #elif HAVE_DECL_STRERROR_R && !(__GLIBC__ >= 2 || defined __UCLIBC__)
43 /* The system's strerror_r function is OK, except that its third argument
44 is 'int', not 'size_t', or its return type is wrong. */
48 # define USE_SYSTEM_STRERROR_R 1
50 #else /* (__GLIBC__ >= 2 || defined __UCLIBC__ ? !HAVE___XPG_STRERROR_R : !HAVE_DECL_STRERROR_R) */
52 /* Use the system's strerror(). */
55 # define USE_SYSTEM_STRERROR 1
57 # if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __sgi || (defined __sun && !defined _LP64)
59 /* No locking needed. */
61 /* Get catgets internationalization functions. */
63 # include <nl_types.h>
66 /* Get sys_nerr, sys_errlist on HP-UX (otherwise only declared in C++ mode).
67 Get sys_nerr, sys_errlist on IRIX (otherwise only declared with _SGIAPI). */
68 # if defined __hpux || defined __sgi
70 extern char *sys_errlist[];
73 /* Get sys_nerr on Solaris. */
74 # if defined __sun && !defined _LP64
78 /* Get sys_nerr, sys_errlist on native Windows. */
83 # include "glthread/lock.h"
85 /* This lock protects the buffer returned by strerror(). We assume that
86 no other uses of strerror() exist in the program. */
87 gl_lock_define_initialized(static, strerror_lock)
95 strerror_r (int errnum, char *buf, size_t buflen)
98 #if GNULIB_defined_ETXTBSY \
99 || GNULIB_defined_ESOCK \
100 || GNULIB_defined_ENOMSG \
101 || GNULIB_defined_EIDRM \
102 || GNULIB_defined_ENOLINK \
103 || GNULIB_defined_EPROTO \
104 || GNULIB_defined_EMULTIHOP \
105 || GNULIB_defined_EBADMSG \
106 || GNULIB_defined_EOVERFLOW \
107 || GNULIB_defined_ENOTSUP \
108 || GNULIB_defined_ESTALE \
109 || GNULIB_defined_EDQUOT \
110 || GNULIB_defined_ECANCELED
112 char const *msg = NULL;
113 /* These error messages are taken from glibc/sysdeps/gnu/errlist.c. */
116 # if GNULIB_defined_ETXTBSY
118 msg = "Text file busy";
122 # if GNULIB_defined_ESOCK /* native Windows platforms */
123 /* EWOULDBLOCK is the same as EAGAIN. */
125 msg = "Operation now in progress";
128 msg = "Operation already in progress";
131 msg = "Socket operation on non-socket";
134 msg = "Destination address required";
137 msg = "Message too long";
140 msg = "Protocol wrong type for socket";
143 msg = "Protocol not available";
145 case EPROTONOSUPPORT:
146 msg = "Protocol not supported";
148 case ESOCKTNOSUPPORT:
149 msg = "Socket type not supported";
152 msg = "Operation not supported";
155 msg = "Protocol family not supported";
158 msg = "Address family not supported by protocol";
161 msg = "Address already in use";
164 msg = "Cannot assign requested address";
167 msg = "Network is down";
170 msg = "Network is unreachable";
173 msg = "Network dropped connection on reset";
176 msg = "Software caused connection abort";
179 msg = "Connection reset by peer";
182 msg = "No buffer space available";
185 msg = "Transport endpoint is already connected";
188 msg = "Transport endpoint is not connected";
191 msg = "Cannot send after transport endpoint shutdown";
194 msg = "Too many references: cannot splice";
197 msg = "Connection timed out";
200 msg = "Connection refused";
203 msg = "Too many levels of symbolic links";
206 msg = "Host is down";
209 msg = "No route to host";
212 msg = "Too many processes";
215 msg = "Too many users";
218 msg = "Disk quota exceeded";
221 msg = "Stale NFS file handle";
224 msg = "Object is remote";
227 /* WSA_INVALID_HANDLE maps to EBADF */
228 /* WSA_NOT_ENOUGH_MEMORY maps to ENOMEM */
229 /* WSA_INVALID_PARAMETER maps to EINVAL */
230 case WSA_OPERATION_ABORTED:
231 msg = "Overlapped operation aborted";
233 case WSA_IO_INCOMPLETE:
234 msg = "Overlapped I/O event object not in signaled state";
237 msg = "Overlapped operations will complete later";
239 /* WSAEINTR maps to EINTR */
240 /* WSAEBADF maps to EBADF */
241 /* WSAEACCES maps to EACCES */
242 /* WSAEFAULT maps to EFAULT */
243 /* WSAEINVAL maps to EINVAL */
244 /* WSAEMFILE maps to EMFILE */
245 /* WSAEWOULDBLOCK maps to EWOULDBLOCK */
246 /* WSAEINPROGRESS is EINPROGRESS */
247 /* WSAEALREADY is EALREADY */
248 /* WSAENOTSOCK is ENOTSOCK */
249 /* WSAEDESTADDRREQ is EDESTADDRREQ */
250 /* WSAEMSGSIZE is EMSGSIZE */
251 /* WSAEPROTOTYPE is EPROTOTYPE */
252 /* WSAENOPROTOOPT is ENOPROTOOPT */
253 /* WSAEPROTONOSUPPORT is EPROTONOSUPPORT */
254 /* WSAESOCKTNOSUPPORT is ESOCKTNOSUPPORT */
255 /* WSAEOPNOTSUPP is EOPNOTSUPP */
256 /* WSAEPFNOSUPPORT is EPFNOSUPPORT */
257 /* WSAEAFNOSUPPORT is EAFNOSUPPORT */
258 /* WSAEADDRINUSE is EADDRINUSE */
259 /* WSAEADDRNOTAVAIL is EADDRNOTAVAIL */
260 /* WSAENETDOWN is ENETDOWN */
261 /* WSAENETUNREACH is ENETUNREACH */
262 /* WSAENETRESET is ENETRESET */
263 /* WSAECONNABORTED is ECONNABORTED */
264 /* WSAECONNRESET is ECONNRESET */
265 /* WSAENOBUFS is ENOBUFS */
266 /* WSAEISCONN is EISCONN */
267 /* WSAENOTCONN is ENOTCONN */
268 /* WSAESHUTDOWN is ESHUTDOWN */
269 /* WSAETOOMANYREFS is ETOOMANYREFS */
270 /* WSAETIMEDOUT is ETIMEDOUT */
271 /* WSAECONNREFUSED is ECONNREFUSED */
272 /* WSAELOOP is ELOOP */
273 /* WSAENAMETOOLONG maps to ENAMETOOLONG */
274 /* WSAEHOSTDOWN is EHOSTDOWN */
275 /* WSAEHOSTUNREACH is EHOSTUNREACH */
276 /* WSAENOTEMPTY maps to ENOTEMPTY */
277 /* WSAEPROCLIM is EPROCLIM */
278 /* WSAEUSERS is EUSERS */
279 /* WSAEDQUOT is EDQUOT */
280 /* WSAESTALE is ESTALE */
281 /* WSAEREMOTE is EREMOTE */
283 msg = "Network subsystem is unavailable";
285 case WSAVERNOTSUPPORTED:
286 msg = "Winsock.dll version out of range";
288 case WSANOTINITIALISED:
289 msg = "Successful WSAStartup not yet performed";
292 msg = "Graceful shutdown in progress";
294 case WSAENOMORE: case WSA_E_NO_MORE:
295 msg = "No more results";
297 case WSAECANCELLED: case WSA_E_CANCELLED:
298 msg = "Call was canceled";
300 case WSAEINVALIDPROCTABLE:
301 msg = "Procedure call table is invalid";
303 case WSAEINVALIDPROVIDER:
304 msg = "Service provider is invalid";
306 case WSAEPROVIDERFAILEDINIT:
307 msg = "Service provider failed to initialize";
309 case WSASYSCALLFAILURE:
310 msg = "System call failure";
312 case WSASERVICE_NOT_FOUND:
313 msg = "Service not found";
315 case WSATYPE_NOT_FOUND:
316 msg = "Class type not found";
319 msg = "Database query was refused";
321 case WSAHOST_NOT_FOUND:
322 msg = "Host not found";
325 msg = "Nonauthoritative host not found";
328 msg = "Nonrecoverable error";
331 msg = "Valid name, no data record of requested type";
333 /* WSA_QOS_* omitted */
337 # if GNULIB_defined_ENOMSG
339 msg = "No message of desired type";
343 # if GNULIB_defined_EIDRM
345 msg = "Identifier removed";
349 # if GNULIB_defined_ENOLINK
351 msg = "Link has been severed";
355 # if GNULIB_defined_EPROTO
357 msg = "Protocol error";
361 # if GNULIB_defined_EMULTIHOP
363 msg = "Multihop attempted";
367 # if GNULIB_defined_EBADMSG
373 # if GNULIB_defined_EOVERFLOW
375 msg = "Value too large for defined data type";
379 # if GNULIB_defined_ENOTSUP
381 msg = "Not supported";
385 # if GNULIB_defined_ESTALE
387 msg = "Stale NFS file handle";
391 # if GNULIB_defined_EDQUOT
393 msg = "Disk quota exceeded";
397 # if GNULIB_defined_ECANCELED
399 msg = "Operation canceled";
406 int saved_errno = errno;
407 size_t len = strlen (msg);
412 memcpy (buf, msg, len + 1);
423 int saved_errno = errno;
425 #if USE_XPG_STRERROR_R
428 extern int __xpg_strerror_r (int errnum, char *buf, size_t buflen);
430 ret = __xpg_strerror_r (errnum, buf, buflen);
435 #elif USE_SYSTEM_STRERROR_R
437 if (buflen > INT_MAX)
441 /* On HP-UX 11.31, strerror_r always fails when buflen < 80. */
445 if (buflen < sizeof (stackbuf))
447 ret = strerror_r (errnum, stackbuf, sizeof (stackbuf));
450 size_t len = strlen (stackbuf);
453 memcpy (buf, stackbuf, len + 1);
459 ret = strerror_r (errnum, buf, buflen);
461 # elif defined __CYGWIN__
462 /* Cygwin <= 1.7.7 only provides the glibc interface, is thread-safe, and
463 always succeeds (although it may truncate). In Cygwin >= 1.7.8, for
464 valid errnum values, instead of truncating, it leaves the buffer
469 if (buflen < sizeof (stackbuf))
473 stackbuf[0] = '\0'; /* in case strerror_r does nothing */
474 strerror_r (errnum, stackbuf, sizeof (stackbuf));
475 len = strlen (stackbuf);
478 memcpy (buf, stackbuf, len + 1);
486 buf[0] = '\0'; /* in case strerror_r does nothing */
487 strerror_r (errnum, buf, buflen);
492 ret = strerror_r (errnum, buf, buflen);
496 /* On AIX 6.1, strerror_r returns -1 and sets errno to EINVAL
498 if (ret < 0 && errno == EINVAL && buflen <= 1)
500 /* Retry with a larger buffer. */
502 ret = strerror_r (errnum, largerbuf, sizeof (largerbuf));
503 if (ret < 0 && errno == EINVAL)
505 /* errnum was out of range. */
510 /* buf was too small. */
516 /* Some old implementations may return (-1, EINVAL) instead of EINVAL. */
520 /* FreeBSD rejects 0; see http://austingroupbugs.net/view.php?id=382. */
521 if (errnum == 0 && ret == EINVAL)
523 if (buflen <= strlen ("Success"))
532 strcpy (buf, "Success");
536 #else /* USE_SYSTEM_STRERROR */
538 /* Try to do what strerror (errnum) does, but without clobbering the
539 buffer used by strerror(). */
541 # if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) /* NetBSD, HP-UX, native Win32 */
543 /* NetBSD: sys_nerr, sys_errlist are declared through _NETBSD_SOURCE
545 HP-UX: sys_nerr, sys_errlist are declared explicitly above.
546 native Win32: sys_nerr, sys_errlist are declared in <stdlib.h>. */
547 if (errnum >= 0 && errnum < sys_nerr)
549 # if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
550 # if defined __NetBSD__
551 nl_catd catd = catopen ("libc", NL_CAT_LOCALE);
554 ? catgets (catd, 1, errnum, sys_errlist[errnum])
555 : sys_errlist[errnum]);
558 nl_catd catd = catopen ("perror", NL_CAT_LOCALE);
561 ? catgets (catd, 1, 1 + errnum, sys_errlist[errnum])
562 : sys_errlist[errnum]);
565 const char *errmsg = sys_errlist[errnum];
567 if (errmsg == NULL || *errmsg == '\0')
571 size_t len = strlen (errmsg);
575 memcpy (buf, errmsg, len + 1);
581 # if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
582 if (catd != (nl_catd)-1)
589 # elif defined __sgi || (defined __sun && !defined _LP64) /* IRIX, Solaris <= 9 32-bit */
591 /* For a valid error number, the system's strerror() function returns
592 a pointer to a not copied string, not to a buffer. */
593 if (errnum >= 0 && errnum < sys_nerr)
595 char *errmsg = strerror (errnum);
597 if (errmsg == NULL || *errmsg == '\0')
601 size_t len = strlen (errmsg);
605 memcpy (buf, errmsg, len + 1);
617 gl_lock_lock (strerror_lock);
620 char *errmsg = strerror (errnum);
622 /* For invalid error numbers, strerror() on
623 - IRIX 6.5 returns NULL,
624 - HP-UX 11 returns an empty string. */
625 if (errmsg == NULL || *errmsg == '\0')
629 size_t len = strlen (errmsg);
633 memcpy (buf, errmsg, len + 1);
641 gl_lock_unlock (strerror_lock);