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 /* Filter this out now, so that rest of this replacement knows that
99 there is room for a non-empty message and trailing NUL. */
107 #if GNULIB_defined_ETXTBSY \
108 || GNULIB_defined_ESOCK \
109 || GNULIB_defined_ENOMSG \
110 || GNULIB_defined_EIDRM \
111 || GNULIB_defined_ENOLINK \
112 || GNULIB_defined_EPROTO \
113 || GNULIB_defined_EMULTIHOP \
114 || GNULIB_defined_EBADMSG \
115 || GNULIB_defined_EOVERFLOW \
116 || GNULIB_defined_ENOTSUP \
117 || GNULIB_defined_ESTALE \
118 || GNULIB_defined_EDQUOT \
119 || GNULIB_defined_ECANCELED
121 char const *msg = NULL;
122 /* These error messages are taken from glibc/sysdeps/gnu/errlist.c. */
125 # if GNULIB_defined_ETXTBSY
127 msg = "Text file busy";
131 # if GNULIB_defined_ESOCK /* native Windows platforms */
132 /* EWOULDBLOCK is the same as EAGAIN. */
134 msg = "Operation now in progress";
137 msg = "Operation already in progress";
140 msg = "Socket operation on non-socket";
143 msg = "Destination address required";
146 msg = "Message too long";
149 msg = "Protocol wrong type for socket";
152 msg = "Protocol not available";
154 case EPROTONOSUPPORT:
155 msg = "Protocol not supported";
157 case ESOCKTNOSUPPORT:
158 msg = "Socket type not supported";
161 msg = "Operation not supported";
164 msg = "Protocol family not supported";
167 msg = "Address family not supported by protocol";
170 msg = "Address already in use";
173 msg = "Cannot assign requested address";
176 msg = "Network is down";
179 msg = "Network is unreachable";
182 msg = "Network dropped connection on reset";
185 msg = "Software caused connection abort";
188 msg = "Connection reset by peer";
191 msg = "No buffer space available";
194 msg = "Transport endpoint is already connected";
197 msg = "Transport endpoint is not connected";
200 msg = "Cannot send after transport endpoint shutdown";
203 msg = "Too many references: cannot splice";
206 msg = "Connection timed out";
209 msg = "Connection refused";
212 msg = "Too many levels of symbolic links";
215 msg = "Host is down";
218 msg = "No route to host";
221 msg = "Too many processes";
224 msg = "Too many users";
227 msg = "Disk quota exceeded";
230 msg = "Stale NFS file handle";
233 msg = "Object is remote";
236 /* WSA_INVALID_HANDLE maps to EBADF */
237 /* WSA_NOT_ENOUGH_MEMORY maps to ENOMEM */
238 /* WSA_INVALID_PARAMETER maps to EINVAL */
239 case WSA_OPERATION_ABORTED:
240 msg = "Overlapped operation aborted";
242 case WSA_IO_INCOMPLETE:
243 msg = "Overlapped I/O event object not in signaled state";
246 msg = "Overlapped operations will complete later";
248 /* WSAEINTR maps to EINTR */
249 /* WSAEBADF maps to EBADF */
250 /* WSAEACCES maps to EACCES */
251 /* WSAEFAULT maps to EFAULT */
252 /* WSAEINVAL maps to EINVAL */
253 /* WSAEMFILE maps to EMFILE */
254 /* WSAEWOULDBLOCK maps to EWOULDBLOCK */
255 /* WSAEINPROGRESS is EINPROGRESS */
256 /* WSAEALREADY is EALREADY */
257 /* WSAENOTSOCK is ENOTSOCK */
258 /* WSAEDESTADDRREQ is EDESTADDRREQ */
259 /* WSAEMSGSIZE is EMSGSIZE */
260 /* WSAEPROTOTYPE is EPROTOTYPE */
261 /* WSAENOPROTOOPT is ENOPROTOOPT */
262 /* WSAEPROTONOSUPPORT is EPROTONOSUPPORT */
263 /* WSAESOCKTNOSUPPORT is ESOCKTNOSUPPORT */
264 /* WSAEOPNOTSUPP is EOPNOTSUPP */
265 /* WSAEPFNOSUPPORT is EPFNOSUPPORT */
266 /* WSAEAFNOSUPPORT is EAFNOSUPPORT */
267 /* WSAEADDRINUSE is EADDRINUSE */
268 /* WSAEADDRNOTAVAIL is EADDRNOTAVAIL */
269 /* WSAENETDOWN is ENETDOWN */
270 /* WSAENETUNREACH is ENETUNREACH */
271 /* WSAENETRESET is ENETRESET */
272 /* WSAECONNABORTED is ECONNABORTED */
273 /* WSAECONNRESET is ECONNRESET */
274 /* WSAENOBUFS is ENOBUFS */
275 /* WSAEISCONN is EISCONN */
276 /* WSAENOTCONN is ENOTCONN */
277 /* WSAESHUTDOWN is ESHUTDOWN */
278 /* WSAETOOMANYREFS is ETOOMANYREFS */
279 /* WSAETIMEDOUT is ETIMEDOUT */
280 /* WSAECONNREFUSED is ECONNREFUSED */
281 /* WSAELOOP is ELOOP */
282 /* WSAENAMETOOLONG maps to ENAMETOOLONG */
283 /* WSAEHOSTDOWN is EHOSTDOWN */
284 /* WSAEHOSTUNREACH is EHOSTUNREACH */
285 /* WSAENOTEMPTY maps to ENOTEMPTY */
286 /* WSAEPROCLIM is EPROCLIM */
287 /* WSAEUSERS is EUSERS */
288 /* WSAEDQUOT is EDQUOT */
289 /* WSAESTALE is ESTALE */
290 /* WSAEREMOTE is EREMOTE */
292 msg = "Network subsystem is unavailable";
294 case WSAVERNOTSUPPORTED:
295 msg = "Winsock.dll version out of range";
297 case WSANOTINITIALISED:
298 msg = "Successful WSAStartup not yet performed";
301 msg = "Graceful shutdown in progress";
303 case WSAENOMORE: case WSA_E_NO_MORE:
304 msg = "No more results";
306 case WSAECANCELLED: case WSA_E_CANCELLED:
307 msg = "Call was canceled";
309 case WSAEINVALIDPROCTABLE:
310 msg = "Procedure call table is invalid";
312 case WSAEINVALIDPROVIDER:
313 msg = "Service provider is invalid";
315 case WSAEPROVIDERFAILEDINIT:
316 msg = "Service provider failed to initialize";
318 case WSASYSCALLFAILURE:
319 msg = "System call failure";
321 case WSASERVICE_NOT_FOUND:
322 msg = "Service not found";
324 case WSATYPE_NOT_FOUND:
325 msg = "Class type not found";
328 msg = "Database query was refused";
330 case WSAHOST_NOT_FOUND:
331 msg = "Host not found";
334 msg = "Nonauthoritative host not found";
337 msg = "Nonrecoverable error";
340 msg = "Valid name, no data record of requested type";
342 /* WSA_QOS_* omitted */
346 # if GNULIB_defined_ENOMSG
348 msg = "No message of desired type";
352 # if GNULIB_defined_EIDRM
354 msg = "Identifier removed";
358 # if GNULIB_defined_ENOLINK
360 msg = "Link has been severed";
364 # if GNULIB_defined_EPROTO
366 msg = "Protocol error";
370 # if GNULIB_defined_EMULTIHOP
372 msg = "Multihop attempted";
376 # if GNULIB_defined_EBADMSG
382 # if GNULIB_defined_EOVERFLOW
384 msg = "Value too large for defined data type";
388 # if GNULIB_defined_ENOTSUP
390 msg = "Not supported";
394 # if GNULIB_defined_ESTALE
396 msg = "Stale NFS file handle";
400 # if GNULIB_defined_EDQUOT
402 msg = "Disk quota exceeded";
406 # if GNULIB_defined_ECANCELED
408 msg = "Operation canceled";
415 int saved_errno = errno;
416 size_t len = strlen (msg);
421 memcpy (buf, msg, len + 1);
432 int saved_errno = errno;
434 #if USE_XPG_STRERROR_R
437 extern int __xpg_strerror_r (int errnum, char *buf, size_t buflen);
439 ret = __xpg_strerror_r (errnum, buf, buflen);
444 #elif USE_SYSTEM_STRERROR_R
446 if (buflen > INT_MAX)
450 /* On HP-UX 11.31, strerror_r always fails when buflen < 80. */
454 if (buflen < sizeof (stackbuf))
456 ret = strerror_r (errnum, stackbuf, sizeof (stackbuf));
459 size_t len = strlen (stackbuf);
462 memcpy (buf, stackbuf, len + 1);
468 ret = strerror_r (errnum, buf, buflen);
470 # elif defined __CYGWIN__
471 /* Cygwin <= 1.7.7 only provides the glibc interface, is thread-safe, and
472 always succeeds (although it may truncate). In Cygwin >= 1.7.8, for
473 valid errnum values, instead of truncating, it leaves the buffer
478 if (buflen < sizeof (stackbuf))
482 stackbuf[0] = '\0'; /* in case strerror_r does nothing */
483 strerror_r (errnum, stackbuf, sizeof (stackbuf));
484 len = strlen (stackbuf);
487 memcpy (buf, stackbuf, len + 1);
495 buf[0] = '\0'; /* in case strerror_r does nothing */
496 strerror_r (errnum, buf, buflen);
501 ret = strerror_r (errnum, buf, buflen);
504 /* Some old implementations may return (-1, EINVAL) instead of EINVAL. */
508 /* FreeBSD rejects 0; see http://austingroupbugs.net/view.php?id=382. */
509 if (errnum == 0 && ret == EINVAL)
511 if (buflen <= strlen ("Success"))
520 strcpy (buf, "Success");
524 #else /* USE_SYSTEM_STRERROR */
526 /* Try to do what strerror (errnum) does, but without clobbering the
527 buffer used by strerror(). */
529 # if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) /* NetBSD, HP-UX, native Win32 */
531 /* NetBSD: sys_nerr, sys_errlist are declared through _NETBSD_SOURCE
533 HP-UX: sys_nerr, sys_errlist are declared explicitly above.
534 native Win32: sys_nerr, sys_errlist are declared in <stdlib.h>. */
535 if (errnum >= 0 && errnum < sys_nerr)
537 # if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
538 # if defined __NetBSD__
539 nl_catd catd = catopen ("libc", NL_CAT_LOCALE);
542 ? catgets (catd, 1, errnum, sys_errlist[errnum])
543 : sys_errlist[errnum]);
546 nl_catd catd = catopen ("perror", NL_CAT_LOCALE);
549 ? catgets (catd, 1, 1 + errnum, sys_errlist[errnum])
550 : sys_errlist[errnum]);
553 const char *errmsg = sys_errlist[errnum];
555 if (errmsg == NULL || *errmsg == '\0')
559 size_t len = strlen (errmsg);
563 memcpy (buf, errmsg, len + 1);
569 # if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
570 if (catd != (nl_catd)-1)
577 # elif defined __sgi || (defined __sun && !defined _LP64) /* IRIX, Solaris <= 9 32-bit */
579 /* For a valid error number, the system's strerror() function returns
580 a pointer to a not copied string, not to a buffer. */
581 if (errnum >= 0 && errnum < sys_nerr)
583 char *errmsg = strerror (errnum);
585 if (errmsg == NULL || *errmsg == '\0')
589 size_t len = strlen (errmsg);
593 memcpy (buf, errmsg, len + 1);
605 gl_lock_lock (strerror_lock);
608 char *errmsg = strerror (errnum);
610 /* For invalid error numbers, strerror() on
611 - IRIX 6.5 returns NULL,
612 - HP-UX 11 returns an empty string. */
613 if (errmsg == NULL || *errmsg == '\0')
617 size_t len = strlen (errmsg);
621 memcpy (buf, errmsg, len + 1);
629 gl_lock_unlock (strerror_lock);