summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/string.h1
-rw-r--r--lib/libc/string/strerror.337
-rw-r--r--lib/libc/string/strerror.c93
3 files changed, 108 insertions, 23 deletions
diff --git a/include/string.h b/include/string.h
index 66b14f4..5f2a6e1 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 447e208..ed63b25 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 626e5d7..8628d8d 100644
--- a/lib/libc/string/strerror.c
+++ b/lib/libc/string/strerror.c
@@ -39,35 +39,90 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <string.h>
+#include <errno.h>
-char *
-strerror(num)
- int num;
+
+int
+strerror_r(int errnum, char *strerrbuf, size_t buflen)
{
#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;
+ char *p, *t;
+ char tmp[40]; /* 64-bit number + slop */
+ int len;
- errnum = num; /* convert to unsigned */
- if (errnum < sys_nerr)
- return ((char *)sys_errlist[errnum]);
+ uerr = errnum; /* convert to unsigned */
+ if (uerr < sys_nerr) {
+ len = strlcpy(strerrbuf, (char *)sys_errlist[uerr], buflen);
+ return (len <= buflen) ? 0 : ERANGE;
+ }
- /* Do this by hand, so we don't link to stdio(3). */
+ /* Print unknown errno by hand so we don't link to stdio(3). */
t = tmp;
- if (num < 0)
- errnum = -errnum;
+ if (errnum < 0)
+ uerr = -uerr;
do {
- *t++ = "0123456789"[errnum % 10];
- } while (errnum /= 10);
- if (num < 0)
+ *t++ = "0123456789"[uerr % 10];
+ } while (uerr /= 10);
+
+ if (errnum < 0)
*t++ = '-';
- for (p = ebuf + sizeof(UPREFIX) - 1;;) {
+
+ strlcpy(strerrbuf, UPREFIX, buflen);
+ for (p = strerrbuf + sizeof(UPREFIX) - 1; p < strerrbuf + buflen; ) {
*p++ = *--t;
if (t <= tmp)
break;
}
- *p = '\0';
- return (ebuf);
+
+ 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;
+{
+ unsigned int uerr;
+ static char ebuf[ERR_LEN];
+
+ uerr = num; /* convert to unsigned */
+ if (uerr < sys_nerr)
+ return (char *)sys_errlist[uerr];
+
+ /* 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
OpenPOWER on IntegriCloud