root/maint/gnulib/lib/strerror_r.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gl_lock_define_initialized
  2. safe_copy
  3. strerror_r

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

/* [previous][next][first][last][top][bottom][index][help] */