diff options
-rw-r--r-- | libc/stdio/Makefile | 2 | ||||
-rw-r--r-- | libc/stdio/old_vfprintf.c | 2 | ||||
-rw-r--r-- | libc/stdio/printf.c | 2 | ||||
-rw-r--r-- | libc/stdio/stdio.c | 53 | ||||
-rw-r--r-- | libc/sysdeps/linux/common/bits/uClibc_stdio.h | 8 |
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. */ |