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