strerror_r: Fix test failure on mingw.
[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 /* Specification.  */
23 #include <string.h>
24
25 #include <errno.h>
26
27 # if GNULIB_defined_ESOCK /* native Windows platforms */
28 #  if HAVE_WINSOCK2_H
29 #   include <winsock2.h>
30 #  endif
31 # endif
32
33
34 #if HAVE_DECL_STRERROR_R && !(__GLIBC__ >= 2 || defined __UCLIBC__)
35
36 /* The system's strerror_r function is OK, except that its third argument
37    is 'int', not 'size_t', or its return type is wrong.  */
38
39 # include <limits.h>
40
41 # define USE_SYSTEM_STRERROR_R 1
42
43 #elif (__GLIBC__ >= 2 || defined __UCLIBC__) && HAVE___XPG_STRERROR_R /* glibc >= 2.3.4 */
44
45 # define USE_XPG_STRERROR_R 1
46
47 #else /* (__GLIBC__ >= 2 || defined __UCLIBC__ ? !HAVE___XPG_STRERROR_R : !HAVE_DECL_STRERROR_R) */
48
49 # include "glthread/lock.h"
50
51 /* Use strerror(), with locking.  */
52 # undef strerror
53
54 # define USE_SYSTEM_STRERROR 1
55
56 /* This lock protects the buffer returned by strerror().  We assume that
57    no other uses of strerror() exist in the program.  */
58 gl_lock_define_initialized(static, strerror_lock)
59
60 #endif
61
62
63 int
64 strerror_r (int errnum, char *buf, size_t buflen)
65 #undef strerror_r
66 {
67 #if GNULIB_defined_ETXTBSY \
68     || GNULIB_defined_ESOCK \
69     || GNULIB_defined_ENOMSG \
70     || GNULIB_defined_EIDRM \
71     || GNULIB_defined_ENOLINK \
72     || GNULIB_defined_EPROTO \
73     || GNULIB_defined_EMULTIHOP \
74     || GNULIB_defined_EBADMSG \
75     || GNULIB_defined_EOVERFLOW \
76     || GNULIB_defined_ENOTSUP \
77     || GNULIB_defined_ESTALE \
78     || GNULIB_defined_EDQUOT \
79     || GNULIB_defined_ECANCELED
80   {
81     char const *msg = NULL;
82     /* These error messages are taken from glibc/sysdeps/gnu/errlist.c.  */
83     switch (errnum)
84       {
85 # if GNULIB_defined_ETXTBSY
86       case ETXTBSY:
87         msg = "Text file busy";
88         break;
89 # endif
90
91 # if GNULIB_defined_ESOCK /* native Windows platforms */
92       /* EWOULDBLOCK is the same as EAGAIN.  */
93       case EINPROGRESS:
94         msg = "Operation now in progress";
95         break;
96       case EALREADY:
97         msg = "Operation already in progress";
98         break;
99       case ENOTSOCK:
100         msg = "Socket operation on non-socket";
101         break;
102       case EDESTADDRREQ:
103         msg = "Destination address required";
104         break;
105       case EMSGSIZE:
106         msg = "Message too long";
107         break;
108       case EPROTOTYPE:
109         msg = "Protocol wrong type for socket";
110         break;
111       case ENOPROTOOPT:
112         msg = "Protocol not available";
113         break;
114       case EPROTONOSUPPORT:
115         msg = "Protocol not supported";
116         break;
117       case ESOCKTNOSUPPORT:
118         msg = "Socket type not supported";
119         break;
120       case EOPNOTSUPP:
121         msg = "Operation not supported";
122         break;
123       case EPFNOSUPPORT:
124         msg = "Protocol family not supported";
125         break;
126       case EAFNOSUPPORT:
127         msg = "Address family not supported by protocol";
128         break;
129       case EADDRINUSE:
130         msg = "Address already in use";
131         break;
132       case EADDRNOTAVAIL:
133         msg = "Cannot assign requested address";
134         break;
135       case ENETDOWN:
136         msg = "Network is down";
137         break;
138       case ENETUNREACH:
139         msg = "Network is unreachable";
140         break;
141       case ENETRESET:
142         msg = "Network dropped connection on reset";
143         break;
144       case ECONNABORTED:
145         msg = "Software caused connection abort";
146         break;
147       case ECONNRESET:
148         msg = "Connection reset by peer";
149         break;
150       case ENOBUFS:
151         msg = "No buffer space available";
152         break;
153       case EISCONN:
154         msg = "Transport endpoint is already connected";
155         break;
156       case ENOTCONN:
157         msg = "Transport endpoint is not connected";
158         break;
159       case ESHUTDOWN:
160         msg = "Cannot send after transport endpoint shutdown";
161         break;
162       case ETOOMANYREFS:
163         msg = "Too many references: cannot splice";
164         break;
165       case ETIMEDOUT:
166         msg = "Connection timed out";
167         break;
168       case ECONNREFUSED:
169         msg = "Connection refused";
170         break;
171       case ELOOP:
172         msg = "Too many levels of symbolic links";
173         break;
174       case EHOSTDOWN:
175         msg = "Host is down";
176         break;
177       case EHOSTUNREACH:
178         msg = "No route to host";
179         break;
180       case EPROCLIM:
181         msg = "Too many processes";
182         break;
183       case EUSERS:
184         msg = "Too many users";
185         break;
186       case EDQUOT:
187         msg = "Disk quota exceeded";
188         break;
189       case ESTALE:
190         msg = "Stale NFS file handle";
191         break;
192       case EREMOTE:
193         msg = "Object is remote";
194         break;
195 #  if HAVE_WINSOCK2_H
196       /* WSA_INVALID_HANDLE maps to EBADF */
197       /* WSA_NOT_ENOUGH_MEMORY maps to ENOMEM */
198       /* WSA_INVALID_PARAMETER maps to EINVAL */
199       case WSA_OPERATION_ABORTED:
200         msg = "Overlapped operation aborted";
201         break;
202       case WSA_IO_INCOMPLETE:
203         msg = "Overlapped I/O event object not in signaled state";
204         break;
205       case WSA_IO_PENDING:
206         msg = "Overlapped operations will complete later";
207         break;
208       /* WSAEINTR maps to EINTR */
209       /* WSAEBADF maps to EBADF */
210       /* WSAEACCES maps to EACCES */
211       /* WSAEFAULT maps to EFAULT */
212       /* WSAEINVAL maps to EINVAL */
213       /* WSAEMFILE maps to EMFILE */
214       /* WSAEWOULDBLOCK maps to EWOULDBLOCK */
215       /* WSAEINPROGRESS is EINPROGRESS */
216       /* WSAEALREADY is EALREADY */
217       /* WSAENOTSOCK is ENOTSOCK */
218       /* WSAEDESTADDRREQ is EDESTADDRREQ */
219       /* WSAEMSGSIZE is EMSGSIZE */
220       /* WSAEPROTOTYPE is EPROTOTYPE */
221       /* WSAENOPROTOOPT is ENOPROTOOPT */
222       /* WSAEPROTONOSUPPORT is EPROTONOSUPPORT */
223       /* WSAESOCKTNOSUPPORT is ESOCKTNOSUPPORT */
224       /* WSAEOPNOTSUPP is EOPNOTSUPP */
225       /* WSAEPFNOSUPPORT is EPFNOSUPPORT */
226       /* WSAEAFNOSUPPORT is EAFNOSUPPORT */
227       /* WSAEADDRINUSE is EADDRINUSE */
228       /* WSAEADDRNOTAVAIL is EADDRNOTAVAIL */
229       /* WSAENETDOWN is ENETDOWN */
230       /* WSAENETUNREACH is ENETUNREACH */
231       /* WSAENETRESET is ENETRESET */
232       /* WSAECONNABORTED is ECONNABORTED */
233       /* WSAECONNRESET is ECONNRESET */
234       /* WSAENOBUFS is ENOBUFS */
235       /* WSAEISCONN is EISCONN */
236       /* WSAENOTCONN is ENOTCONN */
237       /* WSAESHUTDOWN is ESHUTDOWN */
238       /* WSAETOOMANYREFS is ETOOMANYREFS */
239       /* WSAETIMEDOUT is ETIMEDOUT */
240       /* WSAECONNREFUSED is ECONNREFUSED */
241       /* WSAELOOP is ELOOP */
242       /* WSAENAMETOOLONG maps to ENAMETOOLONG */
243       /* WSAEHOSTDOWN is EHOSTDOWN */
244       /* WSAEHOSTUNREACH is EHOSTUNREACH */
245       /* WSAENOTEMPTY maps to ENOTEMPTY */
246       /* WSAEPROCLIM is EPROCLIM */
247       /* WSAEUSERS is EUSERS */
248       /* WSAEDQUOT is EDQUOT */
249       /* WSAESTALE is ESTALE */
250       /* WSAEREMOTE is EREMOTE */
251       case WSASYSNOTREADY:
252         msg = "Network subsystem is unavailable";
253         break;
254       case WSAVERNOTSUPPORTED:
255         msg = "Winsock.dll version out of range";
256         break;
257       case WSANOTINITIALISED:
258         msg = "Successful WSAStartup not yet performed";
259         break;
260       case WSAEDISCON:
261         msg = "Graceful shutdown in progress";
262         break;
263       case WSAENOMORE: case WSA_E_NO_MORE:
264         msg = "No more results";
265         break;
266       case WSAECANCELLED: case WSA_E_CANCELLED:
267         msg = "Call was canceled";
268         break;
269       case WSAEINVALIDPROCTABLE:
270         msg = "Procedure call table is invalid";
271         break;
272       case WSAEINVALIDPROVIDER:
273         msg = "Service provider is invalid";
274         break;
275       case WSAEPROVIDERFAILEDINIT:
276         msg = "Service provider failed to initialize";
277         break;
278       case WSASYSCALLFAILURE:
279         msg = "System call failure";
280         break;
281       case WSASERVICE_NOT_FOUND:
282         msg = "Service not found";
283         break;
284       case WSATYPE_NOT_FOUND:
285         msg = "Class type not found";
286         break;
287       case WSAEREFUSED:
288         msg = "Database query was refused";
289         break;
290       case WSAHOST_NOT_FOUND:
291         msg = "Host not found";
292         break;
293       case WSATRY_AGAIN:
294         msg = "Nonauthoritative host not found";
295         break;
296       case WSANO_RECOVERY:
297         msg = "Nonrecoverable error";
298         break;
299       case WSANO_DATA:
300         msg = "Valid name, no data record of requested type";
301         break;
302       /* WSA_QOS_* omitted */
303 #  endif
304 # endif
305
306 # if GNULIB_defined_ENOMSG
307       case ENOMSG:
308         msg = "No message of desired type";
309         break;
310 # endif
311
312 # if GNULIB_defined_EIDRM
313       case EIDRM:
314         msg = "Identifier removed";
315         break;
316 # endif
317
318 # if GNULIB_defined_ENOLINK
319       case ENOLINK:
320         msg = "Link has been severed";
321         break;
322 # endif
323
324 # if GNULIB_defined_EPROTO
325       case EPROTO:
326         msg = "Protocol error";
327         break;
328 # endif
329
330 # if GNULIB_defined_EMULTIHOP
331       case EMULTIHOP:
332         msg = "Multihop attempted";
333         break;
334 # endif
335
336 # if GNULIB_defined_EBADMSG
337       case EBADMSG:
338         msg = "Bad message";
339         break;
340 # endif
341
342 # if GNULIB_defined_EOVERFLOW
343       case EOVERFLOW:
344         msg = "Value too large for defined data type";
345         break;
346 # endif
347
348 # if GNULIB_defined_ENOTSUP
349       case ENOTSUP:
350         msg = "Not supported";
351         break;
352 # endif
353
354 # if GNULIB_defined_ESTALE
355       case ESTALE:
356         msg = "Stale NFS file handle";
357         break;
358 # endif
359
360 # if GNULIB_defined_EDQUOT
361       case EDQUOT:
362         msg = "Disk quota exceeded";
363         break;
364 # endif
365
366 # if GNULIB_defined_ECANCELED
367       case ECANCELED:
368         msg = "Operation canceled";
369         break;
370 # endif
371       }
372
373     if (msg)
374       {
375         size_t len = strlen (msg);
376
377         if (len < buflen)
378           {
379             memcpy (buf, msg, len + 1);
380             return 0;
381           }
382         else
383           return ERANGE;
384       }
385   }
386 #endif
387
388   {
389     int ret;
390
391 #if USE_SYSTEM_STRERROR_R
392
393     if (buflen > INT_MAX)
394       buflen = INT_MAX;
395
396 # ifdef __hpux
397     /* On HP-UX 11.31, strerror_r always fails when buflen < 80.  */
398     {
399       char stackbuf[80];
400
401       if (buflen < sizeof (stackbuf))
402         {
403           ret = strerror_r (errnum, stackbuf, sizeof (stackbuf));
404           if (ret == 0)
405             {
406               size_t len = strlen (stackbuf);
407
408               if (len < buflen)
409                 memcpy (buf, stackbuf, len + 1);
410               else
411                 ret = ERANGE;
412             }
413         }
414       else
415         ret = strerror_r (errnum, buf, buflen);
416     }
417 # elif defined __CYGWIN__
418     /* Cygwin only provides the glibc interface, is thread-safe, and
419        always succeeds (although it may truncate). */
420     strerror_r (errnum, buf, buflen);
421     ret = 0;
422 # else
423     ret = strerror_r (errnum, buf, buflen);
424 # endif
425
426 # ifdef _AIX
427     /* On AIX 6.1, strerror_r returns -1 and sets errno to EINVAL
428        if buflen <= 1.  */
429     if (ret < 0 && errno == EINVAL && buflen <= 1)
430       {
431         /* Retry with a larger buffer.  */
432         char largerbuf[10];
433         ret = strerror_r (errnum, largerbuf, sizeof (largerbuf));
434         if (ret < 0 && errno == EINVAL)
435           {
436             /* errnum was out of range.  */
437             ret = EINVAL;
438           }
439         else
440           {
441             /* buf was too small.  */
442             ret = ERANGE;
443           }
444       }
445 # endif
446
447     /* Some old implementations may return (-1, EINVAL) instead of EINVAL.  */
448     if (ret < 0)
449       ret = errno;
450
451     /* FreeBSD rejects 0; see http://austingroupbugs.net/view.php?id=382.  */
452     if (errnum == 0 && ret == EINVAL)
453       {
454         if (buflen <= strlen ("Success"))
455           {
456             ret = ERANGE;
457             if (buflen)
458               buf[0] = 0;
459           }
460         else
461           {
462             ret = 0;
463             strcpy (buf, "Success");
464           }
465       }
466
467 #elif USE_XPG_STRERROR_R
468
469     {
470       extern int __xpg_strerror_r (int errnum, char *buf, size_t buflen);
471
472       ret = __xpg_strerror_r (errnum, buf, buflen);
473       if (ret < 0)
474         ret = errno;
475     }
476
477 #else /* USE_SYSTEM_STRERROR */
478
479     gl_lock_lock (strerror_lock);
480
481     {
482       char *errmsg = strerror (errnum);
483
484       /* For invalid error numbers, strerror() on
485            - IRIX 6.5 returns NULL,
486            - HP-UX 11 returns an empty string.  */
487       if (errmsg == NULL || *errmsg == '\0')
488         ret = EINVAL;
489       else
490         {
491           size_t len = strlen (errmsg);
492
493           if (len < buflen)
494             {
495               memcpy (buf, errmsg, len + 1);
496               ret = 0;
497             }
498           else
499             ret = ERANGE;
500         }
501     }
502
503     gl_lock_unlock (strerror_lock);
504
505 #endif
506
507     return ret;
508   }
509 }