strerror_r: fix Solaris test failures
[gnulib.git] / lib / strerror_r.c
1 /* strerror_r.c --- POSIX compatible system error routine
2
3    Copyright (C) 2010-2011 Free Software Foundation, Inc.
4
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.
9
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.
14
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/>.  */
17
18 /* Written by Bruno Haible <bruno@clisp.org>, 2010.  */
19
20 #include <config.h>
21
22 /* Enable declaration of sys_nerr and sys_errlist in <errno.h> on NetBSD.  */
23 #define _NETBSD_SOURCE 1
24
25 /* Specification.  */
26 #include <string.h>
27
28 #include <errno.h>
29
30 #if GNULIB_defined_ESOCK /* native Windows platforms */
31 # if HAVE_WINSOCK2_H
32 #  include <winsock2.h>
33 # endif
34 #endif
35
36 /* Reasonable buffer size that should never trigger ERANGE; if this
37    proves too small, we intentionally abort(), to remind us to fix
38    this value as well as strerror-impl.h.  */
39 #define STACKBUF_LEN 256
40
41 #if (__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__) && HAVE___XPG_STRERROR_R /* glibc >= 2.3.4, cygwin >= 1.7.9 */
42
43 # define USE_XPG_STRERROR_R 1
44
45 #elif HAVE_DECL_STRERROR_R && !(__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__)
46
47 /* The system's strerror_r function is OK, except that its third argument
48    is 'int', not 'size_t', or its return type is wrong.  */
49
50 # include <limits.h>
51
52 # define USE_SYSTEM_STRERROR_R 1
53
54 #else /* (__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__ ? !HAVE___XPG_STRERROR_R : !HAVE_DECL_STRERROR_R) */
55
56 /* Use the system's strerror().  Exclude glibc and cygwin because the
57    system strerror_r has the wrong return type, and cygwin 1.7.9
58    strerror_r clobbers strerror.  */
59 # undef strerror
60
61 # define USE_SYSTEM_STRERROR 1
62
63 # if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __sgi || (defined __sun && !defined _LP64) || defined __CYGWIN__
64
65 /* No locking needed.  */
66
67 /* Get catgets internationalization functions.  */
68 #  if HAVE_CATGETS
69 #   include <nl_types.h>
70 #  endif
71
72 /* Get sys_nerr, sys_errlist on HP-UX (otherwise only declared in C++ mode).
73    Get sys_nerr, sys_errlist on IRIX (otherwise only declared with _SGIAPI).  */
74 #  if defined __hpux || defined __sgi
75 extern int sys_nerr;
76 extern char *sys_errlist[];
77 #  endif
78
79 /* Get sys_nerr on Solaris.  */
80 #  if defined __sun && !defined _LP64
81 extern int sys_nerr;
82 #  endif
83
84 /* Get sys_nerr, sys_errlist on native Windows.  */
85 #  include <stdlib.h>
86
87 # else
88
89 #  include "glthread/lock.h"
90
91 /* This lock protects the buffer returned by strerror().  We assume that
92    no other uses of strerror() exist in the program.  */
93 gl_lock_define_initialized(static, strerror_lock)
94
95 # endif
96
97 #endif
98
99 /* Copy as much of MSG into BUF as possible, without corrupting errno.
100    Return 0 if MSG fit in BUFLEN, otherwise return ERANGE.  */
101 static int
102 safe_copy (char *buf, size_t buflen, const char *msg)
103 {
104   size_t len = strlen (msg);
105   int ret;
106
107   if (len < buflen)
108     {
109       /* Although POSIX allows memcpy() to corrupt errno, we don't
110          know of any implementation where this is a real problem.  */
111       memcpy (buf, msg, len + 1);
112       ret = 0;
113     }
114   else
115     {
116       memcpy (buf, msg, buflen - 1);
117       buf[buflen - 1] = '\0';
118       ret = ERANGE;
119     }
120   return ret;
121 }
122
123
124 int
125 strerror_r (int errnum, char *buf, size_t buflen)
126 #undef strerror_r
127 {
128   /* Filter this out now, so that rest of this replacement knows that
129      there is room for a non-empty message and trailing NUL.  */
130   if (buflen <= 1)
131     {
132       if (buflen)
133         *buf = '\0';
134       return ERANGE;
135     }
136   *buf = '\0';
137
138 #if GNULIB_defined_ETXTBSY \
139     || GNULIB_defined_ESOCK \
140     || GNULIB_defined_ENOMSG \
141     || GNULIB_defined_EIDRM \
142     || GNULIB_defined_ENOLINK \
143     || GNULIB_defined_EPROTO \
144     || GNULIB_defined_EMULTIHOP \
145     || GNULIB_defined_EBADMSG \
146     || GNULIB_defined_EOVERFLOW \
147     || GNULIB_defined_ENOTSUP \
148     || GNULIB_defined_ESTALE \
149     || GNULIB_defined_EDQUOT \
150     || GNULIB_defined_ECANCELED
151   {
152     char const *msg = NULL;
153     /* These error messages are taken from glibc/sysdeps/gnu/errlist.c.  */
154     switch (errnum)
155       {
156 # if GNULIB_defined_ETXTBSY
157       case ETXTBSY:
158         msg = "Text file busy";
159         break;
160 # endif
161
162 # if GNULIB_defined_ESOCK /* native Windows platforms */
163       /* EWOULDBLOCK is the same as EAGAIN.  */
164       case EINPROGRESS:
165         msg = "Operation now in progress";
166         break;
167       case EALREADY:
168         msg = "Operation already in progress";
169         break;
170       case ENOTSOCK:
171         msg = "Socket operation on non-socket";
172         break;
173       case EDESTADDRREQ:
174         msg = "Destination address required";
175         break;
176       case EMSGSIZE:
177         msg = "Message too long";
178         break;
179       case EPROTOTYPE:
180         msg = "Protocol wrong type for socket";
181         break;
182       case ENOPROTOOPT:
183         msg = "Protocol not available";
184         break;
185       case EPROTONOSUPPORT:
186         msg = "Protocol not supported";
187         break;
188       case ESOCKTNOSUPPORT:
189         msg = "Socket type not supported";
190         break;
191       case EOPNOTSUPP:
192         msg = "Operation not supported";
193         break;
194       case EPFNOSUPPORT:
195         msg = "Protocol family not supported";
196         break;
197       case EAFNOSUPPORT:
198         msg = "Address family not supported by protocol";
199         break;
200       case EADDRINUSE:
201         msg = "Address already in use";
202         break;
203       case EADDRNOTAVAIL:
204         msg = "Cannot assign requested address";
205         break;
206       case ENETDOWN:
207         msg = "Network is down";
208         break;
209       case ENETUNREACH:
210         msg = "Network is unreachable";
211         break;
212       case ENETRESET:
213         msg = "Network dropped connection on reset";
214         break;
215       case ECONNABORTED:
216         msg = "Software caused connection abort";
217         break;
218       case ECONNRESET:
219         msg = "Connection reset by peer";
220         break;
221       case ENOBUFS:
222         msg = "No buffer space available";
223         break;
224       case EISCONN:
225         msg = "Transport endpoint is already connected";
226         break;
227       case ENOTCONN:
228         msg = "Transport endpoint is not connected";
229         break;
230       case ESHUTDOWN:
231         msg = "Cannot send after transport endpoint shutdown";
232         break;
233       case ETOOMANYREFS:
234         msg = "Too many references: cannot splice";
235         break;
236       case ETIMEDOUT:
237         msg = "Connection timed out";
238         break;
239       case ECONNREFUSED:
240         msg = "Connection refused";
241         break;
242       case ELOOP:
243         msg = "Too many levels of symbolic links";
244         break;
245       case EHOSTDOWN:
246         msg = "Host is down";
247         break;
248       case EHOSTUNREACH:
249         msg = "No route to host";
250         break;
251       case EPROCLIM:
252         msg = "Too many processes";
253         break;
254       case EUSERS:
255         msg = "Too many users";
256         break;
257       case EDQUOT:
258         msg = "Disk quota exceeded";
259         break;
260       case ESTALE:
261         msg = "Stale NFS file handle";
262         break;
263       case EREMOTE:
264         msg = "Object is remote";
265         break;
266 #  if HAVE_WINSOCK2_H
267       /* WSA_INVALID_HANDLE maps to EBADF */
268       /* WSA_NOT_ENOUGH_MEMORY maps to ENOMEM */
269       /* WSA_INVALID_PARAMETER maps to EINVAL */
270       case WSA_OPERATION_ABORTED:
271         msg = "Overlapped operation aborted";
272         break;
273       case WSA_IO_INCOMPLETE:
274         msg = "Overlapped I/O event object not in signaled state";
275         break;
276       case WSA_IO_PENDING:
277         msg = "Overlapped operations will complete later";
278         break;
279       /* WSAEINTR maps to EINTR */
280       /* WSAEBADF maps to EBADF */
281       /* WSAEACCES maps to EACCES */
282       /* WSAEFAULT maps to EFAULT */
283       /* WSAEINVAL maps to EINVAL */
284       /* WSAEMFILE maps to EMFILE */
285       /* WSAEWOULDBLOCK maps to EWOULDBLOCK */
286       /* WSAEINPROGRESS is EINPROGRESS */
287       /* WSAEALREADY is EALREADY */
288       /* WSAENOTSOCK is ENOTSOCK */
289       /* WSAEDESTADDRREQ is EDESTADDRREQ */
290       /* WSAEMSGSIZE is EMSGSIZE */
291       /* WSAEPROTOTYPE is EPROTOTYPE */
292       /* WSAENOPROTOOPT is ENOPROTOOPT */
293       /* WSAEPROTONOSUPPORT is EPROTONOSUPPORT */
294       /* WSAESOCKTNOSUPPORT is ESOCKTNOSUPPORT */
295       /* WSAEOPNOTSUPP is EOPNOTSUPP */
296       /* WSAEPFNOSUPPORT is EPFNOSUPPORT */
297       /* WSAEAFNOSUPPORT is EAFNOSUPPORT */
298       /* WSAEADDRINUSE is EADDRINUSE */
299       /* WSAEADDRNOTAVAIL is EADDRNOTAVAIL */
300       /* WSAENETDOWN is ENETDOWN */
301       /* WSAENETUNREACH is ENETUNREACH */
302       /* WSAENETRESET is ENETRESET */
303       /* WSAECONNABORTED is ECONNABORTED */
304       /* WSAECONNRESET is ECONNRESET */
305       /* WSAENOBUFS is ENOBUFS */
306       /* WSAEISCONN is EISCONN */
307       /* WSAENOTCONN is ENOTCONN */
308       /* WSAESHUTDOWN is ESHUTDOWN */
309       /* WSAETOOMANYREFS is ETOOMANYREFS */
310       /* WSAETIMEDOUT is ETIMEDOUT */
311       /* WSAECONNREFUSED is ECONNREFUSED */
312       /* WSAELOOP is ELOOP */
313       /* WSAENAMETOOLONG maps to ENAMETOOLONG */
314       /* WSAEHOSTDOWN is EHOSTDOWN */
315       /* WSAEHOSTUNREACH is EHOSTUNREACH */
316       /* WSAENOTEMPTY maps to ENOTEMPTY */
317       /* WSAEPROCLIM is EPROCLIM */
318       /* WSAEUSERS is EUSERS */
319       /* WSAEDQUOT is EDQUOT */
320       /* WSAESTALE is ESTALE */
321       /* WSAEREMOTE is EREMOTE */
322       case WSASYSNOTREADY:
323         msg = "Network subsystem is unavailable";
324         break;
325       case WSAVERNOTSUPPORTED:
326         msg = "Winsock.dll version out of range";
327         break;
328       case WSANOTINITIALISED:
329         msg = "Successful WSAStartup not yet performed";
330         break;
331       case WSAEDISCON:
332         msg = "Graceful shutdown in progress";
333         break;
334       case WSAENOMORE: case WSA_E_NO_MORE:
335         msg = "No more results";
336         break;
337       case WSAECANCELLED: case WSA_E_CANCELLED:
338         msg = "Call was canceled";
339         break;
340       case WSAEINVALIDPROCTABLE:
341         msg = "Procedure call table is invalid";
342         break;
343       case WSAEINVALIDPROVIDER:
344         msg = "Service provider is invalid";
345         break;
346       case WSAEPROVIDERFAILEDINIT:
347         msg = "Service provider failed to initialize";
348         break;
349       case WSASYSCALLFAILURE:
350         msg = "System call failure";
351         break;
352       case WSASERVICE_NOT_FOUND:
353         msg = "Service not found";
354         break;
355       case WSATYPE_NOT_FOUND:
356         msg = "Class type not found";
357         break;
358       case WSAEREFUSED:
359         msg = "Database query was refused";
360         break;
361       case WSAHOST_NOT_FOUND:
362         msg = "Host not found";
363         break;
364       case WSATRY_AGAIN:
365         msg = "Nonauthoritative host not found";
366         break;
367       case WSANO_RECOVERY:
368         msg = "Nonrecoverable error";
369         break;
370       case WSANO_DATA:
371         msg = "Valid name, no data record of requested type";
372         break;
373       /* WSA_QOS_* omitted */
374 #  endif
375 # endif
376
377 # if GNULIB_defined_ENOMSG
378       case ENOMSG:
379         msg = "No message of desired type";
380         break;
381 # endif
382
383 # if GNULIB_defined_EIDRM
384       case EIDRM:
385         msg = "Identifier removed";
386         break;
387 # endif
388
389 # if GNULIB_defined_ENOLINK
390       case ENOLINK:
391         msg = "Link has been severed";
392         break;
393 # endif
394
395 # if GNULIB_defined_EPROTO
396       case EPROTO:
397         msg = "Protocol error";
398         break;
399 # endif
400
401 # if GNULIB_defined_EMULTIHOP
402       case EMULTIHOP:
403         msg = "Multihop attempted";
404         break;
405 # endif
406
407 # if GNULIB_defined_EBADMSG
408       case EBADMSG:
409         msg = "Bad message";
410         break;
411 # endif
412
413 # if GNULIB_defined_EOVERFLOW
414       case EOVERFLOW:
415         msg = "Value too large for defined data type";
416         break;
417 # endif
418
419 # if GNULIB_defined_ENOTSUP
420       case ENOTSUP:
421         msg = "Not supported";
422         break;
423 # endif
424
425 # if GNULIB_defined_ESTALE
426       case ESTALE:
427         msg = "Stale NFS file handle";
428         break;
429 # endif
430
431 # if GNULIB_defined_EDQUOT
432       case EDQUOT:
433         msg = "Disk quota exceeded";
434         break;
435 # endif
436
437 # if GNULIB_defined_ECANCELED
438       case ECANCELED:
439         msg = "Operation canceled";
440         break;
441 # endif
442       }
443
444     if (msg)
445       return safe_copy (buf, buflen, msg);
446   }
447 #endif
448
449   {
450     int ret;
451     int saved_errno = errno;
452
453 #if USE_XPG_STRERROR_R
454
455     {
456       extern int __xpg_strerror_r (int errnum, char *buf, size_t buflen);
457
458       ret = __xpg_strerror_r (errnum, buf, buflen);
459       if (ret < 0)
460         ret = errno;
461       if (!*buf)
462         {
463           /* glibc 2.13 would not touch buf on err, so we have to fall
464              back to GNU strerror_r which always returns a thread-safe
465              untruncated string to (partially) copy into our buf.  */
466           safe_copy (buf, buflen, strerror_r (errnum, buf, buflen));
467         }
468     }
469
470 #elif USE_SYSTEM_STRERROR_R
471
472     if (buflen > INT_MAX)
473       buflen = INT_MAX;
474
475 # ifdef __hpux
476     /* On HP-UX 11.31, strerror_r always fails when buflen < 80.  */
477     {
478       char stackbuf[80];
479
480       if (buflen < sizeof stackbuf)
481         {
482           ret = strerror_r (errnum, stackbuf, sizeof stackbuf);
483           if (ret == 0)
484             ret = safe_copy (buf, buflen, stackbuf);
485         }
486       else
487         ret = strerror_r (errnum, buf, buflen);
488     }
489 # else
490     /* Solaris 10 does not populate buf on ERANGE.  */
491     ret = strerror_r (errnum, buf, buflen);
492     if (ret == ERANGE && !*buf)
493       {
494         char stackbuf[STACKBUF_LEN];
495
496         /* strerror-impl.h is also affected if our choice of stackbuf
497            size is not large enough.  */
498         if (strerror_r (errnum, stackbuf, sizeof stackbuf) == ERANGE)
499           abort ();
500         safe_copy (buf, buflen, stackbuf);
501       }
502 # endif
503
504     /* Some old implementations may return (-1, EINVAL) instead of EINVAL.  */
505     if (ret < 0)
506       ret = errno;
507
508     /* FreeBSD rejects 0; see http://austingroupbugs.net/view.php?id=382.  */
509     if (errnum == 0 && ret == EINVAL)
510       ret = safe_copy (buf, buflen, "Success");
511
512 #else /* USE_SYSTEM_STRERROR */
513
514     /* Try to do what strerror (errnum) does, but without clobbering the
515        buffer used by strerror().  */
516
517 # if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __CYGWIN__ /* NetBSD, HP-UX, native Win32, Cygwin */
518
519     /* NetBSD:        sys_nerr, sys_errlist are declared through _NETBSD_SOURCE
520                       and <errno.h> above.
521        HP-UX:         sys_nerr, sys_errlist are declared explicitly above.
522        native Win32:  sys_nerr, sys_errlist are declared in <stdlib.h>.
523        Cygwin:        sys_nerr, sys_errlist are declared in <errno.h>.  */
524     if (errnum >= 0 && errnum < sys_nerr)
525       {
526 #  if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
527 #   if defined __NetBSD__
528         nl_catd catd = catopen ("libc", NL_CAT_LOCALE);
529         const char *errmsg =
530           (catd != (nl_catd)-1
531            ? catgets (catd, 1, errnum, sys_errlist[errnum])
532            : sys_errlist[errnum]);
533 #   endif
534 #   if defined __hpux
535         nl_catd catd = catopen ("perror", NL_CAT_LOCALE);
536         const char *errmsg =
537           (catd != (nl_catd)-1
538            ? catgets (catd, 1, 1 + errnum, sys_errlist[errnum])
539            : sys_errlist[errnum]);
540 #   endif
541 #  else
542         const char *errmsg = sys_errlist[errnum];
543 #  endif
544         if (errmsg == NULL || *errmsg == '\0')
545           ret = EINVAL;
546         else
547           ret = safe_copy (buf, buflen, errmsg);
548 #  if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
549         if (catd != (nl_catd)-1)
550           catclose (catd);
551 #  endif
552       }
553     else
554       ret = EINVAL;
555
556 # elif defined __sgi || (defined __sun && !defined _LP64) /* IRIX, Solaris <= 9 32-bit */
557
558     /* For a valid error number, the system's strerror() function returns
559        a pointer to a not copied string, not to a buffer.  */
560     if (errnum >= 0 && errnum < sys_nerr)
561       {
562         char *errmsg = strerror (errnum);
563
564         if (errmsg == NULL || *errmsg == '\0')
565           ret = EINVAL;
566         else
567           ret = safe_copy (buf, buflen, errmsg);
568       }
569     else
570       ret = EINVAL;
571
572 # else
573
574     gl_lock_lock (strerror_lock);
575
576     {
577       char *errmsg = strerror (errnum);
578
579       /* For invalid error numbers, strerror() on
580            - IRIX 6.5 returns NULL,
581            - HP-UX 11 returns an empty string.  */
582       if (errmsg == NULL || *errmsg == '\0')
583         ret = EINVAL;
584       else
585         ret = safe_copy (buf, buflen, errmsg);
586     }
587
588     gl_lock_unlock (strerror_lock);
589
590 # endif
591
592 #endif
593
594     if (ret == EINVAL && !*buf)
595       snprintf (buf, buflen, "Unknown error %d", errnum);
596
597     errno = saved_errno;
598     return ret;
599   }
600 }