From c92585b10b29ce2c31c69cea52e69ef053c9679f Mon Sep 17 00:00:00 2001 From: Assaf Gordon Date: Sun, 17 Apr 2016 02:28:13 -0400 Subject: seq: detect and report I/O errors immediately Ensure I/O errors are detected (and terminate seq), preventing seq from infloop (or running for long time with a large range) upon write errors or ignored SIGPIPE. Examples: seq 1 inf > /dev/full (seq_fast) seq 1.1 0.1 inf >/dev/full (print_numbers) * src/seq.c (io_error): A new function to diagnose appropriate stdio errors and exit the program with failure status. (seq_fast, print_numbers): Explicitly check for write errors and terminate the program with diagnostic. * tests/misc/seq-io-errors.sh: Test error detection with /dev/full. * tests/misc/seq-epipe.sh: Test error detection with broken pipes. * tests/local.mk: Add new tests. * NEWS: Mention the fix. --- src/seq.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/seq.c b/src/seq.c index de92bc278..1b9da40fb 100644 --- a/src/seq.c +++ b/src/seq.c @@ -278,6 +278,15 @@ long_double_format (char const *fmt, struct layout *layout) } } +static void ATTRIBUTE_NORETURN +io_error (void) +{ + /* FIXME: consider option to silently ignore errno=EPIPE */ + error (0, errno, _("standard output")); + clearerr (stdout); + exit (EXIT_FAILURE); +} + /* Actually print the sequence of numbers in the specified range, with the given or default stepping and format. */ @@ -295,7 +304,8 @@ print_numbers (char const *fmt, struct layout layout, for (i = 1; ; i++) { long double x0 = x; - printf (fmt, x); + if (printf (fmt, x) < 0) + io_error (); if (out_of_range) break; x = first + i * step; @@ -336,10 +346,12 @@ print_numbers (char const *fmt, struct layout layout, break; } - fputs (separator, stdout); + if (fputs (separator, stdout) == EOF) + io_error (); } - fputs (terminator, stdout); + if (fputs (terminator, stdout) == EOF) + io_error (); } } @@ -506,14 +518,16 @@ seq_fast (char const *a, char const *b) output buffer so far, and reset to start of buffer. */ if (buf_end - (p_len + 1) < bufp) { - fwrite (buf, bufp - buf, 1, stdout); + if (fwrite (buf, bufp - buf, 1, stdout) != 1) + io_error (); bufp = buf; } } /* Write any remaining buffered output, and the terminator. */ *bufp++ = *terminator; - fwrite (buf, bufp - buf, 1, stdout); + if (fwrite (buf, bufp - buf, 1, stdout) != 1) + io_error (); IF_LINT (free (buf)); } -- cgit v1.2.3-70-g09d2