about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2007-12-03 22:46:10 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2007-12-03 22:46:10 +0000
commit61320c44c1c09a1e9b455771437c94174108739c (patch)
treed7cdbc3b40eec96ded0ac715ef61830c49211770 /Src
parent9794b454777867201e242c425b4fd9629c669fee (diff)
downloadzsh-61320c44c1c09a1e9b455771437c94174108739c.tar.gz
zsh-61320c44c1c09a1e9b455771437c94174108739c.tar.xz
zsh-61320c44c1c09a1e9b455771437c94174108739c.zip
24148: attempt to use strerror_r() to make errors in signal handle safer
Diffstat (limited to 'Src')
-rw-r--r--Src/utils.c37
1 files changed, 35 insertions, 2 deletions
diff --git a/Src/utils.c b/Src/utils.c
index f9e658c0f..7c22a277f 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -255,6 +255,12 @@ zerrmsg(FILE *file, const char *fmt, va_list ap)
 {
     const char *str;
     int num;
+#ifdef HAVE_STRERROR_R
+#define ERRBUFSIZE (80)
+    int olderrno;
+    char errbuf[ERRBUFSIZE];
+#endif
+    char *errmsg;
 
     if ((unset(SHINSTDIN) || locallevel) && lineno)
 	fprintf(file, "%ld: ", (long)lineno);
@@ -304,12 +310,39 @@ zerrmsg(FILE *file, const char *fmt, va_list ap)
 		    errflag = 1;
 		    return;
 		}
+#ifdef HAVE_STRERROR_R
+		/*
+		 * There are two incompatible strerror_r()s floating round.
+		 * The GNU extension refuses to copy the message into the
+		 * buffer if it can return a constant string.  To suppress it
+		 * we need to define _XOPEN_SOURCE to 600.  I don't dare do
+		 * this because we're already depending on _GNU_SOURCE.  So
+		 * try to handle both by looking for errno being set (for the
+		 * standard version failing) or errbuf being left untouched
+		 * (for the GNU version).  One presumes that if strerror_r()
+		 * didn't copy anything to errbuf, then it's safe to
+		 * call strerror() to get the string.
+		 *
+		 * This is a mess, but it's about a decade and half
+		 * too late to shirk from messes in the source.
+		 */
+		olderrno = errno;
+		errno = 0;
+		errbuf[0] = '\0';
+		strerror_r(num, errbuf, ERRBUFSIZE);
+		if (errno || errbuf[0] == '\0')
+		    errmsg = strerror(num);
+		else
+		    errmsg = errbuf;
+		errno = olderrno;
+#else
+		errmsg = strerror(num);
+#endif
 		/* If the message is not about I/O problems, it looks better *
 		 * if we uncapitalize the first letter of the message        */
 		if (num == EIO)
-		    fputs(strerror(num), file);
+		    fputs(errmsg, file);
 		else {
-		    char *errmsg = strerror(num);
 		    fputc(tulower(errmsg[0]), file);
 		    fputs(errmsg + 1, file);
 		}