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 <br...@clisp.org> 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>