]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
tee: generalize the --write-error option to --output-error
authorPádraig Brady <P@draigBrady.com>
Mon, 2 Mar 2015 20:06:17 +0000 (20:06 +0000)
committerPádraig Brady <P@draigBrady.com>
Wed, 4 Mar 2015 13:24:21 +0000 (13:24 +0000)
Adjust commit v8.23-140-gfdd6ebf to add the --output-error option
instead of --write-error, and treat open() errors like write() errors.

* doc/coreutils.texi (tee invocation): s/write-error/output-error/.
* src/tee.c (main): Exit on open() error if appropriate.
* tests/misc/tee.sh: Add a case to test open() errors.
* NEWS: Adjust for the more general output error behavior.

Suggested by Bernhard Voelker.

NEWS
doc/coreutils.texi
src/tee.c
tests/misc/tee.sh

diff --git a/NEWS b/NEWS
index 8aef1a672b2ea4266da319ae447325dc540631b6..1a5123574612768f71c1efd26d712a5035570a53 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -58,7 +58,8 @@ GNU coreutils NEWS                                    -*- outline -*-
   sync no longer ignores arguments, and syncs each specified file, or with the
   --file-system option, the file systems associated with each specified file.
 
-  tee accepts a new --write-error option to control operation with pipes.
+  tee accepts a new --output-error option to control operation with pipes
+  and output errors in general.
 
 ** Changes in behavior
 
index d3239a567cb1c4b154e4fb589eeabfb111c8b33b..6110cecd0d49b9a2efe1b3dfac9e685bd5e7e303 100644 (file)
@@ -13202,29 +13202,29 @@ them.
 Ignore interrupt signals.
 
 @item -p
-@itemx --write-error[=@var{mode}]
+@itemx --output-error[=@var{mode}]
 @opindex -p
-@opindex --write-error
-Select the behavior with write errors on the outputs,
+@opindex --output-error
+Select the behavior with errors on the outputs,
 where @var{mode} is one of the following:
 
 @table @samp
 @item warn
-Warn on error writing any output, including pipes.
+Warn on error opening or writing any output, including pipes.
 Writing is continued to still open files/pipes.
 Exit status indicates failure if any output has an error.
 
 @item warn-nopipe
-Warn on error writing any output, except pipes.
+Warn on error opening or writing any output, except pipes.
 Writing is continued to still open files/pipes.
 Exit status indicates failure if any non pipe output had an error.
 This is the default @var{mode} when not specified.
 
 @item exit
-Exit on error writing any output, including pipes.
+Exit on error opening or writing any output, including pipes.
 
 @item exit-nopipe
-Exit on error writing any output, except pipes.
+Exit on error opening or writing any output, except pipes.
 @end table
 
 @end table
index c163184cb06e58b3c1839171ea07869efb877012..3c39a4ab33bed4a23ce467004ca19d28883de24b 100644 (file)
--- a/src/tee.c
+++ b/src/tee.c
@@ -44,37 +44,37 @@ static bool append;
 /* If true, ignore interrupts. */
 static bool ignore_interrupts;
 
-enum write_error
+enum output_error
   {
-    write_error_sigpipe,      /* traditional behavior, sigpipe enabled.  */
-    write_error_warn,         /* warn on EPIPE, but continue.  */
-    write_error_warn_nopipe,  /* ignore EPIPE, continue.  */
-    write_error_exit,         /* exit on any write error.  */
-    write_error_exit_nopipe   /* exit on any write error except EPIPE.  */
+    output_error_sigpipe,      /* traditional behavior, sigpipe enabled.  */
+    output_error_warn,         /* warn on EPIPE, but continue.  */
+    output_error_warn_nopipe,  /* ignore EPIPE, continue.  */
+    output_error_exit,         /* exit on any output error.  */
+    output_error_exit_nopipe   /* exit on any output error except EPIPE.  */
   };
 
-static enum write_error write_error;
+static enum output_error output_error;
 
 static struct option const long_options[] =
 {
   {"append", no_argument, NULL, 'a'},
   {"ignore-interrupts", no_argument, NULL, 'i'},
-  {"write-error", optional_argument, NULL, 'p'},
+  {"output-error", optional_argument, NULL, 'p'},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
 };
 
-static char const *const write_error_args[] =
+static char const *const output_error_args[] =
 {
   "warn", "warn-nopipe", "exit", "exit-nopipe", NULL
 };
-static enum write_error const write_error_types[] =
+static enum output_error const output_error_types[] =
 {
-  write_error_warn, write_error_warn_nopipe,
-  write_error_exit, write_error_exit_nopipe
+  output_error_warn, output_error_warn_nopipe,
+  output_error_exit, output_error_exit_nopipe
 };
-ARGMATCH_VERIFY (write_error_args, write_error_types);
+ARGMATCH_VERIFY (output_error_args, output_error_types);
 
 void
 usage (int status)
@@ -91,7 +91,7 @@ Copy standard input to each FILE, and also to standard output.\n\
   -i, --ignore-interrupts   ignore interrupt signals\n\
 "), stdout);
       fputs (_("\
-  -p, --write-error[=MODE]  behavior on write error.  See MODE details below\n\
+  -p, --output-error[=MODE]  behavior on write error.  See MODE details below\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -103,7 +103,7 @@ MODE determines behavior with write errors on the outputs:\n\
   'exit'         exit on error writing to any output\n\
   'exit-nopipe'  exit on error writing to any output not a pipe\n\
 The default MODE for the -p option is 'warn-nopipe'.\n\
-The default operation when --write-error is not specified, is to\n\
+The default operation when --output-error is not specified, is to\n\
 exit immediately on error writing to a pipe, and diagnose errors\n\
 writing to non pipe outputs.\n\
 "), stdout);
@@ -143,10 +143,10 @@ main (int argc, char **argv)
 
         case 'p':
           if (optarg)
-            write_error = XARGMATCH ("--write-error", optarg, write_error_args,
-                                     write_error_types);
+            output_error = XARGMATCH ("--output-error", optarg,
+                                      output_error_args, output_error_types);
           else
-            write_error = write_error_warn_nopipe;
+            output_error = output_error_warn_nopipe;
           break;
 
         case_GETOPT_HELP_CHAR;
@@ -161,7 +161,7 @@ main (int argc, char **argv)
   if (ignore_interrupts)
     signal (SIGINT, SIG_IGN);
 
-  if (write_error != write_error_sigpipe)
+  if (output_error != output_error_sigpipe)
     signal (SIGPIPE, SIG_IGN);
 
   /* Do *not* warn if tee is given no file arguments.
@@ -184,7 +184,7 @@ tee_files (int nfiles, const char **files)
   size_t n_outputs = 0;
   FILE **descriptors;
   char buffer[BUFSIZ];
-  ssize_t bytes_read;
+  ssize_t bytes_read = 0;
   int i;
   bool ok = true;
   char const *mode_string =
@@ -219,7 +219,9 @@ tee_files (int nfiles, const char **files)
       descriptors[i] = fopen (files[i], mode_string);
       if (descriptors[i] == NULL)
         {
-          error (0, errno, "%s", files[i]);
+          error (output_error == output_error_exit
+                 || output_error == output_error_exit_nopipe,
+                 errno, "%s", files[i]);
           ok = false;
         }
       else
@@ -229,7 +231,7 @@ tee_files (int nfiles, const char **files)
         }
     }
 
-  while (1)
+  while (n_outputs)
     {
       bytes_read = read (0, buffer, sizeof buffer);
       if (bytes_read < 0 && errno == EINTR)
@@ -244,14 +246,14 @@ tee_files (int nfiles, const char **files)
             && fwrite (buffer, bytes_read, 1, descriptors[i]) != 1)
           {
             int w_errno = errno;
-            bool fail = errno != EPIPE || (write_error == write_error_exit
-                                           || write_error == write_error_warn);
+            bool fail = errno != EPIPE || (output_error == output_error_exit
+                                          || output_error == output_error_warn);
             if (descriptors[i] == stdout)
               clearerr (stdout); /* Avoid redundant close_stdout diagnostic.  */
             if (fail)
               {
-                error (write_error == write_error_exit
-                       || write_error == write_error_exit_nopipe,
+                error (output_error == output_error_exit
+                       || output_error == output_error_exit_nopipe,
                        w_errno, "%s", files[i]);
               }
             descriptors[i] = NULL;
@@ -259,9 +261,6 @@ tee_files (int nfiles, const char **files)
               ok = false;
             n_outputs--;
           }
-
-      if (n_outputs == 0)
-        break;
     }
 
   if (bytes_read == -1)
index 84665cd005de5fbfa3b3ffde35d48432c0cab00b..f457a0b7a12552b2f67acdec274bee17719b8d71 100755 (executable)
@@ -64,7 +64,7 @@ if test -w /dev/full && test -c /dev/full; then
 fi
 
 
-# Ensure tee honors --write-error modes
+# Ensure tee honors --output-error modes
 mkfifo_or_skip_ fifo
 read_fifo() { timeout 10 dd count=1 if=fifo of=/dev/null status=none & }
 
@@ -73,30 +73,36 @@ read_fifo
 yes >fifo
 pipe_status=$?
 
-# Default operation is to exit silently on SIGPIPE
+# Default operation is to continue on output errors but exit silently on SIGPIPE
 read_fifo
-yes | returns_ $pipe_status timeout 10 tee 2>err >fifo || fail=1
-test $(wc -l < err) = 0 || { cat err; fail=1; }
+yes | returns_ $pipe_status timeout 10 tee ./e/noent 2>err >fifo || fail=1
+test $(wc -l < err) = 1 || { cat err; fail=1; }
 
 # With -p, SIGPIPE is suppressed, exit 0 for EPIPE when all outputs finished
 read_fifo
 yes | timeout 10 tee -p 2>err >fifo || fail=1
 test $(wc -l < err) = 0 || { cat err; fail=1; }
 
-# With --write-error=warn, exit 1 for EPIPE when all outputs finished
+# With --output-error=warn, exit 1 for EPIPE when all outputs finished
+read_fifo
+yes | returns_ 1 timeout 10 tee --output-error=warn 2>err >fifo || fail=1
+test $(wc -l < err) = 1 || { cat err; fail=1; }
+
+# With --output-error=exit, exit 1 immediately for EPIPE
 read_fifo
-yes | returns_ 1 timeout 10 tee --write-error=warn 2>err >fifo || fail=1
+yes | returns_ 1 timeout 10 tee --output-error=exit /dev/null 2>err >fifo \
+  || fail=1
 test $(wc -l < err) = 1 || { cat err; fail=1; }
 
-# With --write-error=exit, exit 1 immediately for EPIPE
+# With --output-error=exit, exit 1 immediately on output error
 read_fifo
-yes | returns_ 1 timeout 10 tee --write-error=exit /dev/null 2>err >fifo \
+yes | returns_ 1 timeout 10 tee --output-error=exit ./e/noent 2>err >fifo \
   || fail=1
 test $(wc -l < err) = 1 || { cat err; fail=1; }
 
-# With --write-error=exit-nopipe, exit 0 for EPIPE
+# With --output-error=exit-nopipe, exit 0 for EPIPE
 read_fifo
-yes | timeout 10 tee --write-error=exit-nopipe 2>err >fifo || fail=1
+yes | timeout 10 tee --output-error=exit-nopipe 2>err >fifo || fail=1
 test $(wc -l < err) = 0 || { cat err; fail=1; }
 
 wait