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