bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: tee logs no output if stdout is closed


From: Bruno Haible
Subject: Re: tee logs no output if stdout is closed
Date: Tue, 1 Jul 2008 02:26:16 +0200
User-agent: KMail/1.5.4

Andreas Schwab wrote:
> > How about adding an option '-p' to 'tee', that causes it to ignore SIGPIPE
> > while writing to stdout?
> 
> Just add a trap '' SIGPIPE before starting tee.

Thanks, this does half of the trick: Each 'tee' invocation then writes
the complete stdin contents to the log file. But each 'tee' invocation also
complains:

  tee: standard output: Broken pipe
  tee: write error
  tee: standard output: Broken pipe
  tee: write error
  ...

I don't see any better solution than putting support for this into 'tee'
itself. Jim, here's a patch.


From 9813ded2983b0a7f276dc249e68a246bf9c1686a Mon Sep 17 00:00:00 2001
From: Bruno Haible <address@hidden>
Date: Tue, 1 Jul 2008 02:22:10 +0200
Subject: [PATCH]         New tee option -p.
         * src/tee.c (ignore_sigpipe): New variable.
         (long_options): Add option -p.
         (usage): Document option -p.
         (main): Handle option -p.
         (tee_files): When option -p is specified, ignore SIGPIPE write errors.
         * doc/coreutils.texi (tee invocation): Document option -p.

---
 doc/coreutils.texi |   11 +++++++++++
 src/tee.c          |   38 ++++++++++++++++++++++++++++++++++----
 2 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 155ba8d..c5d7745 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -11341,6 +11341,17 @@ them.
 @opindex --ignore-interrupts
 Ignore interrupt signals.
 
address@hidden -p
address@hidden --ignore-sigpipe
address@hidden -p
address@hidden --ignore-sigpipe
+Ignore failed writes to pipes with no readers.  By default, when standard
+output or one of the given files refers to a pipe with no reading processes,
+the operating system will kill the @command{tee} process with signal
address@hidden, thus terminating the output to the other files.  When the
+option @samp{-p} is specified, the @command{tee} process will continue
+writing to the other specified files.
+
 @end table
 
 The @command{tee} command is useful when you happen to be transferring a large
diff --git a/src/tee.c b/src/tee.c
index 4e46aab..85f4529 100644
--- a/src/tee.c
+++ b/src/tee.c
@@ -41,10 +41,14 @@ static bool append;
 /* If true, ignore interrupts. */
 static bool ignore_interrupts;
 
+/* If true, ignore failed writes to pipes with no readers. */
+static bool ignore_sigpipe;
+
 static struct option const long_options[] =
 {
   {"append", no_argument, NULL, 'a'},
   {"ignore-interrupts", no_argument, NULL, 'i'},
+  {"ignore-sigpipe", no_argument, NULL, 'p'},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -64,6 +68,7 @@ Copy standard input to each FILE, and also to standard 
output.\n\
 \n\
   -a, --append              append to the given FILEs, do not overwrite\n\
   -i, --ignore-interrupts   ignore interrupt signals\n\
+  -p, --ignore-sigpipe      ignore failed writes to pipes with no readers\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -93,7 +98,7 @@ main (int argc, char **argv)
   append = false;
   ignore_interrupts = false;
 
-  while ((optc = getopt_long (argc, argv, "ai", long_options, NULL)) != -1)
+  while ((optc = getopt_long (argc, argv, "aip", long_options, NULL)) != -1)
     {
       switch (optc)
        {
@@ -105,6 +110,10 @@ main (int argc, char **argv)
          ignore_interrupts = true;
          break;
 
+       case 'p':
+         ignore_sigpipe = true;
+         break;
+
        case_GETOPT_HELP_CHAR;
 
        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -117,6 +126,11 @@ main (int argc, char **argv)
   if (ignore_interrupts)
     signal (SIGINT, SIG_IGN);
 
+#ifdef SIGPIPE
+  if (ignore_sigpipe)
+    signal (SIGPIPE, SIG_IGN);
+#endif
+
   /* Do *not* warn if tee is given no file arguments.
      POSIX requires that it work when given no arguments.  */
 
@@ -192,9 +206,25 @@ tee_files (int nfiles, const char **files)
        if (descriptors[i]
            && fwrite (buffer, bytes_read, 1, descriptors[i]) != 1)
          {
-           error (0, errno, "%s", files[i]);
-           descriptors[i] = NULL;
-           ok = false;
+#ifdef SIGPIPE
+           if (ignore_sigpipe && errno == EPIPE)
+             {
+               /* Could not write to a pipe with no readers.
+                  Close the stream.  */
+               fclose (descriptors[i]);
+               /* Close also the underlying file descriptor, to avoid an
+                  error message from close_stdout.  */
+               if (fileno (descriptors[i]) >= 0)
+                 close (fileno (descriptors[i]));
+               descriptors[i] = NULL;
+             }
+           else
+#endif
+             {
+               error (0, errno, "%s", files[i]);
+               descriptors[i] = NULL;
+               ok = false;
+             }
          }
     }
 
-- 
1.5.5.3






reply via email to

[Prev in Thread] Current Thread [Next in Thread]