]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
tac: promptly diagnose write errors
authorCollin Funk <collin.funk1@gmail.com>
Sat, 21 Mar 2026 08:07:28 +0000 (01:07 -0700)
committerCollin Funk <collin.funk1@gmail.com>
Sat, 21 Mar 2026 19:10:59 +0000 (12:10 -0700)
This patch also fixes a bug where 'tac' would print a vague error on
some inputs:

    $ seq 10000 | ./src/tac-prev > /dev/full
    tac-prev: write error
    $ seq 10000 | ./src/tac > /dev/full
    tac: write error: No space left on device

In this case ferror (stdout) is true, but errno has been set back to
zero by a successful fclose (stdout) call.

* src/tac.c (output): Call write_error() if fwrite fails.
* tests/misc/io-errors.sh: Check that 'tac' prints a detailed write
error.
* NEWS: Mention the improvement.

NEWS
src/tac.c
tests/misc/io-errors.sh

diff --git a/NEWS b/NEWS
index 42d1f2e2e987865c8d2b4ef449dae5722935a454..2fabd07b7670e5fa9d2b98f374bd20e88e578073 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -59,6 +59,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   'shuf -i' now operates up to two times faster on systems with unlocked stdio
   functions.
 
+  'tac' will now exit sooner after a write error, which is significant when
+  operating on a file with many lines.
+
   'timeout' now properly detects when it is reparented by a subreaper process on
   Linux instead of init, e.g., the 'systemd --user' process.
 
index 4cab99d0b318490bf38181a89efa20a095b0702b..e63f70fc30443a1b9359c5dd4d9fcb7b51a8a2bd 100644 (file)
--- a/src/tac.c
+++ b/src/tac.c
@@ -158,7 +158,8 @@ output (char const *start, char const *past_end)
 
   if (!start)
     {
-      fwrite (buffer, 1, bytes_in_buffer, stdout);
+      if (fwrite (buffer, 1, bytes_in_buffer, stdout) != bytes_in_buffer)
+        write_error ();
       bytes_in_buffer = 0;
       return;
     }
@@ -169,7 +170,8 @@ output (char const *start, char const *past_end)
       memcpy (buffer + bytes_in_buffer, start, bytes_available);
       bytes_to_add -= bytes_available;
       start += bytes_available;
-      fwrite (buffer, 1, WRITESIZE, stdout);
+      if (fwrite (buffer, 1, WRITESIZE, stdout) != WRITESIZE)
+        write_error ();
       bytes_in_buffer = 0;
       bytes_available = WRITESIZE;
     }
index d5dde67a7c8d4820c3a8ae78c9d87f5c613b4617..d8efee08a2f7bb5ef38e0e50b807419fea3fa7a7 100755 (executable)
@@ -55,6 +55,7 @@ od -v foo
 paste foo
 pr foo
 seq 1
+tac --version; seq 10000 | tac
 tail -n1 foo
 tee < foo
 tr . . < foo