Re: tee logs no output if stdout is closed

2008-10-07 Thread Jim Meyering
Bruno Haible <[EMAIL PROTECTED]> wrote:
> Jim Meyering wrote:
...
>> s/is/may be/
>> Early reader termination may still deserve a diagnostic.
>> Or it could be that POSIX requires the application to diagnose EPIPE,
>> regardless ;-)
>
> I disagree here. If early reader termination leads to a diagnostic in this
> case, the diagnostic is timing dependent (depends which of the CPU cores
> executing the reader process and the writer process is more loaded); this
> is never what you want.
>
> POSIX does not specify anthing here, because it essentially says that during
> the operation specified by POSIX the SIGPIPE handler is set to SIG_DFL.

POSIX does specify the behavior of applications even when SIGPIPE is ignored.
It requires that they diagnose error conditions (which includes EPIPE).


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


Re: tee logs no output if stdout is closed

2008-10-05 Thread Bruno Haible
After the newest changes to gnulib, here's a revised version of the patch
proposed in 


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.  */
+		sigse

Re: tee logs no output if stdout is closed

2008-10-05 Thread Bruno Haible
Jim Meyering wrote:
> Thanks for writing all that.  The code looks fine.

Glad to see that our disagreements have been reduced to the comments.

> Let's not use "signaled" here.

Yes, indeed this term is confusing in a paragraph dealing with signals.

>  How about this in place of the above:
> 
> /* Tell close_stdout whether to ignore an EPIPE error.
>The default (ignore = false) ensures that a close_stdout-induced write
>failure due to EPIPE evokes a diagnostic about the failure, along with
>a nonzero exit status.  Use ignore = true to make close_stdout ignore
>any EPIPE error.

OK, I adopted the "diagnostic, along with a nonzero exit status" wording.
Still generally I prefer to say what the argument indicates, before stating
what is the default value. (It is less challenging for the reader to say
things one at a time.)

> Best not to use "signaled" here.
> Perhaps "diagnosed" instead.

Yup.

> > +   The ignore = true setting is suitable for a scenario where you don't 
> > know
> 
> s/is/may be/
> Early reader termination may still deserve a diagnostic.
> Or it could be that POSIX requires the application to diagnose EPIPE,
> regardless ;-)

I disagree here. If early reader termination leads to a diagnostic in this
case, the diagnostic is timing dependent (depends which of the CPU cores
executing the reader process and the writer process is more loaded); this
is never what you want.

POSIX does not specify anthing here, because it essentially says that during
the operation specified by POSIX the SIGPIPE handler is set to SIG_DFL.

Btw, the wording "is suitable" is not as strong as "is mandatory": it is
merely an advice with explanations.

I committed this:


2008-10-05  Bruno Haible  <[EMAIL PROTECTED]>
Jim Meyering  <[EMAIL PROTECTED]>

Add an option for ignoring EPIPE during close_stdout.
* lib/closeout.h: Include .
(close_stdout_set_ignore_EPIPE): New declaration.
* lib/closeout.c: Include .
(ignore_EPIPE): New variable.
(close_stdout_set_ignore_EPIPE): New function.
(close_stdout): Ignore EPIPE error if ignore_EPIPE is set.
* lib/close-stream.c (close_stream): Mention the possible EPIPE
failure.
* modules/closeout (Depends-on): Add stdbool.

*** lib/close-stream.c.orig 2008-10-06 02:37:14.0 +0200
--- lib/close-stream.c  2008-10-06 01:50:55.0 +0200
***
*** 1,6 
  /* Close a stream, with nicer error checking than fclose's.
  
!Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007 Free
 Software Foundation, Inc.
  
 This program is free software: you can redistribute it and/or modify
--- 1,6 
  /* Close a stream, with nicer error checking than fclose's.
  
!Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007, 2008 Free
 Software Foundation, Inc.
  
 This program is free software: you can redistribute it and/or modify
***
*** 33,38 
--- 33,42 
 otherwise.  A failure might set errno to 0 if the error number
 cannot be determined.
  
+A failure with errno set to EPIPE may or may not indicate an error
+situation worth signaling to the user.  See the documentation of the
+close_stdout_set_ignore_EPIPE function for details.
+ 
 If a program writes *anything* to STREAM, that program should close
 STREAM and make sure that it succeeds before exiting.  Otherwise,
 suppose that you go to the extreme of checking the return status
*** lib/closeout.c.orig 2008-10-06 02:37:14.0 +0200
--- lib/closeout.c  2008-10-06 02:36:36.0 +0200
***
*** 1,6 
  /* Close standard output and standard error, exiting with a diagnostic on 
error.
  
!Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006 Free
 Software Foundation, Inc.
  
 This program is free software: you can redistribute it and/or modify
--- 1,6 
  /* Close standard output and standard error, exiting with a diagnostic on 
error.
  
!Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2008 Free
 Software Foundation, Inc.
  
 This program is free software: you can redistribute it and/or modify
***
*** 21,26 
--- 21,27 
  #include "closeout.h"
  
  #include 
+ #include 
  #include 
  #include 
  
***
*** 42,47 
--- 43,85 
file_name = file;
  }
  
+ static bool ignore_EPIPE /* = false */;
+ 
+ /* Specify the reaction to an EPIPE error during the closing of stdout:
+  - If ignore = true, it shall be ignored.
+  - If ignore = false, it shall evoke a diagnostic, along with a nonzero
+exit status.
+The default is ignore = false.
+ 
+This setting matters only if the SIGPIPE signal is ignored (i.e. its
+handler set to SIG_IGN) or blocked.  Only particular programs need to
+temporarily ignore SIGPIPE.  If SIGPIPE is ignored or blocked because
+it was ignored or blocked in the parent process when it 

Re: tee logs no output if stdout is closed

2008-10-05 Thread Jim Meyering
Bruno Haible <[EMAIL PROTECTED]> wrote:

> Jim Meyering wrote:
>> > You can distinguish close_stream and close_stdout. close_stream is library 
>> > code,
>> > close_stdout is not. What about a 'bool ignore_epipe' that influences the
>> > behaviour of close_stdout? Whereas the library code that called 
>> > close_stream
>> > has to check against EOF/EPIPE itself if it wants to.
>>
>> Indeed.  This sounds workable, perhaps using a new
>> close_stdout_ignore_epipe function.
>
> Here's a proposed patch. The function name 'close_stdout_set_ignore_EPIPE'
> was chosen for consistency with the already existing function
> 'close_stdout_set_file_name'.
>
>
> 2008-10-04  Bruno Haible  <[EMAIL PROTECTED]>
> Jim Meyering  <[EMAIL PROTECTED]>
>
>   Add an option for ignoring EPIPE during close_stdout.
>   * lib/closeout.h: Include .
>   (close_stdout_set_ignore_EPIPE): New declaration.
>   * lib/closeout.c: Include .
>   (ignore_EPIPE): New variable.
>   (close_stdout_set_ignore_EPIPE): New function.
>   (close_stdout): Ignore EPIPE error if ignore_EPIPE is set.
>   * lib/close-stream.c (close_stream): Mention the possible EPIPE
>   failure.
>   * modules/closeout (Depends-on): Add stdbool.
...
> +static bool ignore_EPIPE /* = false */;
> +
> +/* Specify whether an EPIPE error during the closing of stdout should be
> +   ignored (ignore = true) or signaled to the user through an error message
> +   (ignore = false).

Thanks for writing all that.  The code looks fine.

Let's not use "signaled" here.  How about this in place of the above:

/* Tell close_stdout whether to ignore an EPIPE error.
   The default (ignore = false) ensures that a close_stdout-induced write
   failure due to EPIPE evokes a diagnostic about the failure, along with
   a nonzero exit status.  Use ignore = true to make close_stdout ignore
   any EPIPE error.

> +   This setting matters only if the SIGPIPE signal is ignored (i.e. its
> +   handler set to SIG_IGN) or blocked.  Only particular programs need to
> +   temporarily ignore SIGPIPE.  If SIGPIPE is ignored or blocked because
> +   it was ignored or blocked in the parent process when it created the
> +   child process, it usually is a bug in the parent process: It is bad
> +   practice to have SIGPIPE ignored or blocked while creating a child
> +   process.
> +
> +   EPIPE occurs when writing to a pipe or socket that has no readers now,
> +   when SIGPIPE is ignored or blocked.
> +
> +   The ignore = false setting is suitable for a scenario where it is normally
> +   guaranteed that the pipe writer terminates before the pipe reader.  In
> +   this case, an EPIPE is an indication of a premature termination of the
> +   pipe reader and should be signaled.

Best not to use "signaled" here.
Perhaps "diagnosed" instead.

> +
> +   The ignore = true setting is suitable for a scenario where you don't know

s/is/may be/
Early reader termination may still deserve a diagnostic.
Or it could be that POSIX requires the application to diagnose EPIPE,
regardless ;-)

> +   ahead of time whether the pipe writer or the pipe reader will terminate
> +   first.  In this case, an EPIPE is an indication that the pipe writer can
> +   stop doing useless write() calls; this is what close_stdout does anyway.
> +   EPIPE is part of the normal pipe/socket shutdown protocol in this case,
> +   and should not be signaled.  */

s/signaled/diagnosed/

With those changes, you're welcome to commit.


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


Re: tee logs no output if stdout is closed

2008-10-04 Thread Bruno Haible
Jim Meyering wrote:
> > You can distinguish close_stream and close_stdout. close_stream is library 
> > code,
> > close_stdout is not. What about a 'bool ignore_epipe' that influences the
> > behaviour of close_stdout? Whereas the library code that called close_stream
> > has to check against EOF/EPIPE itself if it wants to.
> 
> Indeed.  This sounds workable, perhaps using a new
> close_stdout_ignore_epipe function.

Here's a proposed patch. The function name 'close_stdout_set_ignore_EPIPE'
was chosen for consistency with the already existing function
'close_stdout_set_file_name'.


2008-10-04  Bruno Haible  <[EMAIL PROTECTED]>
Jim Meyering  <[EMAIL PROTECTED]>

Add an option for ignoring EPIPE during close_stdout.
* lib/closeout.h: Include .
(close_stdout_set_ignore_EPIPE): New declaration.
* lib/closeout.c: Include .
(ignore_EPIPE): New variable.
(close_stdout_set_ignore_EPIPE): New function.
(close_stdout): Ignore EPIPE error if ignore_EPIPE is set.
* lib/close-stream.c (close_stream): Mention the possible EPIPE
failure.
* modules/closeout (Depends-on): Add stdbool.

--- lib/closeout.h.orig 2008-10-04 15:01:05.0 +0200
+++ lib/closeout.h  2008-10-04 15:00:29.0 +0200
@@ -1,6 +1,7 @@
 /* Close standard output and standard error.
 
-   Copyright (C) 1998, 2000, 2003, 2004, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1998, 2000, 2003, 2004, 2006, 2008 Free Software Foundation,
+   Inc.
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,11 +19,14 @@
 #ifndef CLOSEOUT_H
 # define CLOSEOUT_H 1
 
+# include 
+
 # ifdef __cplusplus
 extern "C" {
 # endif
 
 void close_stdout_set_file_name (const char *file);
+void close_stdout_set_ignore_EPIPE (bool ignore);
 void close_stdout (void);
 
 # ifdef __cplusplus
--- lib/closeout.c.orig 2008-10-04 15:01:05.0 +0200
+++ lib/closeout.c  2008-10-04 14:54:01.0 +0200
@@ -1,6 +1,6 @@
 /* Close standard output and standard error, exiting with a diagnostic on 
error.
 
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006 Free
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2008 Free
Software Foundation, Inc.
 
This program is free software: you can redistribute it and/or modify
@@ -21,6 +21,7 @@
 #include "closeout.h"
 
 #include 
+#include 
 #include 
 #include 
 
@@ -42,6 +43,41 @@
   file_name = file;
 }
 
+static bool ignore_EPIPE /* = false */;
+
+/* Specify whether an EPIPE error during the closing of stdout should be
+   ignored (ignore = true) or signaled to the user through an error message
+   (ignore = false).
+
+   This setting matters only if the SIGPIPE signal is ignored (i.e. its
+   handler set to SIG_IGN) or blocked.  Only particular programs need to
+   temporarily ignore SIGPIPE.  If SIGPIPE is ignored or blocked because
+   it was ignored or blocked in the parent process when it created the
+   child process, it usually is a bug in the parent process: It is bad
+   practice to have SIGPIPE ignored or blocked while creating a child
+   process.
+
+   EPIPE occurs when writing to a pipe or socket that has no readers now,
+   when SIGPIPE is ignored or blocked.
+
+   The ignore = false setting is suitable for a scenario where it is normally
+   guaranteed that the pipe writer terminates before the pipe reader.  In
+   this case, an EPIPE is an indication of a premature termination of the
+   pipe reader and should be signaled.
+
+   The ignore = true setting is suitable for a scenario where you don't know
+   ahead of time whether the pipe writer or the pipe reader will terminate
+   first.  In this case, an EPIPE is an indication that the pipe writer can
+   stop doing useless write() calls; this is what close_stdout does anyway.
+   EPIPE is part of the normal pipe/socket shutdown protocol in this case,
+   and should not be signaled.  */
+
+void
+close_stdout_set_ignore_EPIPE (bool ignore)
+{
+  ignore_EPIPE = ignore;
+}
+
 /* Close standard output.  On error, issue a diagnostic and _exit
with status 'exit_failure'.
 
@@ -68,7 +104,8 @@
 void
 close_stdout (void)
 {
-  if (close_stream (stdout) != 0)
+  if (close_stream (stdout) != 0
+  && !(ignore_EPIPE && errno == EPIPE))
 {
   char const *write_error = _("write error");
   if (file_name)
--- lib/close-stream.c.orig 2008-10-04 15:01:05.0 +0200
+++ lib/close-stream.c  2008-10-04 14:58:09.0 +0200
@@ -1,6 +1,6 @@
 /* Close a stream, with nicer error checking than fclose's.
 
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007 Free
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007, 2008 Free
Software Foundation, Inc.
 
This program is free software: you can redistribute it and/or modify
@@ -33,6 +33,10 @@
otherwise.  A failure might set errno to 0 if the error num

Re: tee logs no output if stdout is closed

2008-10-04 Thread Jim Meyering
Bruno Haible <[EMAIL PROTECTED]> wrote:

> Jim Meyering wrote:
>> > ... if SIGPIPE is blocked or ignored.
>> >
>> >> which is not generally recommended.
>>
>> In some contexts.  Some environments (mis-configured login/csh) have
>> resulted in the default SIGPIPE handler being SIG_IGN.
>
> I agree that having SIGPIPE blocked or ignoring during an execve() or
> posix_spawn() call is a bad idea. The best strategy for a program that
> wants to write to a subprocess is therefore to
>   0. ensure the SIGPIPE handler is set to SIG_DFL.
>   1. spawn the subprocess,
>   2. switch the SIGPIPE handler to SIG_IGN,
>   3. start writing to the subprocess.
>
>> > If you want both scenarios - the "don't know which of the two terminates 
>> > first"
>> > and the "writer must terminate first" - to be supported by close_stream and
>> > close_stdout, IMO the program needs to be able to tell these functions 
>> > about
>> > it, probably through a global variable 'bool ignore_epipe' or similar.
>>
>> Using a global variable would not be appropriate for library code like
>> this.  What if two applications using the same library want to use
>> different policies?
>
> You can distinguish close_stream and close_stdout. close_stream is library 
> code,
> close_stdout is not. What about a 'bool ignore_epipe' that influences the
> behaviour of close_stdout? Whereas the library code that called close_stream
> has to check against EOF/EPIPE itself if it wants to.

Indeed.  This sounds workable, perhaps using a new
close_stdout_ignore_epipe function.

> That would satisfy the "don't know which of the two terminates first" scenario
> (the 'msgfilter' case), and your scenario of "writer must terminate first"
> as well.


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Jim Meyering
Paolo Bonzini <[EMAIL PROTECTED]> wrote:

>> What else do you propose to cover these cases, if not a global variable?
>
> If only one behavior is needed across an entire package, a dummy module
> with gl_MODULE_INDICATOR would do.  Better than having fwriteerror do
> one thing and close_stdout do another.

This is a good compromise, and may be sufficient.
The alternatives I didn't really want to mention are
to provide a new function or to change the API.


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Bruno Haible
Paolo Bonzini wrote:
> > To make it clear:
> >   - Patch 1 only - applies if close_stdout were modified to ignore EPIPE
> > always (which Jim has rejected).
> >   - Patch 1 + 2 combined - applies if close_stdout is as it currently is.
> 
> What's wrong in having patch 1 + 2 combined with close_stdout modified
> to ignore EPIPE?

Patch 2 would then be redundant and confusing.

Bruno



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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Paolo Bonzini

> What else do you propose to cover these cases, if not a global variable?

If only one behavior is needed across an entire package, a dummy module
with gl_MODULE_INDICATOR would do.  Better than having fwriteerror do
one thing and close_stdout do another.

Paolo


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Bruno Haible
Paolo Bonzini wrote:
> > If you want both scenarios - the "don't know which of the two terminates 
> > first"
> > and the "writer must terminate first" - to be supported by close_stream and
> > close_stdout, IMO the program needs to be able to tell these functions about
> > it, probably through a global variable 'bool ignore_epipe' or similar.
> 
> I think this is not necessary.  Most of the time, programs have no need
> to distinguish *which* pipe was in error, so they are okay with SIGPIPE
> or SIGCHLD.  The global would be needed for programs that deal with
> multiple pipes, cannot rely on SIGCHLD (including the case when they
> want to be 100% correct and don't want to muddle with
> async-signal-safety), *and* need to error out if the reader terminates
> first.

I think you have misunderstood something.

We are discussing different scenarios where SIGPIPE is set to SIG_IGN.

SIGCHLD is not usable because - as Jim pointed out - there may not be a
parent-child relationship between the pipe writer and the pipe reader,
and SIGCHLD is a can of worms anyway (race conditions).

Jim's scenario is "writer must terminate first", and if the reader terminates
first, the writer should show an error message.

My scenario is "don't know which of the two terminates first", and if the
reader terminates first, the writer should acknowledge it and continue
its normal processing.

What else do you propose to cover these cases, if not a global variable?

Bruno



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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Bruno Haible
Jim Meyering wrote:
> > ... if SIGPIPE is blocked or ignored.
> >
> >> which is not generally recommended.
> 
> In some contexts.  Some environments (mis-configured login/csh) have
> resulted in the default SIGPIPE handler being SIG_IGN.

I agree that having SIGPIPE blocked or ignoring during an execve() or
posix_spawn() call is a bad idea. The best strategy for a program that
wants to write to a subprocess is therefore to
  0. ensure the SIGPIPE handler is set to SIG_DFL.
  1. spawn the subprocess,
  2. switch the SIGPIPE handler to SIG_IGN,
  3. start writing to the subprocess.

> > If you want both scenarios - the "don't know which of the two terminates 
> > first"
> > and the "writer must terminate first" - to be supported by close_stream and
> > close_stdout, IMO the program needs to be able to tell these functions about
> > it, probably through a global variable 'bool ignore_epipe' or similar.
> 
> Using a global variable would not be appropriate for library code like
> this.  What if two applications using the same library want to use
> different policies?

You can distinguish close_stream and close_stdout. close_stream is library code,
close_stdout is not. What about a 'bool ignore_epipe' that influences the
behaviour of close_stdout? Whereas the library code that called close_stream
has to check against EOF/EPIPE itself if it wants to.

That would satisfy the "don't know which of the two terminates first" scenario
(the 'msgfilter' case), and your scenario of "writer must terminate first"
as well.

This would also be better than switching back the signal handler to SIG_DFL
right before the call to exit (0) in main(), because close_stdout is registered
as an 'atexit' handler and there are also other calls to exit() in a program,
from xalloc_die() for example.

> While I don't like the alternatives much,
> they're better in the long run.

What are the alternatives that you propose?

Bruno



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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Paolo Bonzini
Bruno Haible wrote:
> Paolo Bonzini wrote:
>>>   http://lists.gnu.org/archive/html/bug-coreutils/2008-09/msg00024.html
>> Doesn't the comment in patch 2
> 
> To make it clear:
>   - Patch 1 only - applies if close_stdout were modified to ignore EPIPE
> always (which Jim has rejected).
>   - Patch 1 + 2 combined - applies if close_stdout is as it currently is.

What's wrong in having patch 1 + 2 combined with close_stdout modified
to ignore EPIPE?  The modification would be invisible in that case when
-p is given.

Paolo


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Jim Meyering
Paolo Bonzini <[EMAIL PROTECTED]> wrote:

> Jim Meyering wrote:
>
>> Imagine a scenario in which the pipe reader is expected always to
>> be reading, and so the pipe writer can expect that any write failure with
>> errno==EPIPE indicates the reader has terminated unexpectedly.

 The above was assuming that SIGPIPE is being ignored.
>>>
>>> But if you need it, what's wrong with un-ignoring it?
>>
>> [we're getting far afield, but... ]
>
> Not really: if the only reason not to have close_stdout ignore EPIPE is
> a bug in a fringe shell on a mis-configured system, then:

No, no, no ;-)
That was just explaining my comment that ignoring
SIGPIPE is not recommended (in some contexts).

> - either you don't care, despite the "trouble to reproduce and
> diagnose", and you make it fail silently
>
> - or you work around it by unignoring SIGPIPE.
>
> I'd prefer to have EPIPE ignored, so I can prepare a patch to most
> coreutils for (2) if you wish.

I'm pretty sure that would be contrary to POSIX.


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Paolo Bonzini
Jim Meyering wrote:

> Imagine a scenario in which the pipe reader is expected always to
> be reading, and so the pipe writer can expect that any write failure with
> errno==EPIPE indicates the reader has terminated unexpectedly.
>>>
>>> The above was assuming that SIGPIPE is being ignored.
>>
>> But if you need it, what's wrong with un-ignoring it?
> 
> [we're getting far afield, but... ]

Not really: if the only reason not to have close_stdout ignore EPIPE is
a bug in a fringe shell on a mis-configured system, then:

- either you don't care, despite the "trouble to reproduce and
diagnose", and you make it fail silently

- or you work around it by unignoring SIGPIPE.

I'd prefer to have EPIPE ignored, so I can prepare a patch to most
coreutils for (2) if you wish.

Paolo


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Bruno Haible
Paolo Bonzini wrote:
> >   http://lists.gnu.org/archive/html/bug-coreutils/2008-09/msg00024.html
> 
> Doesn't the comment in patch 2

To make it clear:
  - Patch 1 only - applies if close_stdout were modified to ignore EPIPE
always (which Jim has rejected).
  - Patch 1 + 2 combined - applies if close_stdout is as it currently is.

Bruno



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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Jim Meyering
Paolo Bonzini <[EMAIL PROTECTED]> wrote:

> Jim Meyering wrote:
>> Paolo Bonzini <[EMAIL PROTECTED]> wrote:
>>> Jim,
>>>
 Imagine a scenario in which the pipe reader is expected always to
 be reading, and so the pipe writer can expect that any write failure with
 errno==EPIPE indicates the reader has terminated unexpectedly.
>>> If the writer should terminate first, the reader can still detect the
>>> failure using SIGPIPE and/or SIGCHLD.  Since you say that you consider
>>
>> The above was assuming that SIGPIPE is being ignored.
>
> But if you need it, what's wrong with un-ignoring it?

[we're getting far afield, but... ]
No point in making many of the coreutils programs un-ignore SIGPIPE
just to work around a fringe shell (csh) on a mis-configured system.
It was enough trouble to reproduce and diagnose ;-)


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Paolo Bonzini
Jim Meyering wrote:
> Paolo Bonzini <[EMAIL PROTECTED]> wrote:
>> Jim,
>>
>>> Imagine a scenario in which the pipe reader is expected always to
>>> be reading, and so the pipe writer can expect that any write failure with
>>> errno==EPIPE indicates the reader has terminated unexpectedly.
>> If the writer should terminate first, the reader can still detect the
>> failure using SIGPIPE and/or SIGCHLD.  Since you say that you consider
> 
> The above was assuming that SIGPIPE is being ignored.

But if you need it, what's wrong with un-ignoring it?

Paolo


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Jim Meyering
Paolo Bonzini <[EMAIL PROTECTED]> wrote:
> Jim,
>
>> Imagine a scenario in which the pipe reader is expected always to
>> be reading, and so the pipe writer can expect that any write failure with
>> errno==EPIPE indicates the reader has terminated unexpectedly.
>
> If the writer should terminate first, the reader can still detect the
> failure using SIGPIPE and/or SIGCHLD.  Since you say that you consider

The above was assuming that SIGPIPE is being ignored.  My goal is for the
_writer_ to be able to detect write failure due to EPIPE (via gnulib's
close_* functions), even when there is no parent child relationship
between the reader and writer.

> ignoring the signal to be discouraged, these programs should not see
> EPIPE anyway.  Yes, you also said:
>
>> Some environments (mis-configured login/csh) have
>> resulted in the default SIGPIPE handler being SIG_IGN.
>
> ... but there are so many other problems that could result from
> misconfiguration, such as fd 0/1/2 not being open.  I don't think

I agree.  we should not cater to misconfigured environments.
Just mentioning one context in which SIGPIPE should not be ignored.


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Paolo Bonzini
Bruno Haible wrote:
> Paolo Bonzini wrote:
>> Is it possible to implement the "tee
>> --ignore-sigpipe" as you did (delaying SIGPIPE until the last input
>> closes, which I also think is the right thing to do) while having
>> close-stream ignore EPIPE?
> 
> Yes it is. The complete patch was posted here:
> 
>   http://lists.gnu.org/archive/html/bug-coreutils/2008-09/msg00024.html

Doesn't the comment in patch 2

  /* Restore the default SIGPIPE signal handling before exiting.  From
 this point on, we prefer to get a SIGPIPE signal to an EPIPE error,
 since close_stdout interprets EPIPE as a failure condition.  */

... also apply as

  /* Restore the default SIGPIPE signal handling before exiting.  From
 this point on, we prefer to get a SIGPIPE signal to an EPIPE error,
 since close_stdout does not interpret EPIPE as a failure

 condition.  */

?  If so, there would be basically no change in the behavior of tee with
patch 2 applied, no matter if close_stdout fails on EPIPE or not.

Paolo


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Paolo Bonzini
Jim,

> Imagine a scenario in which the pipe reader is expected always to
> be reading, and so the pipe writer can expect that any write failure with
> errno==EPIPE indicates the reader has terminated unexpectedly.

If the writer should terminate first, the reader can still detect the
failure using SIGPIPE and/or SIGCHLD.  Since you say that you consider
ignoring the signal to be discouraged, these programs should not see
EPIPE anyway.  Yes, you also said:

> Some environments (mis-configured login/csh) have
> resulted in the default SIGPIPE handler being SIG_IGN.

... but there are so many other problems that could result from
misconfiguration, such as fd 0/1/2 not being open.  I don't think
programs that do not impact security should try to cater for this;
programs that do care about security, instead, are already armored
against misconfigured signals and everything else.  Furthermore, it's
not gnulib's purpose to do this currently, and even if there was a
"super-security" module, it would not make Bruno's proposal any less viable.


Replying to Bruno,

> If you want both scenarios - the "don't know which of the two terminates 
> first"
> and the "writer must terminate first" - to be supported by close_stream and
> close_stdout, IMO the program needs to be able to tell these functions about
> it, probably through a global variable 'bool ignore_epipe' or similar.

I think this is not necessary.  Most of the time, programs have no need
to distinguish *which* pipe was in error, so they are okay with SIGPIPE
or SIGCHLD.  The global would be needed for programs that deal with
multiple pipes, cannot rely on SIGCHLD (including the case when they
want to be 100% correct and don't want to muddle with
async-signal-safety), *and* need to error out if the reader terminates
first.

Paolo


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Jim Meyering
Bruno Haible <[EMAIL PROTECTED]> wrote:
> Jim Meyering wrote:
>> > EPIPE is part of the normal shutdown
>> > protocol of pipes, when the pipe writer chooses to block or ignore SIGPIPE.
>>
>> First, you're assuming that the pipe writer chooses to
>> block or ignore SIGPIPE
>
> Yes, EPIPE only occurs if SIGPIPE is blocked or ignored.
>
>> which is not generally recommended.

In some contexts.  Some environments (mis-configured login/csh) have
resulted in the default SIGPIPE handler being SIG_IGN.

> Huh? There is no authority that recommends leaving SIGPIPE's handler set to
> SIG_DFL. In fact,
>   - SIG_DFL is appropriate for programs whose only purpose/effect is to write
> something to standard output and standard error. (The majority of the
> Unix programs.)
>   - SIG_IGN is appropriate for programs whose main purpose is to do side 
> effects.
>   - SIG_IGN is appropriate also when writing into the stdin of child processes
> which may or may not read all the input before exiting. 'msgfilter' is
> such a program.
>
>> Imagine a scenario in which the pipe reader is expected always to
>> be reading, and so the pipe writer can expect that any write failure with
>> errno==EPIPE indicates the reader has terminated unexpectedly.  With your
>> modification, a pipe writer using close_stream would be unable to detect
>> a write failure due to EPIPE.
>
> The pipe writer will be the parent process of the pipe reader in this case,
> right? (If it's the other way around, the pipe writer should better terminate

What if the writer and reader processes have no such relationship?

> when the pipe reader is gone, hence it should have SIGPIPE set to SIG_DFL.)
> Then the detection whether the pipe reader has terminated unexpectedly should
> better be done through the exit code, IMO, rather than by continually writing.
>
> In this scenario, the pipe writer is expected to terminate before the pipe
> reader.
>
> The majority use-case of pipes is when you don't know ahead of time which
> of the two processes, pipe reader of pipe writer, will terminate first.
> In this case, EPIPE may occur as part of normal operation, depending on the
> timing of the two processes. close_stdout is not currently usable in this
> situation.
>
> If you want both scenarios - the "don't know which of the two terminates 
> first"
> and the "writer must terminate first" - to be supported by close_stream and
> close_stdout, IMO the program needs to be able to tell these functions about
> it, probably through a global variable 'bool ignore_epipe' or similar.

Using a global variable would not be appropriate for library code like
this.  What if two applications using the same library want to use
different policies?

While I don't like the alternatives much,
they're better in the long run.


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Bruno Haible
Jim Meyering wrote:
> > EPIPE is part of the normal shutdown
> > protocol of pipes, when the pipe writer chooses to block or ignore SIGPIPE.
> 
> First, you're assuming that the pipe writer chooses to
> block or ignore SIGPIPE

Yes, EPIPE only occurs if SIGPIPE is blocked or ignored.

> which is not generally recommended.

Huh? There is no authority that recommends leaving SIGPIPE's handler set to
SIG_DFL. In fact,
  - SIG_DFL is appropriate for programs whose only purpose/effect is to write
something to standard output and standard error. (The majority of the
Unix programs.)
  - SIG_IGN is appropriate for programs whose main purpose is to do side 
effects.
  - SIG_IGN is appropriate also when writing into the stdin of child processes
which may or may not read all the input before exiting. 'msgfilter' is
such a program.

> Imagine a scenario in which the pipe reader is expected always to
> be reading, and so the pipe writer can expect that any write failure with
> errno==EPIPE indicates the reader has terminated unexpectedly.  With your
> modification, a pipe writer using close_stream would be unable to detect
> a write failure due to EPIPE.

The pipe writer will be the parent process of the pipe reader in this case,
right? (If it's the other way around, the pipe writer should better terminate
when the pipe reader is gone, hence it should have SIGPIPE set to SIG_DFL.)
Then the detection whether the pipe reader has terminated unexpectedly should
better be done through the exit code, IMO, rather than by continually writing.

In this scenario, the pipe writer is expected to terminate before the pipe
reader.

The majority use-case of pipes is when you don't know ahead of time which
of the two processes, pipe reader of pipe writer, will terminate first.
In this case, EPIPE may occur as part of normal operation, depending on the
timing of the two processes. close_stdout is not currently usable in this
situation.

If you want both scenarios - the "don't know which of the two terminates first"
and the "writer must terminate first" - to be supported by close_stream and
close_stdout, IMO the program needs to be able to tell these functions about
it, probably through a global variable 'bool ignore_epipe' or similar.

Bruno



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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Bruno Haible
Paolo Bonzini wrote:
> Is it possible to implement the "tee
> --ignore-sigpipe" as you did (delaying SIGPIPE until the last input
> closes, which I also think is the right thing to do) while having
> close-stream ignore EPIPE?

Yes it is. The complete patch was posted here:

  http://lists.gnu.org/archive/html/bug-coreutils/2008-09/msg00024.html

Bruno



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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Jim Meyering
Bruno Haible <[EMAIL PROTECTED]> wrote:
> Jim Meyering wrote:
>> >* lib/close-stream.c (close_stream): Ignore error EPIPE from fclose.
>> >
>> I know this condition arises only when ignoring or handling SIGPIPE,
>> (which should be rather unusual) but even so, I really dislike the idea
>> of ignoring a write error.  Even if the write error would not occur
>> with slightly less output data, it's still one less _legitimate_ error
>> that can be reported.  If there is an EPIPE error, IMHO, close_stream
>> must diagnose it.
>
> This does not convince me, because EPIPE is part of the normal shutdown
> protocol of pipes, when the pipe writer chooses to block or ignore SIGPIPE.

First, you're assuming that the pipe writer chooses to
block or ignore SIGPIPE, which is not generally recommended.
But that's ok.  Just be aware that the discussion below
is relevant only in relatively unusual circumstances.

The problem is that close_stream is intended to be a general-purpose
function, and I think it must always report a write failure, even if in
some applications like yours, those are always deemed ignorable.

Imagine a scenario in which the pipe reader is expected always to
be reading, and so the pipe writer can expect that any write failure with
errno==EPIPE indicates the reader has terminated unexpectedly.  With your
modification, a pipe writer using close_stream would be unable to detect
a write failure due to EPIPE.


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


Re: tee logs no output if stdout is closed

2008-10-03 Thread Paolo Bonzini

> I cannot change 'close-stream', since you own that module. But for 
> 'fwriteerror',
> which I use in GNU gettext - and where I don't want to have spurious, timing-
> dependent error messages - I'm applying this:

I tend to agree with you on EPIPE, but OTOH this is as bad as it can be.
 Can't we find an agreement?  Is it possible to implement the "tee
--ignore-sigpipe" as you did (delaying SIGPIPE until the last input
closes, which I also think is the right thing to do) while having
close-stream ignore EPIPE?

Paolo


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


Re: tee logs no output if stdout is closed

2008-09-29 Thread Eric Blake
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

According to Bruno Haible on 9/26/2008 8:10 AM:
>> I know this condition arises only when ignoring or handling SIGPIPE,
>> (which should be rather unusual) but even so, I really dislike the idea
>> of ignoring a write error.  Even if the write error would not occur
>> with slightly less output data, it's still one less _legitimate_ error
>> that can be reported.  If there is an EPIPE error, IMHO, close_stream
>> must diagnose it.
> 
> This does not convince me, because EPIPE is part of the normal shutdown
> protocol of pipes, when the pipe writer chooses to block or ignore SIGPIPE.
> 
> The very purpose of having different error codes listed in  is
> to be able to react differently on them.

Sounds like we should ask the Austin group for an opinion.

- --
Don't work too hard, make some time for fun as well!

Eric Blake [EMAIL PROTECTED]
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkjgwk4ACgkQ84KuGfSFAYA2HgCfX7wO58HIN/+BFnncLKaxmqpu
raYAnj/KwGfM00iaY36Mb9fQZro78KAc
=iqI7
-END PGP SIGNATURE-


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


Re: tee logs no output if stdout is closed

2008-09-26 Thread Bruno Haible
Jim Meyering wrote:
> > * lib/close-stream.c (close_stream): Ignore error EPIPE from fclose.
> >
> I know this condition arises only when ignoring or handling SIGPIPE,
> (which should be rather unusual) but even so, I really dislike the idea
> of ignoring a write error.  Even if the write error would not occur
> with slightly less output data, it's still one less _legitimate_ error
> that can be reported.  If there is an EPIPE error, IMHO, close_stream
> must diagnose it.

This does not convince me, because EPIPE is part of the normal shutdown
protocol of pipes, when the pipe writer chooses to block or ignore SIGPIPE.

The very purpose of having different error codes listed in  is
to be able to react differently on them.

I cannot change 'close-stream', since you own that module. But for 
'fwriteerror',
which I use in GNU gettext - and where I don't want to have spurious, timing-
dependent error messages - I'm applying this:


2008-09-26  Bruno Haible  <[EMAIL PROTECTED]>

* lib/fwriteerror.c (do_fwriteerror): Ignore error EPIPE.

*** lib/fwriteerror.c.orig  2008-09-26 16:07:15.0 +0200
--- lib/fwriteerror.c   2008-09-26 15:38:27.0 +0200
***
*** 1,5 
  /* Detect write error on a stream.
!Copyright (C) 2003-2006 Free Software Foundation, Inc.
 Written by Bruno Haible <[EMAIL PROTECTED]>, 2003.
  
 This program is free software: you can redistribute it and/or modify
--- 1,5 
  /* Detect write error on a stream.
!Copyright (C) 2003-2006, 2008 Free Software Foundation, Inc.
 Written by Bruno Haible <[EMAIL PROTECTED]>, 2003.
  
 This program is free software: you can redistribute it and/or modify
***
*** 38,44 
stdout_closed = true;
  }
  
!   /* Need to
   1. test the error indicator of the stream,
   2. flush the buffers both in userland and in the kernel, through fclose,
  testing for error again.  */
--- 38,56 
stdout_closed = true;
  }
  
!   /* This function returns an error indication if there was a previous failure
!  or if fclose failed, with two exceptions:
!- Ignore an fclose failure if there was no previous error, no data
!remains to be flushed, and fclose failed with EBADF.  That can
!happen when a program like cp is invoked like this `cp a b >&-'
!(i.e., with standard output closed) and doesn't generate any
!output (hence no previous error and nothing to be flushed).
!- Ignore an fclose failure due to EPIPE.  That can happen when a
!program blocks or ignores SIGPIPE, and the output pipe or socket
!has no readers now.  The EPIPE tells us that we should stop writing
!to this output.  That's what we are doing anyway here.
! 
!  Need to
   1. test the error indicator of the stream,
   2. flush the buffers both in userland and in the kernel, through fclose,
  testing for error again.  */
***
*** 71,82 
if (fflush (fp))
goto close_preserving_errno; /* errno is set here */
if (fclose (fp) && errno != EBADF)
!   return -1; /* errno is set here */
  }
else
  {
if (fclose (fp))
!   return -1; /* errno is set here */
  }
  
return 0;
--- 83,94 
if (fflush (fp))
goto close_preserving_errno; /* errno is set here */
if (fclose (fp) && errno != EBADF)
!   goto got_errno; /* errno is set here */
  }
else
  {
if (fclose (fp))
!   goto got_errno; /* errno is set here */
  }
  
return 0;
***
*** 88,95 
  int saved_errno = errno;
  fclose (fp);
  errno = saved_errno;
- return -1;
}
  }
  
  int
--- 100,112 
  int saved_errno = errno;
  fclose (fp);
  errno = saved_errno;
}
+  got_errno:
+   /* There's an error.  Ignore EPIPE.  */
+   if (errno == EPIPE)
+ return 0;
+   else
+ return -1;
  }
  
  int



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


Re: tee logs no output if stdout is closed

2008-09-02 Thread Bruno Haible
Jim Meyering wrote:
> If there is an EPIPE error, IMHO, close_stream must diagnose it.

Well, then here is an amended patch (just for coreutils: 0001 and 0002,
with a single ChangeLog entry) for the 'tee' program.

The idea behind the patch is as follows:

SIGPIPE is an optimization through which the readers of a pipe can communicate
to the writers of the pipe "save your effort, no one is interested in your
output any more".

Suppose "tee /some/pipe-or-socket" is invoked. The 'tee' process has one
input and two outputs (stdout and /some/pipe-or-socket). If any of the output
destinations are shut down, the 'tee' process will get a SIGPIPE signal during
the next write() call. According to POSIX, 'tee' must terminate in this
situation.

Viewing SIGPIPE as an optimization, a different behaviour is useful:
When the first of the output destinations is shut down, 'tee' continues
to forward the input to the second destination. When the second destination
is shut down as well, _then_ there's no point for more input, and 'tee'
can terminate itself.

The new option '-p' implements this behaviour.

The reason for patch 0002 is to handle the case that some output destination
shuts down immediately after the input is terminated. In this case you
don't want a diagnostic; it's better to let the 'tee' process die from a
SIGPIPE in this case. This is the purpose of the line
   signal (SIGPIPE, SIG_DFL);

Bruno

From af4129d7520276b678539299799a177856e3ecdd Mon Sep 17 00:00:00 2001
From: Bruno Haible <[EMAIL PROTECTED]>
Date: Sun, 31 Aug 2008 17:35:16 +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  |   60 +++
 2 files changed, 66 insertions(+), 5 deletions(-)

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 3a04176..f81c35a 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -11369,6 +11369,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..42eb689 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,9 @@ main (int argc, char **argv)
   if (ignore_interrupts)
 signal (SIGINT, SIG_IGN);
 
+  if (ignore_sigpipe)
+signal (SIGPIPE, SIG_IGN);
+
   /* Do *not* warn if tee is given no file arguments.
  POSIX requires that it work when given no arguments.  */
 
@@ -135,6 +147,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 +174,7 @@ tee_files (int nf

Re: tee logs no output if stdout is closed

2008-09-02 Thread Jim Meyering
Bruno Haible <[EMAIL PROTECTED]> wrote:
> 2008-08-31  Bruno Haible  <[EMAIL PROTECTED]>
>
>   * lib/close-stream.c (close_stream): Ignore error EPIPE from fclose.
>
> --- lib/close-stream.c.orig   2008-08-31 17:18:56.0 +0200
> +++ lib/close-stream.c2008-08-31 17:14:12.0 +0200
> @@ -1,6 +1,6 @@
>  /* Close a stream, with nicer error checking than fclose's.
>
> -   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007 Free
> +   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007, 2008 Free
> Software Foundation, Inc.
>
> This program is free software: you can redistribute it and/or modify
> @@ -57,14 +57,20 @@
>bool fclose_fail = (fclose (stream) != 0);
>
>/* Return an error indication if there was a previous failure or if
> - fclose failed, with one exception: ignore an fclose failure if
> - there was no previous error, no data remains to be flushed, and
> - fclose failed with EBADF.  That can happen when a program like cp
> - is invoked like this `cp a b >&-' (i.e., with standard output
> - closed) and doesn't generate any output (hence no previous error
> - and nothing to be flushed).  */
> + fclose failed, with two exceptions:
> +   - Ignore an fclose failure if there was no previous error, no data
> +  remains to be flushed, and fclose failed with EBADF.  That can
> +  happen when a program like cp is invoked like this `cp a b >&-'
> +  (i.e., with standard output closed) and doesn't generate any
> +  output (hence no previous error and nothing to be flushed).
> +   - Ignore an fclose failure due to EPIPE.  That can happen when a
> +  program blocks or ignores SIGPIPE, and the output pipe or socket
> +  has no readers now.  The EPIPE tells us that we should stop writing
> +  to this output.  That's what we are doing anyway here, in
> +  close_stream.  */
>
> -  if (prev_fail || (fclose_fail && (some_pending || errno != EBADF)))
> +  if (prev_fail
> +  || (fclose_fail && (some_pending || errno != EBADF) && errno != EPIPE))
>  {
>if (! fclose_fail)
>   errno = 0;

I know this condition arises only when ignoring or handling SIGPIPE,
(which should be rather unusual) but even so, I really dislike the idea
of ignoring a write error.  Even if the write error would not occur
with slightly less output data, it's still one less _legitimate_ error
that can be reported.  If there is an EPIPE error, IMHO, close_stream
must diagnose it.


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


Re: tee logs no output if stdout is closed

2008-09-01 Thread Eric Blake
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

According to Bruno Haible on 8/31/2008 9:39 AM:
> Right. close_stdout and more generally close_stream should be changed to
> handle an EPIPE failure. An EPIPE errno value means that the kernel is telling
> the program "This pipe/socket has no readers any more. You can stop writing
> to it." But in close_stream we are already stopping the output to this
> pipe/socket. There's no point in signalling an error about this situation.
> 
> Also, if the reader process terminated only a moment later, the fflush and
> fclose would succeed, and the output would land in the kernel's pipe buffer
> and be discarded at that place.

Interesting arguments.  I'm still not 100% sure that POSIX allows or
forbids this, but I spent some time rereading
http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap01.html#tag_01_11.
 Writes can only fail with EPIPE when SIGPIPE is ignored; if SIGPIPE is
not ignored, then the default handler would have already exited prior to
any EPIPE.  The subsection "Consequences of Errors" states that "utilities
may terminate prematurely if they encounter ... difficulties ... writing
files".  It is that use of "may" instead of "shall" that makes it sound
like it is still reasonable to ignore EPIPE rather than declaring it a
write failure; and provided that no message is printed to stderr and exit
status is not affected, then it looks like you are correct - a compliant
app can safely ignore EPIPE errors if it happened to inherit an ignored
SIGPIPE.

One other argument in favor of Bruno's proposal:  for most write errors,
ignoring the error loses information (for example, discarding ENOSPC is
harmful, because the user may need to know when the disk is full).  But
for EPIPE, the user can always ensure that SIGPIPE is not ignored, and
thus that non-zero exit status will be provided (in other words, EPIPE is
an ignorable error because the user always has the option to avoid it in
the first place).

So, if Jim and/or Paul agrees, I'm inclined to agree with your gnulib
patch to close_stream, to silently ignore EPIPE rather than declare it a
write failure.

- --
Don't work too hard, make some time for fun as well!

Eric Blake [EMAIL PROTECTED]
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAki8j5AACgkQ84KuGfSFAYAvXwCeLzA1qM6Zqp5mM5QqHkRmOcVF
hQwAn03Ko02DgtcFgKGWCf8YwbS7ykyH
=u9xO
-END PGP SIGNATURE-


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


Re: tee logs no output if stdout is closed

2008-08-31 Thread Bruno Haible
Hi Jim,

On 2008-07-01 you replied to a proposed new 'tee' option that makes it ignore
SIGPIPE in 
:
> Thanks for the patch, but I'm reluctant to use it
> in part because it covers only the write syscalls deriving
> from tee's explicit fwrite call.  It does not handle
> an EPIPE failure that comes of a close_stdout-induced
> write syscall, so you'd still get the offending diagnostics
> some of the time.

Right. close_stdout and more generally close_stream should be changed to
handle an EPIPE failure. An EPIPE errno value means that the kernel is telling
the program "This pipe/socket has no readers any more. You can stop writing
to it." But in close_stream we are already stopping the output to this
pipe/socket. There's no point in signalling an error about this situation.

Also, if the reader process terminated only a moment later, the fflush and
fclose would succeed, and the output would land in the kernel's pipe buffer
and be discarded at that place.

I'm therefore proposing
  - a gnulib patch to ignore EPIPE in close_stream,
  - a coreutils patch to add option '-p' to 'tee'. Revised so that when _all_
output destinations of 'tee' have no readers any more, 'tee' terminates
with SIGPIPE (like all reasonable filter programs that have only 1 output
destination do).

Both patches are attached.

Bruno

2008-08-31  Bruno Haible  <[EMAIL PROTECTED]>

	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.

--- src/tee.c.orig	2008-08-31 17:22:12.0 +0200
+++ src/tee.c	2008-08-31 17:15:15.0 +0200
@@ -41,10 +41,14 @@
 /* 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 @@
 \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 @@
   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 @@
 	  ignore_interrupts = true;
 	  break;
 
+	case 'p':
+	  ignore_sigpipe = true;
+	  break;
+
 	case_GETOPT_HELP_CHAR;
 
 	case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -117,6 +126,9 @@
   if (ignore_interrupts)
 signal (SIGINT, SIG_IGN);
 
+  if (ignore_sigpipe)
+signal (SIGPIPE, SIG_IGN);
+
   /* Do *not* warn if tee is given no file arguments.
  POSIX requires that it work when given no arguments.  */
 
@@ -135,6 +147,7 @@
 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 +174,7 @@
   descriptors[0] = stdout;
   files[0] = _("standard output");
   setvbuf (stdout, NULL, _IONBF, 0);
+  num_open_descriptors = 1;
 
   for (i = 1; i <= nfiles; i++)
 {
@@ -173,7 +187,10 @@
 	  ok = false;
 	}
   else
-	setvbuf (descriptors[i], NULL, _IONBF, 0);
+	{
+	  setvbuf (descriptors[i], NULL, _IONBF, 0);
+	  num_open_descriptors++;
+	}
 }
 
   while (1)
@@ -192,9 +209,41 @@
 	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 forc

Re: tee logs no output if stdout is closed

2008-07-04 Thread Andreas Schwab
Phillip Susi <[EMAIL PROTECTED]> writes:

> Andreas Schwab wrote:
>> It would match the behaviour as defined by ASYNCHRONOUS EVENTS in 1.11
>> Utility Description Defaults.
>
> Could you quote that section or give me a url to somewhere I can see it
> myself?  I have no idea what it says nor where to look it up.

http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap01.html

"ASYNCHRONOUS EVENTS

  The ASYNCHRONOUS EVENTS section lists how the utility reacts to
  such events as signals and what signals are caught.

  Default Behavior: When this section is listed as "Default.", or it
  refers to "the standard action for all other signals; see Utility
  Description Defaults " it means that the action taken as a result
  of the signal shall be one of the following:

  1. The action shall be that inherited from the parent according to
 the rules of inheritance of signal actions defined in the
 System Interfaces volume of IEEE Std 1003.1-2001.

  2. When no action has been taken to change the default, the
 default action shall be that specified by the System Interfaces
 volume of IEEE Std 1003.1-2001.

  3. The result of the utility's execution is as if default actions
 had been taken.

A utility is permitted to catch a signal, perform some additional
processing (such as deleting temporary files), restore the default
signal action (or action inherited from the parent process), and
resignal itself."

> Also what about the issue where tee will try to write() to the now broken
> fd and fail?

That's a normal failure mode.

Andreas.

-- 
Andreas Schwab, SuSE Labs, [EMAIL PROTECTED]
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."


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


Re: tee logs no output if stdout is closed

2008-07-03 Thread Phillip Susi

Andreas Schwab wrote:

It would match the behaviour as defined by ASYNCHRONOUS EVENTS in 1.11
Utility Description Defaults.


Could you quote that section or give me a url to somewhere I can see it 
myself?  I have no idea what it says nor where to look it up.


Also what about the issue where tee will try to write() to the now 
broken fd and fail?



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


Re: tee logs no output if stdout is closed

2008-07-01 Thread Andreas Schwab
Phillip Susi <[EMAIL PROTECTED]> writes:

> Andreas Schwab wrote:
>>> It seems to me that tee should have a SIGPIPE handler which closes the
>>> broken fd and stops trying to write to it, and if ALL outputs have been
>>> closed, exit.
>>
>> That would not be compatible with POSIX.
>
> In what way?

It would match the behaviour as defined by ASYNCHRONOUS EVENTS in 1.11
Utility Description Defaults.

Andreas.

-- 
Andreas Schwab, SuSE Labs, [EMAIL PROTECTED]
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."


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


Re: tee logs no output if stdout is closed

2008-07-01 Thread Jim Meyering
Bruno Haible <[EMAIL PROTECTED]> wrote:
> 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 <[EMAIL PROTECTED]>
> 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.

Hi Bruno,

Thanks for the patch, but I'm reluctant to use it
in part because it covers only the write syscalls deriving
from tee's explicit fwrite call.  It does not handle
an EPIPE failure that comes of a close_stdout-induced
write syscall, so you'd still get the offending diagnostics
some of the time.


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


Re: tee logs no output if stdout is closed

2008-07-01 Thread Phillip Susi

Andreas Schwab wrote:

It seems to me that tee should have a SIGPIPE handler which closes the
broken fd and stops trying to write to it, and if ALL outputs have been
closed, exit.


That would not be compatible with POSIX.


In what way?

Also, won't ignoring SIGPIPE cause problems later when tee tries to 
write() to the broken fd and gets back an error?




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


Re: tee logs no output if stdout is closed

2008-06-30 Thread Bruno Haible
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 <[EMAIL PROTECTED]>
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.
 
[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..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




___
Bug-coreutils mailing list
Bu

Re: tee logs no output if stdout is closed

2008-06-30 Thread Andreas Schwab
Phillip Susi <[EMAIL PROTECTED]> writes:

> Andreas Schwab wrote:
>> Bruno Haible <[EMAIL PROTECTED]> writes:
>>
>>> 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.
>
> Wouldn't that only trap SIGPIPE sent to the shell, not tee?

Ignored signals are inherited.

> Aren't all signal handlers reset on exec()?

Only handled signals.

> It seems to me that tee should have a SIGPIPE handler which closes the
> broken fd and stops trying to write to it, and if ALL outputs have been
> closed, exit.

That would not be compatible with POSIX.

Andreas.

-- 
Andreas Schwab, SuSE Labs, [EMAIL PROTECTED]
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."


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


Re: tee logs no output if stdout is closed

2008-06-30 Thread Phillip Susi

Andreas Schwab wrote:

Bruno Haible <[EMAIL PROTECTED]> writes:


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.


Wouldn't that only trap SIGPIPE sent to the shell, not tee?  Aren't all 
signal handlers reset on exec()?


It seems to me that tee should have a SIGPIPE handler which closes the 
broken fd and stops trying to write to it, and if ALL outputs have been 
closed, exit.




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


Re: tee logs no output if stdout is closed

2008-06-30 Thread Andreas Schwab
Bruno Haible <[EMAIL PROTECTED]> writes:

> 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.

Andreas.

-- 
Andreas Schwab, SuSE Labs, [EMAIL PROTECTED]
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."


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


Re: tee logs no output if stdout is closed

2008-06-30 Thread Bruno Haible
Andreas Schwab wrote:
> It also says:
> 
> ASYNCHRONOUS EVENTS
>   Default ...

That indeed appears to imply that when writing a pipe with no readers,
the 'tee' process should be killed. This is appropriate for utilities which
produce no side effects, i.e. whose _only_ purpose is to produce output
on stdout. But for 'tee', this is only half of what it should do. The other
half is to write to the log file(s).

How about adding an option '-p' to 'tee', that causes it to ignore SIGPIPE
while writing to stdout?

Bruno



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


Re: tee logs no output if stdout is closed

2008-06-30 Thread Andreas Schwab
Bruno Haible <[EMAIL PROTECTED]> writes:

> If 'tee' was to write to the log file(s) first and then only to stdout, and
> if the input is small (does not need buffering), then its stdin input would 
> show
> up in the output, and this would also be POSIX compliant.

Just put a 'cat >/dev/null' in the pipe.

Andreas.

-- 
Andreas Schwab, SuSE Labs, [EMAIL PROTECTED]
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."


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


Re: tee logs no output if stdout is closed

2008-06-30 Thread Bruno Haible
Andreas Schwab wrote:
> > $ rm -f empty; touch empty; rm -f output output2; \
> >   for a in 0 1 2 3 4 5 6 7 8 9 ; do \
> > for b in 0 1 2 3 4 5 6 7 8 9 ; do \
> >   echo g$a$b | tee -a output; \
> >   echo h$a$b >> output2; \
> > done; \
> > sleep 2; \
> >   done \
> >   | { sleep 1; join --nocheck-order -v 2 - empty; }
> >
> > The 'join' command notices that its second argument is empty, stops reading,
> > and exits immediately.
> 
> The tee process then receives a SIGPIPE when trying to write to the
> broken pipe.  That will kill it.

Thanks for explaining.

If 'tee' was to write to the log file(s) first and then only to stdout, and
if the input is small (does not need buffering), then its stdin input would show
up in the output, and this would also be POSIX compliant.

Bruno



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


Re: tee logs no output if stdout is closed

2008-06-30 Thread Andreas Schwab
Bruno Haible <[EMAIL PROTECTED]> writes:

> tee appears to drop its input (i.e. it does not write it into the specified
> log file) if stdout is closed.
>
> I didn't expect this behaviour, and POSIX
>http://www.opengroup.org/susv3/utilities/tee.html
> does not mandate this behaviour either. Rather, it says:
>   "If any file operands are specified, the standard input shall be copied to
>each named file."

It also says:

ASYNCHRONOUS EVENTS
  Default, except that if the −i option was specified, SIGINT shall
  be ignored.

> $ rm -f empty; touch empty; rm -f output output2; \
>   for a in 0 1 2 3 4 5 6 7 8 9 ; do \
> for b in 0 1 2 3 4 5 6 7 8 9 ; do \
>   echo g$a$b | tee -a output; \
>   echo h$a$b >> output2; \
> done; \
> sleep 2; \
>   done \
>   | { sleep 1; join --nocheck-order -v 2 - empty; }
>
> The 'join' command notices that its second argument is empty, stops reading,
> and exits immediately.

The tee process then receives a SIGPIPE when trying to write to the
broken pipe.  That will kill it.

Andreas.

-- 
Andreas Schwab, SuSE Labs, [EMAIL PROTECTED]
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."


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


tee logs no output if stdout is closed

2008-06-29 Thread Bruno Haible
tee appears to drop its input (i.e. it does not write it into the specified
log file) if stdout is closed.

I didn't expect this behaviour, and POSIX
   http://www.opengroup.org/susv3/utilities/tee.html
does not mandate this behaviour either. Rather, it says:
  "If any file operands are specified, the standard input shall be copied to
   each named file."

$ tee --version
tee (GNU coreutils) 6.12.70-4f470

$ rm -f empty; touch empty; rm -f output output2; \
  for a in 0 1 2 3 4 5 6 7 8 9 ; do \
for b in 0 1 2 3 4 5 6 7 8 9 ; do \
  echo g$a$b | tee -a output; \
  echo h$a$b >> output2; \
done; \
sleep 2; \
  done \
  | { sleep 1; join --nocheck-order -v 2 - empty; }

The 'join' command notices that its second argument is empty, stops reading,
and exits immediately.
As a result, while a is 1 2 3 4 5 6 7 8 9, stdout is already closed.
The file 'output2' contains 100 lines, which shows that all loop iterations
were performed. The file 'output' contains only 10 lines, showing that 'tee'
dropped the output for a > 0.

Bruno



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