diff options
author | mike <mike@FreeBSD.org> | 2002-12-18 16:53:31 +0000 |
---|---|---|
committer | mike <mike@FreeBSD.org> | 2002-12-18 16:53:31 +0000 |
commit | 91ae3fa45da5b963b386ec2315195c8a46fca992 (patch) | |
tree | 16025c382d603596fbc3bf588b0fc5edf45a3c74 /lib/libc/string/strerror.c | |
parent | e32cc6fbb43a3952c915a86eefab4195c58aaaf5 (diff) | |
download | FreeBSD-src-91ae3fa45da5b963b386ec2315195c8a46fca992.zip FreeBSD-src-91ae3fa45da5b963b386ec2315195c8a46fca992.tar.gz |
Rearrange strerror() so that its itoa procedure can be used with
strerror_r(). Doing this allows us to ensure that strerror_r() always
fills the supplied buffer regardless of EINVAL or ERANGE errors.
strerror()'s semantics have changed slightly such that an argument of
0 is now considered invalid and errno is set to EINVAL.
Remove internal regression test for strerror() and strerror_r(). This
will be reincarnated in src/tools/regression/lib/libc/string.
In strerror(3), add a comment about strerror()'s bogus return type.
PR: 44356
Diffstat (limited to 'lib/libc/string/strerror.c')
-rw-r--r-- | lib/libc/string/strerror.c | 124 |
1 files changed, 39 insertions, 85 deletions
diff --git a/lib/libc/string/strerror.c b/lib/libc/string/strerror.c index 32e35aa..0d2e126 100644 --- a/lib/libc/string/strerror.c +++ b/lib/libc/string/strerror.c @@ -37,108 +37,62 @@ static char sccsid[] = "@(#)strerror.c 8.1 (Berkeley) 6/4/93"; #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include <errno.h> #include <stdio.h> #include <string.h> -#include <errno.h> -int -strerror_r(int errnum, char *strerrbuf, size_t buflen) -{ - int len; - - if ((errnum >= 0) && (errnum < sys_nerr)) { - len = strlcpy(strerrbuf, (char *)sys_errlist[errnum], buflen); - return ((len < buflen) ? 0 : ERANGE); - } - return (EINVAL); -} +#define UPREFIX "Unknown error: " +/* + * Define a buffer size big enough to describe a 64-bit signed integer + * converted to ASCII decimal (19 bytes), with an optional leading sign + * (1 byte), finally we get the prefix and a trailing NUL from UPREFIX. + */ +#define EBUFSIZE (20 + sizeof(UPREFIX)) -char * -strerror(num) - int num; +/* Don't link to stdio(3) to avoid bloat for statically linked binaries. */ +static void +errstr(int num, char *buf, size_t len) { - char *p, *t; - unsigned int uerr; - static char const unknown_prefix[] = "Unknown error: "; - - /* - * 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 */ - - if ((num >= 0) && (num < sys_nerr)) - return ((char *)sys_errlist[num]); + unsigned int uerr; + char *p, *t; + char tmp[EBUFSIZE]; - /* - * Set errno to EINVAL per P1003.1-200x Draft June 14, 2001. - */ - errno = EINVAL; - - /* - * 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; + if (strlcpy(buf, UPREFIX, len) >= len) + return; t = tmp; + uerr = (num >= 0) ? num : -num; 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; ) + for (p = buf + strlen(UPREFIX); t > tmp && p < buf + len - 1;) *p++ = *--t; *p = '\0'; - return (ebuf); } -#ifdef STANDALONE_TEST - -#include <limits.h> - -main() +int +strerror_r(int errnum, char *strerrbuf, size_t buflen) { - char mybuf[64]; - int ret; - - errno = 0; - - printf("strerror(0) yeilds: %s\n", strerror(0)); - printf("strerror(1) yeilds: %s\n", strerror(1)); - printf("strerror(47) yeilds: %s\n", strerror(47)); - printf("strerror(sys_nerr - 1) yeilds: %s\n", strerror(sys_nerr - 1)); - printf("errno = %d\n", errno); errno = 0; - - printf("strerror(sys_nerr) yeilds: %s\n", strerror(sys_nerr)); - printf("errno = %d\n", errno); errno = 0; - - printf("strerror(437) yeilds: %s\n", strerror(437)); - printf("errno = %d\n", errno); errno = 0; - - 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); + int retval; + + retval = 0; + if (errnum < 1 || errnum >= sys_nerr) { + errstr(errnum, strerrbuf, buflen); + retval = EINVAL; + } else if (strlcpy(strerrbuf, sys_errlist[errnum], buflen) >= buflen) + retval = ERANGE; + return (retval); +} - memset(mybuf, '*', 63); mybuf[63] = '\0'; - ret = strerror_r(1234, mybuf, 64); - printf("strerror_r(1234) returns %d (%s)\n", ret, mybuf); +char * +strerror(int num) +{ + static char ebuf[EBUFSIZE]; - memset(mybuf, '*', 63); mybuf[63] = '\0'; - ret = strerror_r(1, mybuf, 10); - printf("strerror_r on short buffer returns %d (%s)\n", ret, mybuf); + if (num > 0 && num < sys_nerr) + return ((char *)sys_errlist[num]); + errno = EINVAL; + errstr(num, ebuf, sizeof(ebuf)); + return (ebuf); } -#endif |