After the newest changes to gnulib, here's a revised version of the patch
proposed in 
<http://lists.gnu.org/archive/html/bug-coreutils/2008-09/msg00024.html>

From a4434d71a1a3ec7a6aee6de4a81da36301b12a28 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[EMAIL PROTECTED]>
Date: Mon, 6 Oct 2008 02:58:58 +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
 until the last open output descriptor is closed.
 * doc/coreutils.texi (tee invocation): Document option -p.

---
 doc/coreutils.texi |   11 +++++++++
 src/tee.c          |   63 +++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 69 insertions(+), 5 deletions(-)

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 67da740..a271251 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -11445,6 +11445,17 @@ them.
 @opindex --ignore-interrupts
 Ignore interrupt signals.
 
[EMAIL PROTECTED] -p
[EMAIL PROTECTED] --ignore-sigpipe
[EMAIL PROTECTED] -p
[EMAIL PROTECTED] --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
[EMAIL PROTECTED], 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..e7c5943 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,12 @@ main (int argc, char **argv)
   if (ignore_interrupts)
     signal (SIGINT, SIG_IGN);
 
+  if (ignore_sigpipe)
+    {
+      signal (SIGPIPE, SIG_IGN);
+      close_stdout_set_ignore_EPIPE (true);
+    }
+
   /* Do *not* warn if tee is given no file arguments.
      POSIX requires that it work when given no arguments.  */
 
@@ -135,6 +150,7 @@ static bool
 tee_files (int nfiles, const char **files)
 {
   FILE **descriptors;
+  size_t num_open_descriptors;
   char buffer[BUFSIZ];
   ssize_t bytes_read;
   int i;
@@ -161,6 +177,7 @@ tee_files (int nfiles, const char **files)
   descriptors[0] = stdout;
   files[0] = _("standard output");
   setvbuf (stdout, NULL, _IONBF, 0);
+  num_open_descriptors = 1;
 
   for (i = 1; i <= nfiles; i++)
     {
@@ -173,7 +190,10 @@ tee_files (int nfiles, const char **files)
 	  ok = false;
 	}
       else
-	setvbuf (descriptors[i], NULL, _IONBF, 0);
+	{
+	  setvbuf (descriptors[i], NULL, _IONBF, 0);
+	  num_open_descriptors++;
+	}
     }
 
   while (1)
@@ -192,9 +212,41 @@ 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;
+	    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;
+		if (--num_open_descriptors == 0)
+		  {
+		    /* All output descriptors are closed.  We have no reason
+		       to continue reading input any more.  Raise a SIGPIPE
+		       and terminate.  */
+		    sigset_t sigpipe_set;
+
+		    sigemptyset (&sigpipe_set);
+		    sigaddset (&sigpipe_set, SIGPIPE);
+		    sigprocmask (SIG_UNBLOCK, &sigpipe_set, NULL);
+
+		    signal (SIGPIPE, SIG_DFL);
+
+		    raise (SIGPIPE);
+
+		    /* raise didn't terminate? So force a termination.  */
+		    goto done;
+		  }
+	      }
+	    else
+	      {
+		error (0, errno, "%s", files[i]);
+		descriptors[i] = NULL;
+		ok = false;
+	      }
 	  }
     }
 
@@ -213,6 +265,7 @@ tee_files (int nfiles, const char **files)
 	ok = false;
       }
 
+ done:
   free (descriptors);
 
   return ok;
-- 
1.5.6.3

_______________________________________________
Bug-coreutils mailing list
Bug-coreutils@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-coreutils

Reply via email to