bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: perror bug


From: Bruno Haible
Subject: Re: perror bug
Date: Thu, 19 May 2011 05:27:23 +0200
User-agent: KMail/1.9.9

On 2011-14-03 I wrote in
<http://lists.gnu.org/archive/html/bug-gnulib/2011-03/msg00117.html>:
> With gnulib, there are three problems
> in toto:
>   1) The strerror_r replacement, when EXTEND_STRERROR_R is defined,
>      clobbers the strerror function's buffer, which it shouldn't.
>   2) The perror replacement uses strerror, thus clobbering the strerror
>      buffer.
>   3) On Cygwin, perror clobbers the strerror buffer.
> 
> The fix for 1) should be to move most of lib/strerror.c to lib/strerror_r.c.
> The fix for 2) should be to change lib/perror.c to call strerror_r.
> The fix for 3) should be to change m4/perror.m4 to enable the replacement
> on Cygwin.

Here comes the fix for 1). Tested on

  glibc 2.8
  glibc 2.8 with -D_POSIX_C_SOURCE=200112L
  MacOS X 10.5
  OpenBSD 4.4
  AIX 5.1
  AIX 6.1
  HP-UX 11.23
  HP-UX 11.31
  IRIX 6.5
  OSF/1 5.1
  Solaris 9
  Solaris 10
  mingw
  Cygwin 1.5.x


2011-05-18  Bruno Haible  <address@hidden>

        strerror_r: Avoid clobbering the strerror buffer when possible.
        * lib/strerror_r.c (strerror_r): Merge the three implementations.
        Handle gnulib defined errno values here. When strerror() returns NULL
        or an empty string, return EINVAL.
        * lib/strerror.c (strerror): Always call strerror_r. Don't handle
        gnulib defined errno values here.
        * modules/strerror (Depends-on): Add verify, strerror_r-posix.

*** lib/strerror.c.orig Thu May 19 05:17:36 2011
--- lib/strerror.c      Thu May 19 04:47:44 2011
***************
*** 17,355 ****
  
  #include <config.h>
  
  #include <string.h>
  
  #if REPLACE_STRERROR
  
  # include <errno.h>
  # include <stdio.h>
! 
! # if GNULIB_defined_ESOCK /* native Windows platforms */
! #  if HAVE_WINSOCK2_H
! #   include <winsock2.h>
! #  endif
! # endif
  
  # include "intprops.h"
  
  /* Use the system functions, not the gnulib overrides in this file.  */
  # undef sprintf
  
- # undef strerror
- # if ! HAVE_DECL_STRERROR
- #  define strerror(n) NULL
- # endif
- 
  char *
! rpl_strerror (int n)
  {
!   char const *msg = NULL;
!   /* These error messages are taken from glibc/sysdeps/gnu/errlist.c.  */
!   switch (n)
!     {
! # if GNULIB_defined_ETXTBSY
!     case ETXTBSY:
!       msg = "Text file busy";
!       break;
! # endif
! 
! # if GNULIB_defined_ESOCK /* native Windows platforms */
!     /* EWOULDBLOCK is the same as EAGAIN.  */
!     case EINPROGRESS:
!       msg = "Operation now in progress";
!       break;
!     case EALREADY:
!       msg = "Operation already in progress";
!       break;
!     case ENOTSOCK:
!       msg = "Socket operation on non-socket";
!       break;
!     case EDESTADDRREQ:
!       msg = "Destination address required";
!       break;
!     case EMSGSIZE:
!       msg = "Message too long";
!       break;
!     case EPROTOTYPE:
!       msg = "Protocol wrong type for socket";
!       break;
!     case ENOPROTOOPT:
!       msg = "Protocol not available";
!       break;
!     case EPROTONOSUPPORT:
!       msg = "Protocol not supported";
!       break;
!     case ESOCKTNOSUPPORT:
!       msg = "Socket type not supported";
!       break;
!     case EOPNOTSUPP:
!       msg = "Operation not supported";
!       break;
!     case EPFNOSUPPORT:
!       msg = "Protocol family not supported";
!       break;
!     case EAFNOSUPPORT:
!       msg = "Address family not supported by protocol";
!       break;
!     case EADDRINUSE:
!       msg = "Address already in use";
!       break;
!     case EADDRNOTAVAIL:
!       msg = "Cannot assign requested address";
!       break;
!     case ENETDOWN:
!       msg = "Network is down";
!       break;
!     case ENETUNREACH:
!       msg = "Network is unreachable";
!       break;
!     case ENETRESET:
!       msg = "Network dropped connection on reset";
!       break;
!     case ECONNABORTED:
!       msg = "Software caused connection abort";
!       break;
!     case ECONNRESET:
!       msg = "Connection reset by peer";
!       break;
!     case ENOBUFS:
!       msg = "No buffer space available";
!       break;
!     case EISCONN:
!       msg = "Transport endpoint is already connected";
!       break;
!     case ENOTCONN:
!       msg = "Transport endpoint is not connected";
!       break;
!     case ESHUTDOWN:
!       msg = "Cannot send after transport endpoint shutdown";
!       break;
!     case ETOOMANYREFS:
!       msg = "Too many references: cannot splice";
!       break;
!     case ETIMEDOUT:
!       msg = "Connection timed out";
!       break;
!     case ECONNREFUSED:
!       msg = "Connection refused";
!       break;
!     case ELOOP:
!       msg = "Too many levels of symbolic links";
!       break;
!     case EHOSTDOWN:
!       msg = "Host is down";
!       break;
!     case EHOSTUNREACH:
!       msg = "No route to host";
!       break;
!     case EPROCLIM:
!       msg = "Too many processes";
!       break;
!     case EUSERS:
!       msg = "Too many users";
!       break;
!     case EDQUOT:
!       msg = "Disk quota exceeded";
!       break;
!     case ESTALE:
!       msg = "Stale NFS file handle";
!       break;
!     case EREMOTE:
!       msg = "Object is remote";
!       break;
! #  if HAVE_WINSOCK2_H
!     /* WSA_INVALID_HANDLE maps to EBADF */
!     /* WSA_NOT_ENOUGH_MEMORY maps to ENOMEM */
!     /* WSA_INVALID_PARAMETER maps to EINVAL */
!     case WSA_OPERATION_ABORTED:
!       msg = "Overlapped operation aborted";
!       break;
!     case WSA_IO_INCOMPLETE:
!       msg = "Overlapped I/O event object not in signaled state";
!       break;
!     case WSA_IO_PENDING:
!       msg = "Overlapped operations will complete later";
!       break;
!     /* WSAEINTR maps to EINTR */
!     /* WSAEBADF maps to EBADF */
!     /* WSAEACCES maps to EACCES */
!     /* WSAEFAULT maps to EFAULT */
!     /* WSAEINVAL maps to EINVAL */
!     /* WSAEMFILE maps to EMFILE */
!     /* WSAEWOULDBLOCK maps to EWOULDBLOCK */
!     /* WSAEINPROGRESS is EINPROGRESS */
!     /* WSAEALREADY is EALREADY */
!     /* WSAENOTSOCK is ENOTSOCK */
!     /* WSAEDESTADDRREQ is EDESTADDRREQ */
!     /* WSAEMSGSIZE is EMSGSIZE */
!     /* WSAEPROTOTYPE is EPROTOTYPE */
!     /* WSAENOPROTOOPT is ENOPROTOOPT */
!     /* WSAEPROTONOSUPPORT is EPROTONOSUPPORT */
!     /* WSAESOCKTNOSUPPORT is ESOCKTNOSUPPORT */
!     /* WSAEOPNOTSUPP is EOPNOTSUPP */
!     /* WSAEPFNOSUPPORT is EPFNOSUPPORT */
!     /* WSAEAFNOSUPPORT is EAFNOSUPPORT */
!     /* WSAEADDRINUSE is EADDRINUSE */
!     /* WSAEADDRNOTAVAIL is EADDRNOTAVAIL */
!     /* WSAENETDOWN is ENETDOWN */
!     /* WSAENETUNREACH is ENETUNREACH */
!     /* WSAENETRESET is ENETRESET */
!     /* WSAECONNABORTED is ECONNABORTED */
!     /* WSAECONNRESET is ECONNRESET */
!     /* WSAENOBUFS is ENOBUFS */
!     /* WSAEISCONN is EISCONN */
!     /* WSAENOTCONN is ENOTCONN */
!     /* WSAESHUTDOWN is ESHUTDOWN */
!     /* WSAETOOMANYREFS is ETOOMANYREFS */
!     /* WSAETIMEDOUT is ETIMEDOUT */
!     /* WSAECONNREFUSED is ECONNREFUSED */
!     /* WSAELOOP is ELOOP */
!     /* WSAENAMETOOLONG maps to ENAMETOOLONG */
!     /* WSAEHOSTDOWN is EHOSTDOWN */
!     /* WSAEHOSTUNREACH is EHOSTUNREACH */
!     /* WSAENOTEMPTY maps to ENOTEMPTY */
!     /* WSAEPROCLIM is EPROCLIM */
!     /* WSAEUSERS is EUSERS */
!     /* WSAEDQUOT is EDQUOT */
!     /* WSAESTALE is ESTALE */
!     /* WSAEREMOTE is EREMOTE */
!     case WSASYSNOTREADY:
!       msg = "Network subsystem is unavailable";
!       break;
!     case WSAVERNOTSUPPORTED:
!       msg = "Winsock.dll version out of range";
!       break;
!     case WSANOTINITIALISED:
!       msg = "Successful WSAStartup not yet performed";
!       break;
!     case WSAEDISCON:
!       msg = "Graceful shutdown in progress";
!       break;
!     case WSAENOMORE: case WSA_E_NO_MORE:
!       msg = "No more results";
!       break;
!     case WSAECANCELLED: case WSA_E_CANCELLED:
!       msg = "Call was canceled";
!       break;
!     case WSAEINVALIDPROCTABLE:
!       msg = "Procedure call table is invalid";
!       break;
!     case WSAEINVALIDPROVIDER:
!       msg = "Service provider is invalid";
!       break;
!     case WSAEPROVIDERFAILEDINIT:
!       msg = "Service provider failed to initialize";
!       break;
!     case WSASYSCALLFAILURE:
!       msg = "System call failure";
!       break;
!     case WSASERVICE_NOT_FOUND:
!       msg = "Service not found";
!       break;
!     case WSATYPE_NOT_FOUND:
!       msg = "Class type not found";
!       break;
!     case WSAEREFUSED:
!       msg = "Database query was refused";
!       break;
!     case WSAHOST_NOT_FOUND:
!       msg = "Host not found";
!       break;
!     case WSATRY_AGAIN:
!       msg = "Nonauthoritative host not found";
!       break;
!     case WSANO_RECOVERY:
!       msg = "Nonrecoverable error";
!       break;
!     case WSANO_DATA:
!       msg = "Valid name, no data record of requested type";
!       break;
!     /* WSA_QOS_* omitted */
! #  endif
! # endif
! 
! # if GNULIB_defined_ENOMSG
!     case ENOMSG:
!       msg = "No message of desired type";
!       break;
! # endif
! 
! # if GNULIB_defined_EIDRM
!     case EIDRM:
!       msg = "Identifier removed";
!       break;
! # endif
! 
! # if GNULIB_defined_ENOLINK
!     case ENOLINK:
!       msg = "Link has been severed";
!       break;
! # endif
! 
! # if GNULIB_defined_EPROTO
!     case EPROTO:
!       msg = "Protocol error";
!       break;
! # endif
! 
! # if GNULIB_defined_EMULTIHOP
!     case EMULTIHOP:
!       msg = "Multihop attempted";
!       break;
! # endif
! 
! # if GNULIB_defined_EBADMSG
!     case EBADMSG:
!       msg = "Bad message";
!       break;
! # endif
! 
! # if GNULIB_defined_EOVERFLOW
!     case EOVERFLOW:
!       msg = "Value too large for defined data type";
!       break;
! # endif
! 
! # if GNULIB_defined_ENOTSUP
!     case ENOTSUP:
!       msg = "Not supported";
!       break;
! # endif
! 
! # if GNULIB_defined_ESTALE
!     case ESTALE:
!       msg = "Stale NFS file handle";
!       break;
! # endif
! 
! # if GNULIB_defined_EDQUOT
!     case EDQUOT:
!       msg = "Disk quota exceeded";
!       break;
! # endif
! 
! # if GNULIB_defined_ECANCELED
!     case ECANCELED:
!       msg = "Operation canceled";
!       break;
! # endif
!     }
  
!   if (msg)
!     return (char *) msg;
  
!   {
!     char *result = strerror (n);
  
!     if (result == NULL || result[0] == '\0')
!       {
!         static char const fmt[] = "Unknown error (%d)";
!         static char msg_buf[sizeof fmt + INT_STRLEN_BOUND (n)];
!         sprintf (msg_buf, fmt, n);
!         return msg_buf;
!       }
  
!     return result;
    }
  }
  
--- 17,56 ----
  
  #include <config.h>
  
+ /* Specification.  */
  #include <string.h>
  
  #if REPLACE_STRERROR
  
  # include <errno.h>
  # include <stdio.h>
! # include <stdlib.h>
  
  # include "intprops.h"
+ # include "verify.h"
  
  /* Use the system functions, not the gnulib overrides in this file.  */
  # undef sprintf
  
  char *
! strerror (int n)
  {
!   static char buf[256];
  
!   int ret = strerror_r (n, buf, sizeof (buf));
  
!   if (ret == 0)
!     return buf;
  
!   if (ret == ERANGE)
!     /* If this happens, increase the size of buf.  */
!     abort ();
  
!   {
!     static char const fmt[] = "Unknown error (%d)";
!     verify (sizeof (buf) >= sizeof (fmt) + INT_STRLEN_BOUND (n));
!     sprintf (buf, fmt, n);
!     return buf;
    }
  }
  
*** lib/strerror_r.c.orig       Thu May 19 05:17:36 2011
--- lib/strerror_r.c    Thu May 19 05:04:39 2011
***************
*** 24,143 ****
  
  #include <errno.h>
  
! #if HAVE_DECL_STRERROR_R && !(__GLIBC__ >= 2 || defined __UCLIBC__) && 
!EXTEND_STRERROR_R
  
  /* The system's strerror_r function is OK, except that its third argument
     is 'int', not 'size_t', or its return type is wrong.  */
  
  # include <limits.h>
  
  int
  strerror_r (int errnum, char *buf, size_t buflen)
! # undef strerror_r
  {
!   int ret;
  
!   if (buflen > INT_MAX)
!     buflen = INT_MAX;
  
! # ifdef __hpux
!   /* On HP-UX 11.31, strerror_r always fails when buflen < 80.  */
!   {
!     char stackbuf[80];
  
!     if (buflen < sizeof (stackbuf))
        {
!         ret = strerror_r (errnum, stackbuf, sizeof (stackbuf));
!         if (ret == 0)
!           {
!             size_t len = strlen (stackbuf);
  
!             if (len < buflen)
!               memcpy (buf, stackbuf, len + 1);
!             else
!               ret = ERANGE;
            }
        }
-     else
-       ret = strerror_r (errnum, buf, buflen);
    }
! # elif defined __CYGWIN__
!   /* Cygwin only provides the glibc interface, is thread-safe, and
!      always succeeds (although it may truncate). */
!   strerror_r (errnum, buf, buflen);
!   ret = 0;
! # else
!   ret = strerror_r (errnum, buf, buflen);
! # endif
  
! # ifdef _AIX
!   /* On AIX 6.1, strerror_r returns -1 and sets errno to EINVAL
!      if buflen <= 1.  */
!   if (ret < 0 && errno == EINVAL && buflen <= 1)
      {
!       /* Retry with a larger buffer.  */
!       char largerbuf[10];
!       ret = strerror_r (errnum, largerbuf, sizeof (largerbuf));
!       if (ret < 0 && errno == EINVAL)
          {
!           /* errnum was out of range.  */
!           return EINVAL;
          }
        else
!         {
!           /* buf was too small.  */
!           return ERANGE;
!         }
      }
  # endif
  
!   /* Some old implementations may return (-1, EINVAL) instead of EINVAL.  */
!   return (ret < 0 ? errno : ret);
! }
! 
! #elif (__GLIBC__ >= 2 || defined __UCLIBC__) && HAVE___XPG_STRERROR_R /* 
glibc >= 2.3.4 */ && !EXTEND_STRERROR_R
  
! int
! strerror_r (int errnum, char *buf, size_t buflen)
! {
!   extern int __xpg_strerror_r (int errnum, char *buf, size_t buflen);
  
!   int ret = __xpg_strerror_r (errnum, buf, buflen);
!   return (ret < 0 ? errno : ret);
! }
  
! #else /* (__GLIBC__ >= 2 || defined __UCLIBC__ ? !HAVE___XPG_STRERROR_R : 
!HAVE_DECL_STRERROR_R) || EXTEND_STRERROR_R */
  
! # include "glthread/lock.h"
  
! /* Use strerror(), with locking.  */
  
! /* This lock protects the buffer returned by strerror().  We assume that
!    no other uses of strerror() exist in the program.  */
! gl_lock_define_initialized(static, strerror_lock)
  
! int
! strerror_r (int errnum, char *buf, size_t buflen)
! {
!   gl_lock_lock (strerror_lock);
  
!   {
!     char *errmsg = strerror (errnum);
!     size_t len = strlen (errmsg);
!     int ret;
  
!     if (len < buflen)
!       {
!         memcpy (buf, errmsg, len + 1);
!         ret = 0;
!       }
!     else
!       ret = ERANGE;
  
      gl_lock_unlock (strerror_lock);
  
      return ret;
    }
  }
- 
- #endif
--- 24,481 ----
  
  #include <errno.h>
  
! # if GNULIB_defined_ESOCK /* native Windows platforms */
! #  if HAVE_WINSOCK2_H
! #   include <winsock2.h>
! #  endif
! # endif
! 
! 
! #if HAVE_DECL_STRERROR_R && !(__GLIBC__ >= 2 || defined __UCLIBC__)
  
  /* The system's strerror_r function is OK, except that its third argument
     is 'int', not 'size_t', or its return type is wrong.  */
  
  # include <limits.h>
  
+ # define USE_SYSTEM_STRERROR_R 1
+ 
+ #elif (__GLIBC__ >= 2 || defined __UCLIBC__) && HAVE___XPG_STRERROR_R /* 
glibc >= 2.3.4 */
+ 
+ # define USE_XPG_STRERROR_R 1
+ 
+ #else /* (__GLIBC__ >= 2 || defined __UCLIBC__ ? !HAVE___XPG_STRERROR_R : 
!HAVE_DECL_STRERROR_R) */
+ 
+ # include "glthread/lock.h"
+ 
+ /* Use strerror(), with locking.  */
+ # undef strerror
+ 
+ # define USE_SYSTEM_STRERROR 1
+ 
+ /* This lock protects the buffer returned by strerror().  We assume that
+    no other uses of strerror() exist in the program.  */
+ gl_lock_define_initialized(static, strerror_lock)
+ 
+ #endif
+ 
+ 
  int
  strerror_r (int errnum, char *buf, size_t buflen)
! #undef strerror_r
  {
! #if EXTEND_STRERROR_R
!   {
!     char const *msg = NULL;
!     /* These error messages are taken from glibc/sysdeps/gnu/errlist.c.  */
!     switch (errnum)
!       {
! # if GNULIB_defined_ETXTBSY
!       case ETXTBSY:
!         msg = "Text file busy";
!         break;
! # endif
  
! # if GNULIB_defined_ESOCK /* native Windows platforms */
!       /* EWOULDBLOCK is the same as EAGAIN.  */
!       case EINPROGRESS:
!         msg = "Operation now in progress";
!         break;
!       case EALREADY:
!         msg = "Operation already in progress";
!         break;
!       case ENOTSOCK:
!         msg = "Socket operation on non-socket";
!         break;
!       case EDESTADDRREQ:
!         msg = "Destination address required";
!         break;
!       case EMSGSIZE:
!         msg = "Message too long";
!         break;
!       case EPROTOTYPE:
!         msg = "Protocol wrong type for socket";
!         break;
!       case ENOPROTOOPT:
!         msg = "Protocol not available";
!         break;
!       case EPROTONOSUPPORT:
!         msg = "Protocol not supported";
!         break;
!       case ESOCKTNOSUPPORT:
!         msg = "Socket type not supported";
!         break;
!       case EOPNOTSUPP:
!         msg = "Operation not supported";
!         break;
!       case EPFNOSUPPORT:
!         msg = "Protocol family not supported";
!         break;
!       case EAFNOSUPPORT:
!         msg = "Address family not supported by protocol";
!         break;
!       case EADDRINUSE:
!         msg = "Address already in use";
!         break;
!       case EADDRNOTAVAIL:
!         msg = "Cannot assign requested address";
!         break;
!       case ENETDOWN:
!         msg = "Network is down";
!         break;
!       case ENETUNREACH:
!         msg = "Network is unreachable";
!         break;
!       case ENETRESET:
!         msg = "Network dropped connection on reset";
!         break;
!       case ECONNABORTED:
!         msg = "Software caused connection abort";
!         break;
!       case ECONNRESET:
!         msg = "Connection reset by peer";
!         break;
!       case ENOBUFS:
!         msg = "No buffer space available";
!         break;
!       case EISCONN:
!         msg = "Transport endpoint is already connected";
!         break;
!       case ENOTCONN:
!         msg = "Transport endpoint is not connected";
!         break;
!       case ESHUTDOWN:
!         msg = "Cannot send after transport endpoint shutdown";
!         break;
!       case ETOOMANYREFS:
!         msg = "Too many references: cannot splice";
!         break;
!       case ETIMEDOUT:
!         msg = "Connection timed out";
!         break;
!       case ECONNREFUSED:
!         msg = "Connection refused";
!         break;
!       case ELOOP:
!         msg = "Too many levels of symbolic links";
!         break;
!       case EHOSTDOWN:
!         msg = "Host is down";
!         break;
!       case EHOSTUNREACH:
!         msg = "No route to host";
!         break;
!       case EPROCLIM:
!         msg = "Too many processes";
!         break;
!       case EUSERS:
!         msg = "Too many users";
!         break;
!       case EDQUOT:
!         msg = "Disk quota exceeded";
!         break;
!       case ESTALE:
!         msg = "Stale NFS file handle";
!         break;
!       case EREMOTE:
!         msg = "Object is remote";
!         break;
! #  if HAVE_WINSOCK2_H
!       /* WSA_INVALID_HANDLE maps to EBADF */
!       /* WSA_NOT_ENOUGH_MEMORY maps to ENOMEM */
!       /* WSA_INVALID_PARAMETER maps to EINVAL */
!       case WSA_OPERATION_ABORTED:
!         msg = "Overlapped operation aborted";
!         break;
!       case WSA_IO_INCOMPLETE:
!         msg = "Overlapped I/O event object not in signaled state";
!         break;
!       case WSA_IO_PENDING:
!         msg = "Overlapped operations will complete later";
!         break;
!       /* WSAEINTR maps to EINTR */
!       /* WSAEBADF maps to EBADF */
!       /* WSAEACCES maps to EACCES */
!       /* WSAEFAULT maps to EFAULT */
!       /* WSAEINVAL maps to EINVAL */
!       /* WSAEMFILE maps to EMFILE */
!       /* WSAEWOULDBLOCK maps to EWOULDBLOCK */
!       /* WSAEINPROGRESS is EINPROGRESS */
!       /* WSAEALREADY is EALREADY */
!       /* WSAENOTSOCK is ENOTSOCK */
!       /* WSAEDESTADDRREQ is EDESTADDRREQ */
!       /* WSAEMSGSIZE is EMSGSIZE */
!       /* WSAEPROTOTYPE is EPROTOTYPE */
!       /* WSAENOPROTOOPT is ENOPROTOOPT */
!       /* WSAEPROTONOSUPPORT is EPROTONOSUPPORT */
!       /* WSAESOCKTNOSUPPORT is ESOCKTNOSUPPORT */
!       /* WSAEOPNOTSUPP is EOPNOTSUPP */
!       /* WSAEPFNOSUPPORT is EPFNOSUPPORT */
!       /* WSAEAFNOSUPPORT is EAFNOSUPPORT */
!       /* WSAEADDRINUSE is EADDRINUSE */
!       /* WSAEADDRNOTAVAIL is EADDRNOTAVAIL */
!       /* WSAENETDOWN is ENETDOWN */
!       /* WSAENETUNREACH is ENETUNREACH */
!       /* WSAENETRESET is ENETRESET */
!       /* WSAECONNABORTED is ECONNABORTED */
!       /* WSAECONNRESET is ECONNRESET */
!       /* WSAENOBUFS is ENOBUFS */
!       /* WSAEISCONN is EISCONN */
!       /* WSAENOTCONN is ENOTCONN */
!       /* WSAESHUTDOWN is ESHUTDOWN */
!       /* WSAETOOMANYREFS is ETOOMANYREFS */
!       /* WSAETIMEDOUT is ETIMEDOUT */
!       /* WSAECONNREFUSED is ECONNREFUSED */
!       /* WSAELOOP is ELOOP */
!       /* WSAENAMETOOLONG maps to ENAMETOOLONG */
!       /* WSAEHOSTDOWN is EHOSTDOWN */
!       /* WSAEHOSTUNREACH is EHOSTUNREACH */
!       /* WSAENOTEMPTY maps to ENOTEMPTY */
!       /* WSAEPROCLIM is EPROCLIM */
!       /* WSAEUSERS is EUSERS */
!       /* WSAEDQUOT is EDQUOT */
!       /* WSAESTALE is ESTALE */
!       /* WSAEREMOTE is EREMOTE */
!       case WSASYSNOTREADY:
!         msg = "Network subsystem is unavailable";
!         break;
!       case WSAVERNOTSUPPORTED:
!         msg = "Winsock.dll version out of range";
!         break;
!       case WSANOTINITIALISED:
!         msg = "Successful WSAStartup not yet performed";
!         break;
!       case WSAEDISCON:
!         msg = "Graceful shutdown in progress";
!         break;
!       case WSAENOMORE: case WSA_E_NO_MORE:
!         msg = "No more results";
!         break;
!       case WSAECANCELLED: case WSA_E_CANCELLED:
!         msg = "Call was canceled";
!         break;
!       case WSAEINVALIDPROCTABLE:
!         msg = "Procedure call table is invalid";
!         break;
!       case WSAEINVALIDPROVIDER:
!         msg = "Service provider is invalid";
!         break;
!       case WSAEPROVIDERFAILEDINIT:
!         msg = "Service provider failed to initialize";
!         break;
!       case WSASYSCALLFAILURE:
!         msg = "System call failure";
!         break;
!       case WSASERVICE_NOT_FOUND:
!         msg = "Service not found";
!         break;
!       case WSATYPE_NOT_FOUND:
!         msg = "Class type not found";
!         break;
!       case WSAEREFUSED:
!         msg = "Database query was refused";
!         break;
!       case WSAHOST_NOT_FOUND:
!         msg = "Host not found";
!         break;
!       case WSATRY_AGAIN:
!         msg = "Nonauthoritative host not found";
!         break;
!       case WSANO_RECOVERY:
!         msg = "Nonrecoverable error";
!         break;
!       case WSANO_DATA:
!         msg = "Valid name, no data record of requested type";
!         break;
!       /* WSA_QOS_* omitted */
! #  endif
! # endif
  
! # if GNULIB_defined_ENOMSG
!       case ENOMSG:
!         msg = "No message of desired type";
!         break;
! # endif
  
! # if GNULIB_defined_EIDRM
!       case EIDRM:
!         msg = "Identifier removed";
!         break;
! # endif
! 
! # if GNULIB_defined_ENOLINK
!       case ENOLINK:
!         msg = "Link has been severed";
!         break;
! # endif
! 
! # if GNULIB_defined_EPROTO
!       case EPROTO:
!         msg = "Protocol error";
!         break;
! # endif
! 
! # if GNULIB_defined_EMULTIHOP
!       case EMULTIHOP:
!         msg = "Multihop attempted";
!         break;
! # endif
! 
! # if GNULIB_defined_EBADMSG
!       case EBADMSG:
!         msg = "Bad message";
!         break;
! # endif
! 
! # if GNULIB_defined_EOVERFLOW
!       case EOVERFLOW:
!         msg = "Value too large for defined data type";
!         break;
! # endif
! 
! # if GNULIB_defined_ENOTSUP
!       case ENOTSUP:
!         msg = "Not supported";
!         break;
! # endif
! 
! # if GNULIB_defined_ESTALE
!       case ESTALE:
!         msg = "Stale NFS file handle";
!         break;
! # endif
! 
! # if GNULIB_defined_EDQUOT
!       case EDQUOT:
!         msg = "Disk quota exceeded";
!         break;
! # endif
! 
! # if GNULIB_defined_ECANCELED
!       case ECANCELED:
!         msg = "Operation canceled";
!         break;
! # endif
!       }
! 
!     if (msg)
        {
!         size_t len = strlen (msg);
  
!         if (len < buflen)
!           {
!             memcpy (buf, msg, len + 1);
!             return 0;
            }
+         else
+           return ERANGE;
        }
    }
! #endif
  
!   {
!     int ret;
! 
! #if USE_SYSTEM_STRERROR_R
! 
!     if (buflen > INT_MAX)
!       buflen = INT_MAX;
! 
! # ifdef __hpux
!     /* On HP-UX 11.31, strerror_r always fails when buflen < 80.  */
      {
!       char stackbuf[80];
! 
!       if (buflen < sizeof (stackbuf))
          {
!           ret = strerror_r (errnum, stackbuf, sizeof (stackbuf));
!           if (ret == 0)
!             {
!               size_t len = strlen (stackbuf);
! 
!               if (len < buflen)
!                 memcpy (buf, stackbuf, len + 1);
!               else
!                 ret = ERANGE;
!             }
          }
        else
!         ret = strerror_r (errnum, buf, buflen);
      }
+ # elif defined __CYGWIN__
+     /* Cygwin only provides the glibc interface, is thread-safe, and
+        always succeeds (although it may truncate). */
+     strerror_r (errnum, buf, buflen);
+     ret = 0;
+ # else
+     ret = strerror_r (errnum, buf, buflen);
  # endif
  
! # ifdef _AIX
!     /* On AIX 6.1, strerror_r returns -1 and sets errno to EINVAL
!        if buflen <= 1.  */
!     if (ret < 0 && errno == EINVAL && buflen <= 1)
!       {
!         /* Retry with a larger buffer.  */
!         char largerbuf[10];
!         ret = strerror_r (errnum, largerbuf, sizeof (largerbuf));
!         if (ret < 0 && errno == EINVAL)
!           {
!             /* errnum was out of range.  */
!             ret = EINVAL;
!           }
!         else
!           {
!             /* buf was too small.  */
!             ret = ERANGE;
!           }
!       }
! # endif
  
!     /* Some old implementations may return (-1, EINVAL) instead of EINVAL.  */
!     if (ret < 0)
!       ret = errno;
  
! #elif USE_XPG_STRERROR_R
  
!     {
!       extern int __xpg_strerror_r (int errnum, char *buf, size_t buflen);
  
!       ret = __xpg_strerror_r (errnum, buf, buflen);
!       if (ret < 0)
!         ret = errno;
!     }
  
! #else /* USE_SYSTEM_STRERROR */
  
!     gl_lock_lock (strerror_lock);
  
!     {
!       char *errmsg = strerror (errnum);
  
!       /* For invalid error numbers, strerror() on
!            - IRIX 6.5 returns NULL,
!            - HP-UX 11 returns an empty string.  */
!       if (errmsg == NULL || *errmsg == '\0')
!         ret = EINVAL;
!       else
!         {
!           size_t len = strlen (errmsg);
  
!           if (len < buflen)
!             {
!               memcpy (buf, errmsg, len + 1);
!               ret = 0;
!             }
!           else
!             ret = ERANGE;
!         }
!     }
  
      gl_lock_unlock (strerror_lock);
  
+ #endif
+ 
      return ret;
    }
  }
*** modules/strerror.orig       Thu May 19 05:17:36 2011
--- modules/strerror    Thu May 19 04:13:54 2011
***************
*** 7,14 ****
  
  Depends-on:
  string
! errno           [test $REPLACE_STRERROR = 1]
! intprops        [test $REPLACE_STRERROR = 1]
  
  configure.ac:
  gl_FUNC_STRERROR
--- 7,16 ----
  
  Depends-on:
  string
! errno            [test $REPLACE_STRERROR = 1]
! intprops         [test $REPLACE_STRERROR = 1]
! verify           [test $REPLACE_STRERROR = 1]
! strerror_r-posix [test $REPLACE_STRERROR = 1]
  
  configure.ac:
  gl_FUNC_STRERROR

-- 
In memoriam Eli Cohen <http://en.wikipedia.org/wiki/Eli_Cohen>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]