Jeff Epler shared a 'date' invocation in a Coreutils bug report that
produces a lot of output [1]. While not a bug itself, the report made me
notice that 'date' doesn't diagnose write errors immediately. That
behavior should be changed, in my opinion.

If you allowed it to run for however long it takes (hours?) to generate
output, you would see a write error:

    $ strace date +`python -c 'print("%2147483648c" * 10000)'` 2>&1 \
        > /dev/full | head -n 100
    [...]
    write(1, "                                "..., 4096) = -1 ENOSPC (No space 
left on device)
    write(1, "                                "..., 4096) = -1 ENOSPC (No space 
left on device)
    write(1, "                                "..., 4096) = -1 ENOSPC (No space 
left on device)
    write(1, "                                "..., 4096) = -1 ENOSPC (No space 
left on device)
    write(1, "                                "..., 4096) = -1 ENOSPC (No space 
left on device)

This patch checks for an error on the stream and returns early if there
is one:

    $ time ./src/date +`python -c 'print("%2147483648c" * 10000)'` > /dev/full
    date: write error: No space left on device
    
    real        0m0.019s
    user        0m0.012s
    sys 0m0.007s

I'll push the attatched patch to Gnulib and then add a test to Coreutils
if that is okay.

Collin

[1] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=79705

>From f3bff3feaacf3bb2a66104e64bfba196196f9e88 Mon Sep 17 00:00:00 2001
Message-ID: <f3bff3feaacf3bb2a66104e64bfba196196f9e88.1761716685.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Tue, 28 Oct 2025 22:43:57 -0700
Subject: [PATCH] fprintftime: Promptly diagnose write errors.

* lib/strftime.c (memset_byte) [FPRINTFTIME]: Break the loop if the
stream has an error.
(__strftime_internal) [FPRINTFTIME]: Return early if the stream has an
error.
---
 ChangeLog      |  8 ++++++++
 lib/strftime.c | 12 ++++++++++--
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index b4519b0e32..a37df95acf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2025-10-28  Collin Funk  <[email protected]>
+
+	fprintftime: Promptly diagnose write errors.
+	* lib/strftime.c (memset_byte) [FPRINTFTIME]: Break the loop if the
+	stream has an error.
+	(__strftime_internal) [FPRINTFTIME]: Return early if the stream has an
+	error.
+
 2025-10-27  Paul Eggert  <[email protected]>
 
 	openat2: new module
diff --git a/lib/strftime.c b/lib/strftime.c
index 27e2ca0976..4ca70b059f 100644
--- a/lib/strftime.c
+++ b/lib/strftime.c
@@ -207,8 +207,12 @@ enum pad_style
 #endif
 
 #if FPRINTFTIME
-# define memset_byte(P, Len, Byte) \
-  do { size_t _i; for (_i = 0; _i < Len; _i++) fputc (Byte, P); } while (0)
+# define memset_byte(P, Len, Byte)                              \
+  do                                                            \
+    {                                                           \
+      for (size_t _i = 0; _i < Len && ! ferror (P); _i++)       \
+        fputc (Byte, P);                                        \
+    } while (0)
 # define memset_space(P, Len) memset_byte (P, Len, ' ')
 # define memset_zero(P, Len) memset_byte (P, Len, '0')
 #elif defined COMPILE_WIDE
@@ -2368,6 +2372,10 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
           cpy (f - percent + 1, percent);
           break;
         }
+#if FPRINTFTIME
+      if (ferror (s))
+        return i;
+#endif
     }
 
 #if ! FPRINTFTIME
-- 
2.51.1

Reply via email to