summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2002-06-18 08:41:28 +0000
committerManuel Novoa III <mjn3@codepoet.org>2002-06-18 08:41:28 +0000
commit5b0c2c6d870cc9f9f2eae32f4d71abc6f9348e20 (patch)
tree60d5b9ee265a8d359484c6dbb3d25da6f209718e /libc
parent6f1e6c22ab67fbb7b5642e142ac3c1f4d6968263 (diff)
Fix perror() and printf("%m") to not call strerror(), as required by the
standards. Temporarily added a utility function to wrap Erik's strerror_r so that "Unknown error xxx" strings can be generated for errno's which cause strerror_r to fail. That utility function will eventually be merged in with the strerror/strerror_r functions when I change over to optionallly mmap'ing the system error strings to provide for lower mem comsumption on non-MMU platforms, as well as locale-specific system error messages.
Diffstat (limited to 'libc')
-rw-r--r--libc/stdio/Makefile2
-rw-r--r--libc/stdio/old_vfprintf.c2
-rw-r--r--libc/stdio/printf.c2
-rw-r--r--libc/stdio/stdio.c53
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_stdio.h8
5 files changed, 59 insertions, 8 deletions
diff --git a/libc/stdio/Makefile b/libc/stdio/Makefile
index 14fdb7029..0145b9475 100644
--- a/libc/stdio/Makefile
+++ b/libc/stdio/Makefile
@@ -57,7 +57,7 @@ MOBJ = fclose.o fflush.o fopen.o freopen.o perror.o remove.o \
__fsetlocking.o flockfile.o ftrylockfile.o funlockfile.o \
_stdio_fopen.o _stdio_fread.o _stdio_fwrite.o _stdio_adjpos.o \
_stdio_lseek.o _stdio_init.o \
- _stdio_fsfopen.o _stdio_fdout.o _uintmaxtostr.o
+ _stdio_fsfopen.o _stdio_fdout.o _uintmaxtostr.o _stdio_strerror_r.o
# ifeq ($(DOLFS),true)
# MOBJ += fopen64.o freopen64.o ftello64.o fseeko64.o fsetpos64.o fgetpos64.o
diff --git a/libc/stdio/old_vfprintf.c b/libc/stdio/old_vfprintf.c
index 2158d9741..036c97c94 100644
--- a/libc/stdio/old_vfprintf.c
+++ b/libc/stdio/old_vfprintf.c
@@ -270,7 +270,7 @@ int vfprintf(FILE * __restrict op, register const char * __restrict fmt,
if (*fmt == 'm') {
flag[FLAG_PLUS] = '\0';
flag[FLAG_0_PAD] = ' ';
- p = strerror(errno);
+ p = _stdio_strerror_r(errno, tmp, sizeof(tmp));
goto print;
}
#endif
diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c
index 92b5b5956..2fac4c93f 100644
--- a/libc/stdio/printf.c
+++ b/libc/stdio/printf.c
@@ -1207,7 +1207,7 @@ int _do_one_spec(FILE * __restrict stream, register ppfs_t *ppfs, int *count)
}
#ifdef __STDIO_PRINTF_M_SUPPORT
} else if (ppfs->conv_num == CONV_m) {
- s = strerror(errno);
+ s = _stdio_strerror_r(errno, buf, sizeof(buf));
goto SET_STRING_LEN;
#endif
} else {
diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c
index 1462874f0..c84731675 100644
--- a/libc/stdio/stdio.c
+++ b/libc/stdio/stdio.c
@@ -3105,14 +3105,22 @@ void perror(register const char *s)
#ifdef __STDIO_PRINTF_M_SPEC
fprintf(_stderr, "%s%s%m\n", s, sep); /* Use the gnu %m feature. */
#else
- /* TODO: use strerror_r instead? */
- fprintf(_stderr, "%s%s%s\n", s, sep, strerror(errno));
+ {
+ char buf[64];
+ fprintf(_stderr, "%s%s%s\n", s, sep,
+ _stdio_strerror_r(errno, buf, sizeof(buf)));
+ }
#endif
#else
/* Note: Assumes stderr not closed or buffered. */
- __STDIO_THREADLOCK(stderr);
- _stdio_fdout(STDERR_FILENO, s, sep, strerror(errno));
- __STDIO_THREADUNLOCK(stderr);
+ {
+ char buf[64];
+
+ __STDIO_THREADLOCK(stderr);
+ _stdio_fdout(STDERR_FILENO, s, sep,
+ _stdio_strerror_r(errno, buf, sizeof(buf)));
+ __STDIO_THREADUNLOCK(stderr);
+ }
#endif
}
@@ -3209,3 +3217,38 @@ char *_uintmaxtostr(char * __restrict bufend, uintmax_t uval,
#undef INTERNAL_DIV_MOD
#endif
+/**********************************************************************/
+#ifdef L__stdio_strerror_r
+
+/* This is an internal routine, and assumes buf and buflen are set
+ * appropriately.
+ *
+ * WARNING!!! While it is similar to the glibc strerror_r function,
+ * it is not the same. It is expected that "unknown" error strings
+ * will fit in the buffer passed. Also, the return value may not
+ * be == buf, as unknown strings are "right-justified" in the buf
+ * due to the way _int10stostr works. */
+
+static const char unknown[] = "Unknown error";
+
+char *_stdio_strerror_r(int err, char *buf, size_t buflen)
+{
+ int errsave;
+
+ assert(buflen >= __UIM_BUFLEN_INT + sizeof(unknown));
+
+ errsave = errno; /* Backup the errno. */
+
+ if (strerror_r(err, buf, buflen)) { /* Failed! */
+ __set_errno(errsave); /* Restore old errno. */
+
+ buf = _int10tostr(buf+buflen-1, err) - sizeof(unknown);
+ strcpy(buf, unknown);
+ buf[sizeof(unknown)-1] = ' '; /* Overwrite the nul. */
+ }
+
+ return buf;
+}
+
+#endif
+/**********************************************************************/
diff --git a/libc/sysdeps/linux/common/bits/uClibc_stdio.h b/libc/sysdeps/linux/common/bits/uClibc_stdio.h
index 83ca2fb04..1a559bd9c 100644
--- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h
+++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h
@@ -438,6 +438,14 @@ typedef enum {
__UIM_UPPER = 'A' - 10,
} __UIM_CASE;
+/* WARNING!!! While similar to the glibc strerror_r function, the
+ * following function is not the same. It expects "unknown" error
+ * strings will fit in the buffer passed. Also, the return value
+ * may not be == buf, as unknown strings are "right-justified" in
+ * the buf due to the way _int10stostr works. */
+
+extern char *_stdio_strerror_r(int err, char *buf, size_t buflen);
+
/* Write a NULL-terminated list of "char *" args to file descriptor fd.
* For an example of usage, see __assert.c.
*/