]> git.ipfire.org Git - thirdparty/mtr.git/commitdiff
reliability: check writing to stdout and stderr was successful
authorSami Kerola <kerolasa@iki.fi>
Mon, 29 Aug 2016 18:17:32 +0000 (19:17 +0100)
committerSami Kerola <kerolasa@iki.fi>
Mon, 29 Aug 2016 18:22:50 +0000 (19:22 +0100)
This is expected behaviour.

$ mtr --help > /dev/full; echo $?
./mtr: write error: No space left on device
1

Earlier write errors returned successful zero.

Reference: https://www.irill.org/events/ghm-gnu-hackers-meeting/videos/jim-meyering-goodbye-world-the-perils-of-relying-on-output-streams-in-c

configure.ac
mtr.c
utils.c
utils.h

index d2e88bc80217f68b257b026b4fe5a07677c2a2cf..0926bbc17721662f5ccfc0413658394eb194dd9a 100644 (file)
@@ -46,6 +46,7 @@ AC_CHECK_HEADERS([ \
   ncurses/curses.h \
   socket.h \
   sys/socket.h \
+  stdio_ext.h \
   sys/types.h \
   sys/xti.h \
   values.h \
@@ -53,6 +54,7 @@ AC_CHECK_HEADERS([ \
 
 # Check functions.
 AC_CHECK_FUNCS([ \
+  __fpending \
   fcntl \
 ])
 
diff --git a/mtr.c b/mtr.c
index 14502e386bb8a78e7540f4d9902d0f6cc265f4d5..e28b0f27bbe29f7bf5b04dfa1f07013b238c37fa 100644 (file)
--- a/mtr.c
+++ b/mtr.c
@@ -655,6 +655,9 @@ extern int main(int argc, char **argv)
     error(EXIT_FAILURE, errno, "Unable to drop permissions");
   }
 
+  /* This will check if stdout/stderr writing is successful */
+  atexit(close_stdout);
+
   /* reset the random seed */
   srand (getpid());
 
diff --git a/utils.c b/utils.c
index f6c432681cd4a593bbf64c84b7b55f2b781f24e5..0a98e6c598becfa89752a15f4e33fc0d62604018 100644 (file)
--- a/utils.c
+++ b/utils.c
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "config.h"
+
 #include <ctype.h>
 #include <errno.h>
 #include <limits.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #ifdef HAVE_ERROR_H
 # include <error.h>
 # include "portability/error.h"
 #endif
 
+#ifdef HAVE_STDIO_EXT_H
+# include <stdio_ext.h>
+#endif
+
 #include "utils.h"
 
 extern char *trim(char *s)
@@ -109,3 +117,33 @@ extern char *xstrdup(const char *str)
     error(EXIT_FAILURE, errno, "cannot duplicate string: %s", str);
   return ret;
 }
+
+#ifndef HAVE___FPENDING
+static inline int __fpending(FILE *stream __attribute__((__unused__)))
+{
+  return 0;
+}
+#endif
+static inline int close_stream(FILE *stream)
+{
+  const int some_pending = (__fpending(stream) != 0);
+  const int prev_fail = (ferror(stream) != 0);
+  const int fclose_fail = (fclose(stream) != 0);
+
+  if (prev_fail || (fclose_fail && (some_pending || errno != EBADF))) {
+    if (!fclose_fail && !(errno == EPIPE))
+      errno = 0;
+    return EOF;
+  }
+  return 0;
+}
+/* Meant to be used atexit(close_stdout); */
+extern void close_stdout(void)
+{
+  if (close_stream(stdout) != 0 && !(errno == EPIPE)) {
+    error(0, errno, "write error");
+    _exit(EXIT_FAILURE);
+  }
+  if (close_stream(stderr) != 0)
+    _exit(EXIT_FAILURE);
+}
diff --git a/utils.h b/utils.h
index 5f9609d02827795a6235248e2a3953315da1a8a3..437bca0b7db64663e4950ea956d06132d78394e6 100644 (file)
--- a/utils.h
+++ b/utils.h
@@ -35,3 +35,5 @@ static inline void xstrncpy(char *dest, const char *src, size_t n)
 
 extern void *xmalloc(const size_t size);
 extern char *xstrdup(const char *str);
+
+extern void close_stdout(void);