diff --git a/include/string.h b/include/string.h index 66b14f4fac23..5f2a6e128cd0 100644 --- a/include/string.h +++ b/include/string.h @@ -62,6 +62,7 @@ int strcoll __P((const char *, const char *)); char *strcpy __P((char *, const char *)); size_t strcspn __P((const char *, const char *)); char *strerror __P((int)); +int strerror_r __P((int, char *, size_t)); size_t strlen __P((const char *)); char *strncat __P((char *, const char *, size_t)); int strncmp __P((const char *, const char *, size_t)); diff --git a/lib/libc/string/strerror.3 b/lib/libc/string/strerror.3 index 447e208c39c0..ed63b25f5be7 100644 --- a/lib/libc/string/strerror.3 +++ b/lib/libc/string/strerror.3 @@ -36,12 +36,13 @@ .\" @(#)strerror.3 8.1 (Berkeley) 6/9/93 .\" $FreeBSD$ .\" -.Dd June 9, 1993 +.Dd Nov 26, 2001 .Dt STRERROR 3 .Os .Sh NAME .Nm perror , .Nm strerror , +.Nm strerror_r , .Nm sys_errlist , .Nm sys_nerr .Nd system error messages @@ -56,9 +57,12 @@ .In string.h .Ft char * .Fn strerror "int errnum" +.Ft int +.Fn strerror_r "int errnum" "char * strerrbuf" "size_t buflen" .Sh DESCRIPTION The -.Fn strerror +.Fn strerror , +.Fn strerror_r and .Fn perror functions look up the error message string corresponding to an @@ -68,11 +72,27 @@ The .Fn strerror function accepts an error number argument .Fa errnum -and -returns a pointer to the corresponding +and returns a pointer to the corresponding message string. .Pp The +.Fn strerror_r +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. +.Pp +The .Fn perror function finds the error message corresponding to the current value of the global variable @@ -107,6 +127,8 @@ contains a count of the messages in .Va sys_errlist . The use of these variables is deprecated; .Fn strerror +or +.Fn strerror_r should be used instead. .Sh SEE ALSO .Xr intro 2 , @@ -118,6 +140,13 @@ and .Fn perror functions first appeared in .Bx 4.4 . +The +.Fn strerror_r +function was implemented in +.Fx 4.4 +by +.An Wes Peters +.Aq wes@freebsd.org . .Sh BUGS For unknown error numbers, the .Fn strerror diff --git a/lib/libc/string/strerror.c b/lib/libc/string/strerror.c index 626e5d7287a7..8628d8d9c436 100644 --- a/lib/libc/string/strerror.c +++ b/lib/libc/string/strerror.c @@ -39,35 +39,90 @@ __FBSDID("$FreeBSD$"); #include #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; + + uerr = errnum; /* convert to unsigned */ + if (uerr < sys_nerr) { + len = strlcpy(strerrbuf, (char *)sys_errlist[uerr], 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; +} + + +/* + * 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; { -#define UPREFIX "Unknown error: " - static char ebuf[40] = UPREFIX; /* 64-bit number + slop */ - register unsigned int errnum; - register char *p, *t; - char tmp[40]; + unsigned int uerr; + static char ebuf[ERR_LEN]; - errnum = num; /* convert to unsigned */ - if (errnum < sys_nerr) - return ((char *)sys_errlist[errnum]); + uerr = num; /* convert to unsigned */ + if (uerr < sys_nerr) + return (char *)sys_errlist[uerr]; - /* Do this by hand, so we don't link to stdio(3). */ - t = tmp; - if (num < 0) - errnum = -errnum; - do { - *t++ = "0123456789"[errnum % 10]; - } while (errnum /= 10); - if (num < 0) - *t++ = '-'; - for (p = ebuf + sizeof(UPREFIX) - 1;;) { - *p++ = *--t; - if (t <= tmp) - break; - } - *p = '\0'; - return (ebuf); + /* strerror can't fail so handle truncation semi-elegantly */ + if (strerror_r(num, ebuf, (size_t) ERR_LEN) != 0) + ebuf[ERR_LEN - 1] = '\0'; + + return ebuf; } + + +#ifdef STANDALONE_TEST +main() +{ + char mybuf[64]; + int ret; + + printf("strerror(47) yeilds: %s\n", strerror(47)); + 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); + printf("strerror_r on short buffer returns %d (%s)\n", ret, mybuf); +} +#endif