From fed1a562c3d1f3cf3cac0dd1413679191ac43002 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Fri, 17 Jan 2020 13:02:57 +0100 Subject: [PATCH] Make I/O errors fatal instead of mere warnings (#63) An input/output error indicates a fatal condition, even if it occurs when closing a file. Awk should not return success on I/O error, but treat I/O errors as it already treats write errors. Test case: $ (trap '' PIPE; awk 'BEGIN { print "hi"; }'; echo "E $?" >&2) | : awk: i/o error occurred while closing /dev/stdout source line number 1 E 2 The test case pipes a line into a dummy command that reads no input, with SIGPIPE ignored so we rely on awk's own I/O checking. No write error is detected, because the pipe is buffered; the broken pipe is only detected as an I/O error on closing stdout. Before this commit, "E 0" was printed (indicating status 0/success) because an I/O error merely produced a warning. A shell script was unable to detect the I/O error using the exit status. --- FIXES | 4 ++++ run.c | 8 ++++---- testdir/T.misc | 5 +++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/FIXES b/FIXES index 6889e30..aac4a4a 100644 --- a/FIXES +++ b/FIXES @@ -25,6 +25,10 @@ THIS SOFTWARE. This file lists all bug fixes, changes, etc., made since the AWK book was sent to the printers in August, 1987. +January 9, 2020: + Input/output errors on closing files are now fatal instead of + mere warnings. Thanks to Martijn Dekker . + January 5, 2020: Fix a bug in the concatentation of two string constants into one done in the grammar. Fixes GitHub issue #61. Thanks diff --git a/run.c b/run.c index a331449..136e20a 100644 --- a/run.c +++ b/run.c @@ -1769,13 +1769,13 @@ Cell *closefile(Node **a, int n) for (i = 0; i < nfiles; i++) { if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) { if (ferror(files[i].fp)) - WARNING( "i/o error occurred on %s", files[i].fname ); + FATAL( "i/o error occurred on %s", files[i].fname ); if (files[i].mode == '|' || files[i].mode == LE) stat = pclose(files[i].fp); else stat = fclose(files[i].fp); if (stat == EOF) - WARNING( "i/o error occurred closing %s", files[i].fname ); + FATAL( "i/o error occurred closing %s", files[i].fname ); if (i > 2) /* don't do /dev/std... */ xfree(files[i].fname); files[i].fname = NULL; /* watch out for ref thru this */ @@ -1795,13 +1795,13 @@ void closeall(void) for (i = 0; i < FOPEN_MAX; i++) { if (files[i].fp) { if (ferror(files[i].fp)) - WARNING( "i/o error occurred on %s", files[i].fname ); + FATAL( "i/o error occurred on %s", files[i].fname ); if (files[i].mode == '|' || files[i].mode == LE) stat = pclose(files[i].fp); else stat = fclose(files[i].fp); if (stat == EOF) - WARNING( "i/o error occurred while closing %s", files[i].fname ); + FATAL( "i/o error occurred while closing %s", files[i].fname ); } } } diff --git a/testdir/T.misc b/testdir/T.misc index 7fc196a..a191ae2 100755 --- a/testdir/T.misc +++ b/testdir/T.misc @@ -466,3 +466,8 @@ echo '' >foo0 $awk 'END { print NF, $0 }' foo0 >foo1 awk '{ print NF, $0 }' foo0| tail -1 >foo2 cmp -s foo1 foo2 || echo 'BAD: T.misc END must preserve $0' + +# Check for nonzero exit status on I/O error. +echo 'E 2' >foo1 +(trap '' PIPE; "$awk" 'BEGIN { print "hi"; }' 2>/dev/null; echo "E $?" >foo2) | : +cmp -s foo1 foo2 || echo 'BAD: T.misc exit status on I/O error'