strerror_r: Reorder #if blocks.
[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         size_t len = strlen (msg);
407
408         if (len < buflen)
409           {
410             memcpy (buf, msg, len + 1);
411             return 0;
412           }
413         else
414           return ERANGE;
415       }
416   }
417 #endif
418
419   {
420     int ret;
421
422 #if USE_XPG_STRERROR_R
423
424     {
425       extern int __xpg_strerror_r (int errnum, char *buf, size_t buflen);
426
427       ret = __xpg_strerror_r (errnum, buf, buflen);
428       if (ret < 0)
429         ret = errno;
430     }
431
432 #elif USE_SYSTEM_STRERROR_R
433
434     if (buflen > INT_MAX)
435       buflen = INT_MAX;
436
437 # ifdef __hpux
438     /* On HP-UX 11.31, strerror_r always fails when buflen < 80.  */
439     {
440       char stackbuf[80];
441
442       if (buflen < sizeof (stackbuf))
443         {
444           ret = strerror_r (errnum, stackbuf, sizeof (stackbuf));
445           if (ret == 0)
446             {
447               size_t len = strlen (stackbuf);
448
449               if (len < buflen)
450                 memcpy (buf, stackbuf, len + 1);
451               else
452                 ret = ERANGE;
453             }
454         }
455       else
456         ret = strerror_r (errnum, buf, buflen);
457     }
458 # elif defined __CYGWIN__
459     /* Cygwin 1.7.8 only provides the glibc interface, is thread-safe, and
460        always succeeds (although it may truncate). */
461     strerror_r (errnum, buf, buflen);
462     ret = 0;
463 # else
464     ret = strerror_r (errnum, buf, buflen);
465 # endif
466
467 # ifdef _AIX
468     /* On AIX 6.1, strerror_r returns -1 and sets errno to EINVAL
469        if buflen <= 1.  */
470     if (ret < 0 && errno == EINVAL && buflen <= 1)
471       {
472         /* Retry with a larger buffer.  */
473         char largerbuf[10];
474         ret = strerror_r (errnum, largerbuf, sizeof (largerbuf));
475         if (ret < 0 && errno == EINVAL)
476           {
477             /* errnum was out of range.  */
478             ret = EINVAL;
479           }
480         else
481           {
482             /* buf was too small.  */
483             ret = ERANGE;
484           }
485       }
486 # endif
487
488     /* Some old implementations may return (-1, EINVAL) instead of EINVAL.  */
489     if (ret < 0)
490       ret = errno;
491
492     /* FreeBSD rejects 0; see http://austingroupbugs.net/view.php?id=382.  */
493     if (errnum == 0 && ret == EINVAL)
494       {
495         if (buflen <= strlen ("Success"))
496           {
497             ret = ERANGE;
498             if (buflen)
499               buf[0] = 0;
500           }
501         else
502           {
503             ret = 0;
504             strcpy (buf, "Success");
505           }
506       }
507
508 #else /* USE_SYSTEM_STRERROR */
509
510     /* Try to do what strerror (errnum) does, but without clobbering the
511        buffer used by strerror().  */
512
513 # if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) /* NetBSD, HP-UX, native Win32 */
514
515     /* NetBSD:        sys_nerr, sys_errlist are declared through _NETBSD_SOURCE
516                       and <errno.h> above.
517        HP-UX:         sys_nerr, sys_errlist are declared explicitly above.
518        native Win32:  sys_nerr, sys_errlist are declared in <stdlib.h>.  */
519     if (errnum >= 0 && errnum < sys_nerr)
520       {
521 #  if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
522         int saved_errno = errno;
523 #   if defined __NetBSD__
524         nl_catd catd = catopen ("libc", NL_CAT_LOCALE);
525         const char *errmsg =
526           (catd != (nl_catd)-1
527            ? catgets (catd, 1, errnum, sys_errlist[errnum])
528            : sys_errlist[errnum]);
529 #   endif
530 #   if defined __hpux
531         nl_catd catd = catopen ("perror", NL_CAT_LOCALE);
532         const char *errmsg =
533           (catd != (nl_catd)-1
534            ? catgets (catd, 1, 1 + errnum, sys_errlist[errnum])
535            : sys_errlist[errnum]);
536 #   endif
537 #  else
538         const char *errmsg = sys_errlist[errnum];
539 #  endif
540         if (errmsg == NULL || *errmsg == '\0')
541           ret = EINVAL;
542         else
543           {
544             size_t len = strlen (errmsg);
545
546             if (len < buflen)
547               {
548                 memcpy (buf, errmsg, len + 1);
549                 ret = 0;
550               }
551             else
552               ret = ERANGE;
553           }
554 #  if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
555         if (catd != (nl_catd)-1)
556           catclose (catd);
557         errno = saved_errno;
558 #  endif
559       }
560     else
561       ret = EINVAL;
562
563 # elif defined __sgi || (defined __sun && !defined _LP64) /* IRIX, Solaris <= 9 32-bit */
564
565     /* For a valid error number, the system's strerror() function returns
566        a pointer to a not copied string, not to a buffer.  */
567     if (errnum >= 0 && errnum < sys_nerr)
568       {
569         char *errmsg = strerror (errnum);
570
571         if (errmsg == NULL || *errmsg == '\0')
572           ret = EINVAL;
573         else
574           {
575             size_t len = strlen (errmsg);
576
577             if (len < buflen)
578               {
579                 memcpy (buf, errmsg, len + 1);
580                 ret = 0;
581               }
582             else
583               ret = ERANGE;
584           }
585       }
586     else
587       ret = EINVAL;
588
589 # else
590
591     gl_lock_lock (strerror_lock);
592
593     {
594       char *errmsg = strerror (errnum);
595
596       /* For invalid error numbers, strerror() on
597            - IRIX 6.5 returns NULL,
598            - HP-UX 11 returns an empty string.  */
599       if (errmsg == NULL || *errmsg == '\0')
600         ret = EINVAL;
601       else
602         {
603           size_t len = strlen (errmsg);
604
605           if (len < buflen)
606             {
607               memcpy (buf, errmsg, len + 1);
608               ret = 0;
609             }
610           else
611             ret = ERANGE;
612         }
613     }
614
615     gl_lock_unlock (strerror_lock);
616
617 # endif
618
619 #endif
620
621     return ret;
622   }
623 }