diff --git a/lib/strerror.c b/lib/strerror.c index f1d22e1437..526187bb87 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -24,10 +24,11 @@ #include "setup.h" #ifdef HAVE_STRERROR_R -#if !defined(HAVE_POSIX_STRERROR_R) && !defined(HAVE_GLIBC_STRERROR_R) -#error "you MUST have either POSIX or glibc strerror_r if strerror_r is found" -#endif /* !POSIX && !glibc */ -#endif /* HAVE_STRERROR_R */ +# if (!defined(HAVE_POSIX_STRERROR_R) && !defined(HAVE_GLIBC_STRERROR_R)) || \ + (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)) +# error "strerror_r MUST be either POSIX-style or glibc-style" +# endif +#endif #include #include @@ -43,14 +44,6 @@ #define _MPRINTF_REPLACE /* use our functions only */ #include -#if defined(HAVE_STRERROR_R) && defined(HAVE_NO_STRERROR_R_DECL) -#ifdef HAVE_POSIX_STRERROR_R -/* seen on AIX 5100-02 gcc 2.9 */ -extern int strerror_r(int errnum, char *strerrbuf, size_t buflen); -#else -extern char *strerror_r(int errnum, char *buf, size_t buflen); -#endif -#endif const char * curl_easy_strerror(CURLcode error) @@ -590,6 +583,7 @@ const char *Curl_strerror(struct connectdata *conn, int err) { char *buf, *p; size_t max; + int old_errno = ERRNO; DEBUGASSERT(conn); DEBUGASSERT(err >= 0); @@ -601,17 +595,15 @@ const char *Curl_strerror(struct connectdata *conn, int err) #ifdef USE_WINSOCK #ifdef _WIN32_WCE - buf[0]=0; { wchar_t wbuf[256]; + wbuf[0] = L'\0'; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL); wcstombs(buf,wbuf,max); } - #else - /* 'sys_nerr' is the maximum errno number, it is not widely portable */ if(err >= 0 && err < sys_nerr) strncpy(buf, strerror(err), max); @@ -622,34 +614,43 @@ const char *Curl_strerror(struct connectdata *conn, int err) snprintf(buf, max, "Unknown error %d (%#x)", err, err); } #endif + #else /* not USE_WINSOCK coming up */ - /* These should be atomic and hopefully thread-safe */ -#ifdef HAVE_STRERROR_R - /* There are two different APIs for strerror_r(). The POSIX and the GLIBC - versions. */ -#ifdef HAVE_POSIX_STRERROR_R - strerror_r(err, buf, max); - /* this may set errno to ERANGE if insufficient storage was supplied via - 'strerrbuf' and 'buflen' to contain the generated message string, or - EINVAL if the value of 'errnum' is not a valid error number.*/ -#else +#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R) + /* + * The POSIX-style strerror_r() may set errno to ERANGE if insufficient + * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated + * message string, or EINVAL if 'errnum' is not a valid error number. + */ + if(0 != strerror_r(err, buf, max)) { + if('\0' == buf[0]) + snprintf(buf, max, "Unknown error %d", err); + } +#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R) + /* + * The glibc-style strerror_r() only *might* use the buffer we pass to + * the function, but it always returns the error message as a pointer, + * so we must copy that string unconditionally (if non-NULL). + */ { - /* HAVE_GLIBC_STRERROR_R */ char buffer[256]; char *msg = strerror_r(err, buffer, sizeof(buffer)); - /* this version of strerror_r() only *might* use the buffer we pass to - the function, but it always returns the error message as a pointer, - so we must copy that string unconditionally (if non-NULL) */ if(msg) strncpy(buf, msg, max); else snprintf(buf, max, "Unknown error %d", err); } -#endif /* end of HAVE_GLIBC_STRERROR_R */ -#else /* HAVE_STRERROR_R */ - strncpy(buf, strerror(err), max); -#endif /* end of HAVE_STRERROR_R */ +#else + { + char *msg = strerror(err); + if(msg) + strncpy(buf, msg, max); + else + snprintf(buf, max, "Unknown error %d", err); + } +#endif + #endif /* end of ! USE_WINSOCK */ buf[max] = '\0'; /* make sure the string is zero terminated */ @@ -659,6 +660,10 @@ const char *Curl_strerror(struct connectdata *conn, int err) *p = '\0'; if((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1) *p = '\0'; + + if(old_errno != ERRNO) + SET_ERRNO(old_errno); + return buf; } @@ -680,6 +685,7 @@ const char *Curl_idn_strerror (struct connectdata *conn, int err) buf = conn->syserr_buf; max = sizeof(conn->syserr_buf)-1; + *buf = '\0'; #ifndef CURL_DISABLE_VERBOSE_STRINGS switch ((Idna_rc)err) {