Browse Source

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.

Manuel Novoa III 22 years ago
parent
commit
5b0c2c6d87

+ 1 - 1
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

+ 1 - 1
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

+ 1 - 1
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 {

+ 48 - 5
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
+/**********************************************************************/

+ 8 - 0
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.
  */