diff --git a/lib/libc/string/strerror.3 b/lib/libc/string/strerror.3 index ed63b25f5be..037b138cad9 100644 --- a/lib/libc/string/strerror.3 +++ b/lib/libc/string/strerror.3 @@ -81,16 +81,7 @@ function renders the same result into .Fa strerrbuf for a maximum of .Fa buflen -characters and returns 0 upon success. If insufficient -storage is provided in -.Fa strerrbuf -(as specified in -.Fa buflen ) -to contain the error string, -.Er ERANGE -is returned and the string in -.Fa strerrbuf -may not be null-terminated. +characters and returns 0 upon success. .Pp The .Fn perror @@ -114,9 +105,25 @@ otherwise, only the error message string is printed. If .Fa errnum is not a recognized error number, -the error message string will contain +.Fn strerror +returns an error message string containing .Dq Li "Unknown error:\ " -followed by the error number in decimal. +followed by the error number in decimal, while +.Fn strerror_r +returns +.Er EINVAL . +.Pp +If insufficient storage is provided in +.Fa strerrbuf +(as specified in +.Fa buflen ) +to contain the error string, +.Fn strerror_r +returns +.Er ERANGE +and the contents of +.Fa strerrbuf +are indeterminate. .Pp The message strings can be accessed directly using the external array diff --git a/lib/libc/string/strerror.c b/lib/libc/string/strerror.c index 8628d8d9c43..e0f4cd3f778 100644 --- a/lib/libc/string/strerror.c +++ b/lib/libc/string/strerror.c @@ -41,88 +41,87 @@ __FBSDID("$FreeBSD$"); #include #include - int strerror_r(int errnum, char *strerrbuf, size_t buflen) { -#define UPREFIX "Unknown error: " - unsigned int uerr; - char *p, *t; - char tmp[40]; /* 64-bit number + slop */ - int len; + int len; - uerr = errnum; /* convert to unsigned */ - if (uerr < sys_nerr) { - len = strlcpy(strerrbuf, (char *)sys_errlist[uerr], buflen); - return (len <= buflen) ? 0 : ERANGE; + if ((errnum > 0) && (errnum < sys_nerr)) { + len = strlcpy(strerrbuf, (char *)sys_errlist[errnum], buflen); + return ((len <= buflen) ? 0 : ERANGE); } - - /* Print unknown errno by hand so we don't link to stdio(3). */ - t = tmp; - if (errnum < 0) - uerr = -uerr; - do { - *t++ = "0123456789"[uerr % 10]; - } while (uerr /= 10); - - if (errnum < 0) - *t++ = '-'; - - strlcpy(strerrbuf, UPREFIX, buflen); - for (p = strerrbuf + sizeof(UPREFIX) - 1; p < strerrbuf + buflen; ) { - *p++ = *--t; - if (t <= tmp) - break; - } - - if (p < strerrbuf + buflen) { - *p = '\0'; - return 0; - } - - return ERANGE; + return (EINVAL); } - -/* - * NOTE: the following length should be enough to hold the longest defined - * error message in sys_errlist, defined in ../gen/errlst.c. This is a WAG - * that is better than the previous value. - */ -#define ERR_LEN 64 - char * strerror(num) - int num; + int num; { - unsigned int uerr; - static char ebuf[ERR_LEN]; + char *p, *t; + unsigned int uerr; + static char const unknown_prefix[] = "Unknown error: "; - uerr = num; /* convert to unsigned */ - if (uerr < sys_nerr) - return (char *)sys_errlist[uerr]; + /* + * Define a buffer size big enough to describe a 64-bit + * number in ASCII decimal (19), with optional leading sign + * (+1) and trailing NUL (+1). + */ +# define NUMLEN 21 +# define EBUFLEN (sizeof unknown_prefix + NUMLEN) + char tmp[NUMLEN]; /* temporary number */ + static char ebuf[EBUFLEN]; /* error message */ - /* strerror can't fail so handle truncation semi-elegantly */ - if (strerror_r(num, ebuf, (size_t) ERR_LEN) != 0) - ebuf[ERR_LEN - 1] = '\0'; + if ((num > 0) && (num < sys_nerr)) + return ((char *)sys_errlist[num]); - return ebuf; + /* + * Print unknown errno by hand so we don't link to stdio(3). + * This collects the ASCII digits in reverse order. + */ + uerr = (num > 0) ? num : -num; + t = tmp; + do { + *t++ = "0123456789"[uerr % 10]; + } while (uerr /= 10); + if (num < 0) + *t++ = '-'; + + /* + * Copy the "unknown" message and the number into the caller + * supplied buffer, inverting the number string. + */ + strcpy(ebuf, unknown_prefix); + for (p = ebuf + sizeof unknown_prefix - 1; t >= tmp; ) + *p++ = *--t; + *p = '\0'; + return (ebuf); } - #ifdef STANDALONE_TEST + +#include + main() { - char mybuf[64]; - int ret; + char mybuf[64]; + int ret; printf("strerror(47) yeilds: %s\n", strerror(47)); + printf("strerror(437) yeilds: %s\n", strerror(437)); + printf("strerror(LONG_MAX) yeilds: %s\n", strerror(LONG_MAX)); + printf("strerror(LONG_MIN) yeilds: %s\n", strerror(LONG_MIN)); + printf("strerror(ULONG_MAX) yeilds: %s\n", strerror(ULONG_MAX)); + + memset(mybuf, '*', 63); mybuf[63] = '\0'; strerror_r(11, mybuf, 64); printf("strerror_r(11) yeilds: %s\n", mybuf); - strerror_r(1234, mybuf, 64); - printf("strerror_r(1234) yeilds: %s\n", mybuf); - memset(mybuf, '*', 63); - ret = strerror_r(4321, mybuf, 16); + + memset(mybuf, '*', 63); mybuf[63] = '\0'; + ret = strerror_r(1234, mybuf, 64); + printf("strerror_r(1234) returns %d (%s)\n", ret, mybuf); + + memset(mybuf, '*', 63); mybuf[63] = '\0'; + ret = strerror_r(1, mybuf, 10); printf("strerror_r on short buffer returns %d (%s)\n", ret, mybuf); } #endif