summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--src/tee.c13
-rwxr-xr-xtests/misc/tee.sh25
3 files changed, 39 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index 5bc942c52..b6795aacf 100644
--- 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,
diff --git a/src/tee.c b/src/tee.c
index 04b7ec322..bfe1b6900 100644
--- 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)
diff --git a/tests/misc/tee.sh b/tests/misc/tee.sh
index 3c3fd11d7..5f2eeda7b 100755
--- a/tests/misc/tee.sh
+++ b/tests/misc/tee.sh
@@ -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