1 /* strerror_r.c --- POSIX compatible system error routine
2 
3    Copyright (C) 2010-2018 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 <https://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 #include <stdio.h>
30 #include <stdlib.h>
31 #if !HAVE_SNPRINTF
32 # include <stdarg.h>
33 #endif
34 
35 #include "strerror-override.h"
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 extern
41 #ifdef __cplusplus
42 "C"
43 #endif
44 int __xpg_strerror_r (int errnum, char *buf, size_t buflen);
45 
46 #elif HAVE_DECL_STRERROR_R && !(__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__)
47 
48 /* The system's strerror_r function is OK, except that its third argument
49    is 'int', not 'size_t', or its return type is wrong.  */
50 
51 # include <limits.h>
52 
53 # define USE_SYSTEM_STRERROR_R 1
54 
55 #else /* (__GLIBC__ >= 2 || defined __UCLIBC__ || defined __CYGWIN__ ? !HAVE___XPG_STRERROR_R : !HAVE_DECL_STRERROR_R) */
56 
57 /* Use the system's strerror().  Exclude glibc and cygwin because the
58    system strerror_r has the wrong return type, and cygwin 1.7.9
59    strerror_r clobbers strerror.  */
60 # undef strerror
61 
62 # define USE_SYSTEM_STRERROR 1
63 
64 # if defined __NetBSD__ || defined __hpux || (defined _WIN32 && !defined __CYGWIN__) || defined __sgi || (defined __sun && !defined _LP64) || defined __CYGWIN__
65 
66 /* No locking needed.  */
67 
68 /* Get catgets internationalization functions.  */
69 #  if HAVE_CATGETS
70 #   include <nl_types.h>
71 #  endif
72 
73 #ifdef __cplusplus
74 extern "C" {
75 #endif
76 
77 /* Get sys_nerr, sys_errlist on HP-UX (otherwise only declared in C++ mode).
78    Get sys_nerr, sys_errlist on IRIX (otherwise only declared with _SGIAPI).  */
79 #  if defined __hpux || defined __sgi
80 extern int sys_nerr;
81 extern char *sys_errlist[];
82 #  endif
83 
84 /* Get sys_nerr on Solaris.  */
85 #  if defined __sun && !defined _LP64
86 extern int sys_nerr;
87 #  endif
88 
89 #ifdef __cplusplus
90 }
91 #endif
92 
93 # else
94 
95 #  include "glthread/lock.h"
96 
97 /* This lock protects the buffer returned by strerror().  We assume that
98    no other uses of strerror() exist in the program.  */
gl_lock_define_initialized(static,strerror_lock)99 gl_lock_define_initialized(static, strerror_lock)
100 
101 # endif
102 
103 #endif
104 
105 /* On MSVC, there is no snprintf() function, just a _snprintf().
106    It is of lower quality, but sufficient for the simple use here.
107    We only have to make sure to NUL terminate the result (_snprintf
108    does not NUL terminate, like strncpy).  */
109 #if !HAVE_SNPRINTF
110 static int
111 local_snprintf (char *buf, size_t buflen, const char *format, ...)
112 {
113   va_list args;
114   int result;
115 
116   va_start (args, format);
117   result = _vsnprintf (buf, buflen, format, args);
118   va_end (args);
119   if (buflen > 0 && (result < 0 || result >= buflen))
120     buf[buflen - 1] = '\0';
121   return result;
122 }
123 # define snprintf local_snprintf
124 #endif
125 
126 /* Copy as much of MSG into BUF as possible, without corrupting errno.
127    Return 0 if MSG fit in BUFLEN, otherwise return ERANGE.  */
128 static int
safe_copy(char * buf,size_t buflen,const char * msg)129 safe_copy (char *buf, size_t buflen, const char *msg)
130 {
131   size_t len = strlen (msg);
132   int ret;
133 
134   if (len < buflen)
135     {
136       /* Although POSIX allows memcpy() to corrupt errno, we don't
137          know of any implementation where this is a real problem.  */
138       memcpy (buf, msg, len + 1);
139       ret = 0;
140     }
141   else
142     {
143       memcpy (buf, msg, buflen - 1);
144       buf[buflen - 1] = '\0';
145       ret = ERANGE;
146     }
147   return ret;
148 }
149 
150 
151 int
strerror_r(int errnum,char * buf,size_t buflen)152 strerror_r (int errnum, char *buf, size_t buflen)
153 #undef strerror_r
154 {
155   /* Filter this out now, so that rest of this replacement knows that
156      there is room for a non-empty message and trailing NUL.  */
157   if (buflen <= 1)
158     {
159       if (buflen)
160         *buf = '\0';
161       return ERANGE;
162     }
163   *buf = '\0';
164 
165   /* Check for gnulib overrides.  */
166   {
167     char const *msg = strerror_override (errnum);
168 
169     if (msg)
170       return safe_copy (buf, buflen, msg);
171   }
172 
173   {
174     int ret;
175     int saved_errno = errno;
176 
177 #if USE_XPG_STRERROR_R
178 
179     {
180       ret = __xpg_strerror_r (errnum, buf, buflen);
181       if (ret < 0)
182         ret = errno;
183       if (!*buf)
184         {
185           /* glibc 2.13 would not touch buf on err, so we have to fall
186              back to GNU strerror_r which always returns a thread-safe
187              untruncated string to (partially) copy into our buf.  */
188           safe_copy (buf, buflen, strerror_r (errnum, buf, buflen));
189         }
190     }
191 
192 #elif USE_SYSTEM_STRERROR_R
193 
194     if (buflen > INT_MAX)
195       buflen = INT_MAX;
196 
197 # ifdef __hpux
198     /* On HP-UX 11.31, strerror_r always fails when buflen < 80; it
199        also fails to change buf on EINVAL.  */
200     {
201       char stackbuf[80];
202 
203       if (buflen < sizeof stackbuf)
204         {
205           ret = strerror_r (errnum, stackbuf, sizeof stackbuf);
206           if (ret == 0)
207             ret = safe_copy (buf, buflen, stackbuf);
208         }
209       else
210         ret = strerror_r (errnum, buf, buflen);
211     }
212 # else
213     ret = strerror_r (errnum, buf, buflen);
214 
215     /* Some old implementations may return (-1, EINVAL) instead of EINVAL.
216        But on Haiku, valid error numbers are negative.  */
217 #  if !defined __HAIKU__
218     if (ret < 0)
219       ret = errno;
220 #  endif
221 # endif
222 
223 # if defined _AIX || defined __HAIKU__
224     /* AIX and Haiku return 0 rather than ERANGE when truncating strings; try
225        again until we are sure we got the entire string.  */
226     if (!ret && strlen (buf) == buflen - 1)
227       {
228         char stackbuf[STACKBUF_LEN];
229         size_t len;
230         strerror_r (errnum, stackbuf, sizeof stackbuf);
231         len = strlen (stackbuf);
232         /* STACKBUF_LEN should have been large enough.  */
233         if (len + 1 == sizeof stackbuf)
234           abort ();
235         if (buflen <= len)
236           ret = ERANGE;
237       }
238 # else
239     /* Solaris 10 does not populate buf on ERANGE.  OpenBSD 4.7
240        truncates early on ERANGE rather than return a partial integer.
241        We prefer the maximal string.  We set buf[0] earlier, and we
242        know of no implementation that modifies buf to be an
243        unterminated string, so this strlen should be portable in
244        practice (rather than pulling in a safer strnlen).  */
245     if (ret == ERANGE && strlen (buf) < buflen - 1)
246       {
247         char stackbuf[STACKBUF_LEN];
248 
249         /* STACKBUF_LEN should have been large enough.  */
250         if (strerror_r (errnum, stackbuf, sizeof stackbuf) == ERANGE)
251           abort ();
252         safe_copy (buf, buflen, stackbuf);
253       }
254 # endif
255 
256 #else /* USE_SYSTEM_STRERROR */
257 
258     /* Try to do what strerror (errnum) does, but without clobbering the
259        buffer used by strerror().  */
260 
261 # if defined __NetBSD__ || defined __hpux || (defined _WIN32 && !defined __CYGWIN__) || defined __CYGWIN__ /* NetBSD, HP-UX, native Windows, Cygwin */
262 
263     /* NetBSD:         sys_nerr, sys_errlist are declared through _NETBSD_SOURCE
264                        and <errno.h> above.
265        HP-UX:          sys_nerr, sys_errlist are declared explicitly above.
266        native Windows: sys_nerr, sys_errlist are declared in <stdlib.h>.
267        Cygwin:         sys_nerr, sys_errlist are declared in <errno.h>.  */
268     if (errnum >= 0 && errnum < sys_nerr)
269       {
270 #  if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
271 #   if defined __NetBSD__
272         nl_catd catd = catopen ("libc", NL_CAT_LOCALE);
273         const char *errmsg =
274           (catd != (nl_catd)-1
275            ? catgets (catd, 1, errnum, sys_errlist[errnum])
276            : sys_errlist[errnum]);
277 #   endif
278 #   if defined __hpux
279         nl_catd catd = catopen ("perror", NL_CAT_LOCALE);
280         const char *errmsg =
281           (catd != (nl_catd)-1
282            ? catgets (catd, 1, 1 + errnum, sys_errlist[errnum])
283            : sys_errlist[errnum]);
284 #   endif
285 #  else
286         const char *errmsg = sys_errlist[errnum];
287 #  endif
288         if (errmsg == NULL || *errmsg == '\0')
289           ret = EINVAL;
290         else
291           ret = safe_copy (buf, buflen, errmsg);
292 #  if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux)
293         if (catd != (nl_catd)-1)
294           catclose (catd);
295 #  endif
296       }
297     else
298       ret = EINVAL;
299 
300 # elif defined __sgi || (defined __sun && !defined _LP64) /* IRIX, Solaris <= 9 32-bit */
301 
302     /* For a valid error number, the system's strerror() function returns
303        a pointer to a not copied string, not to a buffer.  */
304     if (errnum >= 0 && errnum < sys_nerr)
305       {
306         char *errmsg = strerror (errnum);
307 
308         if (errmsg == NULL || *errmsg == '\0')
309           ret = EINVAL;
310         else
311           ret = safe_copy (buf, buflen, errmsg);
312       }
313     else
314       ret = EINVAL;
315 
316 # else
317 
318     gl_lock_lock (strerror_lock);
319 
320     {
321       char *errmsg = strerror (errnum);
322 
323       /* For invalid error numbers, strerror() on
324            - IRIX 6.5 returns NULL,
325            - HP-UX 11 returns an empty string.  */
326       if (errmsg == NULL || *errmsg == '\0')
327         ret = EINVAL;
328       else
329         ret = safe_copy (buf, buflen, errmsg);
330     }
331 
332     gl_lock_unlock (strerror_lock);
333 
334 # endif
335 
336 #endif
337 
338 #if defined _WIN32 && !defined __CYGWIN__
339     /* MSVC 14 defines names for many error codes in the range 100..140,
340        but _sys_errlist contains strings only for the error codes
341        < _sys_nerr = 43.  */
342     if (ret == EINVAL)
343       {
344         const char *errmsg;
345 
346         switch (errnum)
347           {
348           case 100 /* EADDRINUSE */:
349             errmsg = "Address already in use";
350             break;
351           case 101 /* EADDRNOTAVAIL */:
352             errmsg = "Cannot assign requested address";
353             break;
354           case 102 /* EAFNOSUPPORT */:
355             errmsg = "Address family not supported by protocol";
356             break;
357           case 103 /* EALREADY */:
358             errmsg = "Operation already in progress";
359             break;
360           case 105 /* ECANCELED */:
361             errmsg = "Operation canceled";
362             break;
363           case 106 /* ECONNABORTED */:
364             errmsg = "Software caused connection abort";
365             break;
366           case 107 /* ECONNREFUSED */:
367             errmsg = "Connection refused";
368             break;
369           case 108 /* ECONNRESET */:
370             errmsg = "Connection reset by peer";
371             break;
372           case 109 /* EDESTADDRREQ */:
373             errmsg = "Destination address required";
374             break;
375           case 110 /* EHOSTUNREACH */:
376             errmsg = "No route to host";
377             break;
378           case 112 /* EINPROGRESS */:
379             errmsg = "Operation now in progress";
380             break;
381           case 113 /* EISCONN */:
382             errmsg = "Transport endpoint is already connected";
383             break;
384           case 114 /* ELOOP */:
385             errmsg = "Too many levels of symbolic links";
386             break;
387           case 115 /* EMSGSIZE */:
388             errmsg = "Message too long";
389             break;
390           case 116 /* ENETDOWN */:
391             errmsg = "Network is down";
392             break;
393           case 117 /* ENETRESET */:
394             errmsg = "Network dropped connection on reset";
395             break;
396           case 118 /* ENETUNREACH */:
397             errmsg = "Network is unreachable";
398             break;
399           case 119 /* ENOBUFS */:
400             errmsg = "No buffer space available";
401             break;
402           case 123 /* ENOPROTOOPT */:
403             errmsg = "Protocol not available";
404             break;
405           case 126 /* ENOTCONN */:
406             errmsg = "Transport endpoint is not connected";
407             break;
408           case 128 /* ENOTSOCK */:
409             errmsg = "Socket operation on non-socket";
410             break;
411           case 129 /* ENOTSUP */:
412             errmsg = "Not supported";
413             break;
414           case 130 /* EOPNOTSUPP */:
415             errmsg = "Operation not supported";
416             break;
417           case 132 /* EOVERFLOW */:
418             errmsg = "Value too large for defined data type";
419             break;
420           case 133 /* EOWNERDEAD */:
421             errmsg = "Owner died";
422             break;
423           case 134 /* EPROTO */:
424             errmsg = "Protocol error";
425             break;
426           case 135 /* EPROTONOSUPPORT */:
427             errmsg = "Protocol not supported";
428             break;
429           case 136 /* EPROTOTYPE */:
430             errmsg = "Protocol wrong type for socket";
431             break;
432           case 138 /* ETIMEDOUT */:
433             errmsg = "Connection timed out";
434             break;
435           case 140 /* EWOULDBLOCK */:
436             errmsg = "Operation would block";
437             break;
438           default:
439             errmsg = NULL;
440             break;
441           }
442         if (errmsg != NULL)
443           ret = safe_copy (buf, buflen, errmsg);
444       }
445 #endif
446 
447     if (ret == EINVAL && !*buf)
448       {
449 #if defined __HAIKU__
450         /* For consistency with perror().  */
451         snprintf (buf, buflen, "Unknown Application Error (%d)", errnum);
452 #else
453         snprintf (buf, buflen, "Unknown error %d", errnum);
454 #endif
455       }
456 
457     errno = saved_errno;
458     return ret;
459   }
460 }
461