strerror_r: Work around strerror_r() change in Cygwin 1.7.8.
[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
37 #if (__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__) && HAVE___XPG_STRERROR_R /* glibc >= 2.3.4, cygwin >= 1.7.9 */
38
39 # define USE_XPG_STRERROR_R 1
40
41 #elif HAVE_DECL_STRERROR_R && !(__GLIBC__ >= 2 || defined __UCLIBC__)
42
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.  */
45
46 # include <limits.h>
47
48 # define USE_SYSTEM_STRERROR_R 1
49
50 #else /* (__GLIBC__ >= 2 || defined __UCLIBC__ ? !HAVE___XPG_STRERROR_R : !HAVE_DECL_STRERROR_R) */
51
52 /* Use the system's strerror().  */
53 # undef strerror
54
55 # define USE_SYSTEM_STRERROR 1
56
57 # if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __sgi || (defined __sun && !defined _LP64)
58
59 /* No locking needed.  */
60
61 /* Get catgets internationalization functions.  */
62 #  if HAVE_CATGETS
63 #   include <nl_types.h>
64 #  endif
65
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
69 extern int sys_nerr;
70 extern char *sys_errlist[];
71 #  endif
72
73 /* Get sys_nerr on Solaris.  */
74 #  if defined __sun && !defined _LP64
75 extern int sys_nerr;
76 #  endif
77
78 /* Get sys_nerr, sys_errlist on native Windows.  */
79 #  include <stdlib.h>
80
81 # else
82
83 #  include "glthread/lock.h"
84
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)
88
89 # endif
90
91 #endif
92
93
94 int
95 strerror_r (int errnum, char *buf, size_t buflen)
96 #undef strerror_r
97 {
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
111   {
112     char const *msg = NULL;
113     /* These error messages are taken from glibc/sysdeps/gnu/errlist.c.  */
114     switch (errnum)
115       {
116 # if GNULIB_defined_ETXTBSY
117       case ETXTBSY:
118         msg = "Text file busy";
119         break;
120 # endif
121
122 # if GNULIB_defined_ESOCK /* native Windows platforms */
123       /* EWOULDBLOCK is the same as EAGAIN.  */
124       case EINPROGRESS:
125         msg = "Operation now in progress";
126         break;
127       case EALREADY:
128         msg = "Operation already in progress";
129         break;
130       case ENOTSOCK:
131         msg = "Socket operation on non-socket";
132         break;
133       case EDESTADDRREQ:
134         msg = "Destination address required";
135         break;
136       case EMSGSIZE:
137         msg = "Message too long";
138         break;
139       case EPROTOTYPE:
140         msg = "Protocol wrong type for socket";
141         break;
142       case ENOPROTOOPT:
143         msg = "Protocol not available";
144         break;
145       case EPROTONOSUPPORT:
146         msg = "Protocol not supported";
147         break;
148       case ESOCKTNOSUPPORT:
149         msg = "Socket type not supported";
150         break;
151       case EOPNOTSUPP:
152         msg = "Operation not supported";
153         break;
154       case EPFNOSUPPORT:
155         msg = "Protocol family not supported";
156         break;
157       case EAFNOSUPPORT:
158         msg = "Address family not supported by protocol";
159         break;
160       case EADDRINUSE:
161         msg = "Address already in use";
162         break;
163       case EADDRNOTAVAIL:
164         msg = "Cannot assign requested address";
165         break;
166       case ENETDOWN:
167         msg = "Network is down";
168         break;
169       case ENETUNREACH:
170         msg = "Network is unreachable";
171         break;
172       case ENETRESET:
173         msg = "Network dropped connection on reset";
174         break;
175       case ECONNABORTED:
176         msg = "Software caused connection abort";
177         break;
178       case ECONNRESET:
179         msg = "Connection reset by peer";
180         break;
181       case ENOBUFS:
182         msg = "No buffer space available";
183         break;
184       case EISCONN:
185         msg = "Transport endpoint is already connected";
186         break;
187       case ENOTCONN:
188         msg = "Transport endpoint is not connected";
189         break;
190       case ESHUTDOWN:
191         msg = "Cannot send after transport endpoint shutdown";
192         break;
193       case ETOOMANYREFS:
194         msg = "Too many references: cannot splice";
195         break;
196       case ETIMEDOUT:
197         msg = "Connection timed out";
198         break;
199       case ECONNREFUSED:
200         msg = "Connection refused";
201         break;
202       case ELOOP:
203         msg = "Too many levels of symbolic links";
204         break;
205       case EHOSTDOWN:
206         msg = "Host is down";
207         break;
208       case EHOSTUNREACH:
209         msg = "No route to host";
210         break;
211       case EPROCLIM:
212         msg = "Too many processes";
213         break;
214       case EUSERS:
215         msg = "Too many users";
216         break;
217       case EDQUOT:
218         msg = "Disk quota exceeded";
219         break;
220       case ESTALE:
221         msg = "Stale NFS file handle";
222         break;
223       case EREMOTE:
224         msg = "Object is remote";
225         break;
226 #  if HAVE_WINSOCK2_H
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";
232         break;
233       case WSA_IO_INCOMPLETE:
234         msg = "Overlapped I/O event object not in signaled state";
235         break;
236       case WSA_IO_PENDING:
237         msg = "Overlapped operations will complete later";
238         break;
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 */
282       case WSASYSNOTREADY:
283         msg = "Network subsystem is unavailable";
284         break;
285       case WSAVERNOTSUPPORTED:
286         msg = "Winsock.dll version out of range";
287         break;
288       case WSANOTINITIALISED:
289         msg = "Successful WSAStartup not yet performed";
290         break;
291       case WSAEDISCON:
292         msg = "Graceful shutdown in progress";
293         break;
294       case WSAENOMORE: case WSA_E_NO_MORE:
295         msg = "No more results";
296         break;
297       case WSAECANCELLED: case WSA_E_CANCELLED:
298         msg = "Call was canceled";
299         break;
300       case WSAEINVALIDPROCTABLE:
301         msg = "Procedure call table is invalid";
302         break;
303       case WSAEINVALIDPROVIDER:
304         msg = "Service provider is invalid";
305         break;
306       case WSAEPROVIDERFAILEDINIT:
307         msg = "Service provider failed to initialize";
308         break;
309       case WSASYSCALLFAILURE:
310         msg = "System call failure";
311         break;
312       case WSASERVICE_NOT_FOUND:
313         msg = "Service not found";
314         break;
315       case WSATYPE_NOT_FOUND:
316         msg = "Class type not found";
317         break;
318       case WSAEREFUSED:
319         msg = "Database query was refused";
320         break;
321       case WSAHOST_NOT_FOUND:
322         msg = "Host not found";
323         break;
324       case WSATRY_AGAIN:
325         msg = "Nonauthoritative host not found";
326         break;
327       case WSANO_RECOVERY:
328         msg = "Nonrecoverable error";
329         break;
330       case WSANO_DATA:
331         msg = "Valid name, no data record of requested type";
332         break;
333       /* WSA_QOS_* omitted */
334 #  endif
335 # endif
336
337 # if GNULIB_defined_ENOMSG
338       case ENOMSG:
339         msg = "No message of desired type";
340         break;
341 # endif
342
343 # if GNULIB_defined_EIDRM
344       case EIDRM:
345         msg = "Identifier removed";
346         break;
347 # endif
348
349 # if GNULIB_defined_ENOLINK
350       case ENOLINK:
351         msg = "Link has been severed";
352         break;
353 # endif
354
355 # if GNULIB_defined_EPROTO
356       case EPROTO:
357         msg = "Protocol error";
358         break;
359 # endif
360
361 # if GNULIB_defined_EMULTIHOP
362       case EMULTIHOP:
363         msg = "Multihop attempted";
364         break;
365 # endif
366
367 # if GNULIB_defined_EBADMSG
368       case EBADMSG:
369         msg = "Bad message";
370         break;
371 # endif
372
373 # if GNULIB_defined_EOVERFLOW
374       case EOVERFLOW:
375         msg = "Value too large for defined data type";
376         break;
377 # endif
378
379 # if GNULIB_defined_ENOTSUP
380       case ENOTSUP:
381         msg = "Not supported";
382         break;
383 # endif
384
385 # if GNULIB_defined_ESTALE
386       case ESTALE:
387         msg = "Stale NFS file handle";
388         break;
389 # endif
390
391 # if GNULIB_defined_EDQUOT
392       case EDQUOT:
393         msg = "Disk quota exceeded";
394         break;
395 # endif
396
397 # if GNULIB_defined_ECANCELED
398       case ECANCELED:
399         msg = "Operation canceled";
400         break;
401 # endif
402       }
403
404     if (msg)
405       {
406         int saved_errno = errno;
407         size_t len = strlen (msg);
408         int ret = ERANGE;
409
410         if (len < buflen)
411           {
412             memcpy (buf, msg, len + 1);
413             ret = 0;
414           }
415         errno = saved_errno;
416         return ret;
417       }
418   }
419 #endif
420
421   {
422     int ret;
423     int saved_errno = errno;
424
425 #if USE_XPG_STRERROR_R
426
427     {
428       extern int __xpg_strerror_r (int errnum, char *buf, size_t buflen);
429
430       ret = __xpg_strerror_r (errnum, buf, buflen);
431       if (ret < 0)
432         ret = errno;
433     }
434
435 #elif USE_SYSTEM_STRERROR_R
436
437     if (buflen > INT_MAX)
438       buflen = INT_MAX;
439
440 # ifdef __hpux
441     /* On HP-UX 11.31, strerror_r always fails when buflen < 80.  */
442     {
443       char stackbuf[80];
444
445       if (buflen < sizeof (stackbuf))
446         {
447           ret = strerror_r (errnum, stackbuf, sizeof (stackbuf));
448           if (ret == 0)
449             {
450               size_t len = strlen (stackbuf);
451
452               if (len < buflen)
453                 memcpy (buf, stackbuf, len + 1);
454               else
455                 ret = ERANGE;
456             }
457         }
458       else
459         ret = strerror_r (errnum, buf, buflen);
460     }
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
465        untouched.  */
466     {
467       char stackbuf[256];
468
469       if (buflen < sizeof (stackbuf))
470         {
471           size_t len;
472
473           stackbuf[0] = '\0'; /* in case strerror_r does nothing */
474           strerror_r (errnum, stackbuf, sizeof (stackbuf));
475           len = strlen (stackbuf);
476           if (len < buflen)
477             {
478               memcpy (buf, stackbuf, len + 1);
479               ret = 0;
480             }
481           else
482             ret = ERANGE;
483         }
484       else
485         {
486           buf[0] = '\0'; /* in case strerror_r does nothing */
487           strerror_r (errnum, buf, buflen);
488           ret = 0;
489         }
490     }
491 # else
492     ret = strerror_r (errnum, buf, buflen);
493 # endif
494
495 # ifdef _AIX
496     /* On AIX 6.1, strerror_r returns -1 and sets errno to EINVAL
497        if buflen <= 1.  */
498     if (ret < 0 && errno == EINVAL && buflen <= 1)
499       {
500         /* Retry with a larger buffer.  */
501         char largerbuf[10];
502         ret = strerror_r (errnum, largerbuf, sizeof (largerbuf));
503         if (ret < 0 && errno == EINVAL)
504           {
505             /* errnum was out of range.  */
506             ret = EINVAL;
507           }
508         else
509           {
510             /* buf was too small.  */
511             ret = ERANGE;
512           }
513       }
514 # endif
515
516     /* Some old implementations may return (-1, EINVAL) instead of EINVAL.  */
517     if (ret < 0)
518       ret = errno;
519
520     /* FreeBSD rejects 0; see http://austingroupbugs.net/view.php?id=382.  */
521     if (errnum == 0 && ret == EINVAL)
522       {
523         if (buflen <= strlen ("Success"))
524           {
525             ret = ERANGE;
526             if (buflen)
527               buf[0] = 0;
528           }
529         else
530           {
531             ret = 0;
532             strcpy (buf, "Success");
533           }
534       }
535
536 #else /* USE_SYSTEM_STRERROR */
537
538     /* Try to do what strerror (errnum) does, but without clobbering the
539        buffer used by strerror().  */
540
541 # if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) /* NetBSD, HP-UX, native Win32 */
542
543     /* NetBSD:        sys_nerr, sys_errlist are declared through _NETBSD_SOURCE
544                       and <errno.h> above.
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)
548       {
549 #  if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
550 #   if defined __NetBSD__
551         nl_catd catd = catopen ("libc", NL_CAT_LOCALE);
552         const char *errmsg =
553           (catd != (nl_catd)-1
554            ? catgets (catd, 1, errnum, sys_errlist[errnum])
555            : sys_errlist[errnum]);
556 #   endif
557 #   if defined __hpux
558         nl_catd catd = catopen ("perror", NL_CAT_LOCALE);
559         const char *errmsg =
560           (catd != (nl_catd)-1
561            ? catgets (catd, 1, 1 + errnum, sys_errlist[errnum])
562            : sys_errlist[errnum]);
563 #   endif
564 #  else
565         const char *errmsg = sys_errlist[errnum];
566 #  endif
567         if (errmsg == NULL || *errmsg == '\0')
568           ret = EINVAL;
569         else
570           {
571             size_t len = strlen (errmsg);
572
573             if (len < buflen)
574               {
575                 memcpy (buf, errmsg, len + 1);
576                 ret = 0;
577               }
578             else
579               ret = ERANGE;
580           }
581 #  if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
582         if (catd != (nl_catd)-1)
583           catclose (catd);
584 #  endif
585       }
586     else
587       ret = EINVAL;
588
589 # elif defined __sgi || (defined __sun && !defined _LP64) /* IRIX, Solaris <= 9 32-bit */
590
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)
594       {
595         char *errmsg = strerror (errnum);
596
597         if (errmsg == NULL || *errmsg == '\0')
598           ret = EINVAL;
599         else
600           {
601             size_t len = strlen (errmsg);
602
603             if (len < buflen)
604               {
605                 memcpy (buf, errmsg, len + 1);
606                 ret = 0;
607               }
608             else
609               ret = ERANGE;
610           }
611       }
612     else
613       ret = EINVAL;
614
615 # else
616
617     gl_lock_lock (strerror_lock);
618
619     {
620       char *errmsg = strerror (errnum);
621
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')
626         ret = EINVAL;
627       else
628         {
629           size_t len = strlen (errmsg);
630
631           if (len < buflen)
632             {
633               memcpy (buf, errmsg, len + 1);
634               ret = 0;
635             }
636           else
637             ret = ERANGE;
638         }
639     }
640
641     gl_lock_unlock (strerror_lock);
642
643 # endif
644
645 #endif
646
647     errno = saved_errno;
648     return ret;
649   }
650 }