]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
tee: exit early if no more writable outputs
authorPádraig Brady <P@draigBrady.com>
Mon, 16 Feb 2015 13:19:20 +0000 (13:19 +0000)
committerPádraig Brady <P@draigBrady.com>
Wed, 18 Feb 2015 23:41:27 +0000 (23:41 +0000)
* src/tee.c (main): Don't continue reading if we can't
output anywhere.
* tests/misc/tee.sh: Ensure we exit when no more outputs.
* NEWS: Mention the change in behavior.

NEWS
src/tee.c
tests/misc/tee.sh

diff --git a/NEWS b/NEWS
index 5bc942c52e9af664d17ad97373e14f50962ee30b..b6795aacf720f948c3eab51309965298918073f9 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -71,6 +71,8 @@ GNU coreutils NEWS                                    -*- outline -*-
   insensitive file systems like HFS, mv would just remove a hardlinked 'file'
   if called like `mv file File`.  The feature was added in coreutils-5.0.1.
 
+  tee will exit early if there are no more writable outputs.
+
 ** Improvements
 
   cp,install,mv will convert smaller runs of NULs in the input to holes,
index 04b7ec3223fee0c6d9d7591950f212b4c8e604f1..bfe1b6900f815d0efd0d94bae9d840b83e2ea4bd 100644 (file)
--- a/src/tee.c
+++ b/src/tee.c
@@ -135,6 +135,7 @@ main (int argc, char **argv)
 static bool
 tee_files (int nfiles, const char **files)
 {
+  size_t n_outputs = 0;
   FILE **descriptors;
   char buffer[BUFSIZ];
   ssize_t bytes_read;
@@ -164,6 +165,7 @@ tee_files (int nfiles, const char **files)
   descriptors[0] = stdout;
   files[0] = _("standard output");
   setvbuf (stdout, NULL, _IONBF, 0);
+  n_outputs++;
 
   for (i = 1; i <= nfiles; i++)
     {
@@ -176,7 +178,10 @@ tee_files (int nfiles, const char **files)
           ok = false;
         }
       else
-        setvbuf (descriptors[i], NULL, _IONBF, 0);
+        {
+          setvbuf (descriptors[i], NULL, _IONBF, 0);
+          n_outputs++;
+        }
     }
 
   while (1)
@@ -194,9 +199,15 @@ tee_files (int nfiles, const char **files)
             && fwrite (buffer, bytes_read, 1, descriptors[i]) != 1)
           {
             error (0, errno, "%s", files[i]);
+            if (descriptors[i] == stdout)
+              clearerr (stdout); /* Avoid redundant close_stdout diagnostic.  */
             descriptors[i] = NULL;
             ok = false;
+            n_outputs--;
           }
+
+      if (n_outputs == 0)
+        break;
     }
 
   if (bytes_read == -1)
index 3c3fd11d7f8c2ee5e8a2a2e3fd8a9fccc08e1064..5f2eeda7b210c49d98d008a6576d64aa11688055 100755 (executable)
@@ -31,4 +31,29 @@ for n in 0 $nums; do
         done
 done
 
+
+# Ensure tee exits early if no more writable outputs
+if test -w /dev/full && test -c /dev/full; then
+  yes | returns_ 1 timeout 10 tee /dev/full 2>err >/dev/full || fail=1
+  # Ensure an error for each of the 2 outputs
+  # (and no redundant errors for stdout).
+  test $(wc -l < err) = 2 || { cat err; fail=1; }
+
+
+  # Ensure we continue with outputs that are OK
+  seq 10000 > multi_read || framework_failure_
+
+  returns_ 1 tee /dev/full out2 2>err >out1 <multi_read || fail=1
+  cmp multi_read out1 || fail=1
+  cmp multi_read out2 || fail=1
+  # Ensure an error for failing output
+  test $(wc -l < err) = 1 || { cat err; fail=1; }
+
+  returns_ 1 tee out1 out2 2>err >/dev/full <multi_read || fail=1
+  cmp multi_read out1 || fail=1
+  cmp multi_read out2 || fail=1
+  # Ensure an error for failing output
+  test $(wc -l < err) = 1 || { cat err; fail=1; }
+fi
+
 Exit $fail