/* * Our thread-safe and smart strerror() replacement. * * The 'err' argument passed in to this function MUST be a true errno number * as reported on this system. We do no range checking on the number before * we pass it to the "number-to-message" convertion function and there might * be systems that don't do proper range checking in there themselves. * * We don't do range checking (on systems other than Windows) since there is * no good reliable and portable way to do it. */ const char *Curl_strerror( struct connectdata *conn, int err ) { char *buf, *p; size_t max; curlassert( conn ); curlassert( err >= 0 ); buf = conn->syserr_buf; max = sizeof( conn->syserr_buf ) - 1; *buf = '\0'; #if defined( WIN32 ) && !defined( __CYGWIN__ ) /* 'sys_nerr' is the maximum errno number, it is not widely portable */ if ( err >= 0 && err < sys_nerr ) { strncpy( buf, strerror( err ), max ); } else { if ( !get_winsock_error( err, buf, max ) && !FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, LANG_NEUTRAL, buf, max, NULL ) ) { snprintf( buf, max, "Unknown error %d (%#x)", err, err ); } } #else /* not native Windows 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 { /* 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 */ strncpy( buf, msg, max ); } #endif /* end of HAVE_GLIBC_STRERROR_R */ #else /* HAVE_STRERROR_R */ strncpy( buf, strerror( err ), max ); #endif /* end of HAVE_STRERROR_R */ #endif /* end of ! Windows */ buf[max] = '\0'; /* make sure the string is zero terminated */ /* strip trailing '\r\n' or '\n'. */ if ( ( p = strrchr( buf,'\n' ) ) != NULL && ( p - buf ) >= 2 ) { *p = '\0'; } if ( ( p = strrchr( buf,'\r' ) ) != NULL && ( p - buf ) >= 1 ) { *p = '\0'; } return buf; }
const char * windows_strerror (int err) { const char *p; if (err >= 0 && err < sys_nerr) return strerror (err); else if ((p = get_winsock_error (err)) != NULL) return p; else { static char buf[32]; snprintf (buf, sizeof (buf), "Unknown error %d (%#x)", err, err); return buf; } }
char *ec_win_strerror (int err) { static char buf[512]; DWORD lang = MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT); DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK; char *p; if (err >= 0 && err < sys_nerr) { strncpy (buf, strerror(err), sizeof(buf)-1); buf [sizeof(buf)-1] = '\0'; } else { if (!get_winsock_error (err, buf, sizeof(buf)) && !FormatMessage (flags, NULL, err, lang, buf, sizeof(buf)-1, NULL)) snprintf (buf, 512, "Unknown error %d (%#x)", err, err); } /* strip trailing '\r\n' or '\n'. */ p = strrchr (buf, '\n'); if (p && (p - buf) >= 2) *p = '\0'; p = strrchr (buf, '\r'); if (p && (p - buf) >= 1) *p = '\0'; return (buf); }
/* * Our thread-safe and smart strerror() replacement. * * The 'err' argument passed in to this function MUST be a true errno number * as reported on this system. We do no range checking on the number before * we pass it to the "number-to-message" conversion function and there might * be systems that don't do proper range checking in there themselves. * * We don't do range checking (on systems other than Windows) since there is * no good reliable and portable way to do it. */ const char *Curl_strerror(struct connectdata *conn, int err) { char *buf, *p; size_t max; int old_errno = ERRNO; DEBUGASSERT(conn); DEBUGASSERT(err >= 0); buf = conn->syserr_buf; max = sizeof(conn->syserr_buf)-1; *buf = '\0'; #ifdef USE_WINSOCK #ifdef _WIN32_WCE { 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); else { if(!get_winsock_error(err, buf, max) && !FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, LANG_NEUTRAL, buf, (DWORD)max, NULL)) snprintf(buf, max, "Unknown error %d (%#x)", err, err); } #endif #else /* not USE_WINSOCK coming up */ #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). */ { char buffer[256]; char *msg = strerror_r(err, buffer, sizeof(buffer)); if(msg) strncpy(buf, msg, max); else snprintf(buf, max, "Unknown error %d", err); } #elif defined(HAVE_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R) /* * The vxworks-style strerror_r() does use the buffer we pass to the function. * The buffer size should be at least MAXERRSTR_SIZE (150) defined in rtsold.h */ { char buffer[256]; if(OK == strerror_r(err, buffer)) strncpy(buf, buffer, max); else snprintf(buf, max, "Unknown error %d", err); } #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 */ /* strip trailing '\r\n' or '\n'. */ if((p = strrchr(buf,'\n')) != NULL && (p - buf) >= 2) *p = '\0'; if((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1) *p = '\0'; if(old_errno != ERRNO) SET_ERRNO(old_errno); return buf; }