Subject: bug#11540: [PATCH] tee: add a flag to ignore SIGPIPE

From: Pádraig Brady <[email-masked]>
Date: Tue, 22 May 2012 18:18:31 +0100

On 05/22/2012 03:00 PM, Igor Ippolitov wrote:
>>>From 89c055b385a9d4f4804af6b7b3fbe67651471613 Mon Sep 17 00:00:00 2001
> From: Ippolitov A. Igor <[email-masked]>
> Date: Tue, 22 May 2012 17:58:23 +0400
> Subject: [PATCH] tee: add a flag to ignore SIGPIPE
> 
> * src/tee.c: added ignore_sigpipes variable and -p
>              and --ignore-sigpipes options
> 
> If we call tee like:
> program | tee file1 file2 | head -3
> just to be sure there some output from program started. Or like:
> program | tee >(head -1) file1 file2
> We'll get SIGPIPE on writing to a file. It can be undesirable
> behaviour: file1 and file2 would be incomplete.
> Running with -i won't correct this.
> "-p|--ignore-sigpipes" options will make tee ignore any sigpipe
> it can receive. So file1 and file2 would have complete output.

> ---
>  src/tee.c |   19 ++++++++++++++++++-
>  1 files changed, 18 insertions(+), 1 deletions(-)
> 
> diff --git a/src/tee.c b/src/tee.c
> index 2d82577..0021174 100644
> --- a/src/tee.c
> +++ b/src/tee.c
> @@ -43,10 +43,14 @@ static bool append;
>  /* If true, ignore interrupts. */
>  static bool ignore_interrupts;
> 
> +/* if true, ignore sigpipe signal. */
> +static bool ignore_sigpipes;
> +
>  static struct option const long_options[] =
>  {
>    {"append", no_argument, NULL, 'a'},
>    {"ignore-interrupts", no_argument, NULL, 'i'},
> +  {"ignore-sigpipes", no_argument, NULL, 'p'},
>    {GETOPT_HELP_OPTION_DECL},
>    {GETOPT_VERSION_OPTION_DECL},
>    {NULL, 0, NULL, 0}
> @@ -65,6 +69,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 pipe signals\n\
>  "), stdout);
>        fputs (HELP_OPTION_DESCRIPTION, stdout);
>        fputs (VERSION_OPTION_DESCRIPTION, stdout);
> @@ -93,8 +98,9 @@ main (int argc, char **argv)
> 
>    append = false;
>    ignore_interrupts = false;
> +  ignore_sigpipes = 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)
>          {
> @@ -106,6 +112,10 @@ main (int argc, char **argv)
>            ignore_interrupts = true;
>            break;
> 
> +        case 'p':
> +          ignore_sigpipes = true;
> +          break;
> +
>          case_GETOPT_HELP_CHAR;
> 
>          case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
> @@ -116,7 +126,14 @@ main (int argc, char **argv)
>      }
> 
>    if (ignore_interrupts)
> +    {
>      signal (SIGINT, SIG_IGN);
> +    }
> +
> +  if (ignore_sigpipes)
> +    {
> +    signal (SIGPIPE, SIG_IGN);
> +    }
> 
>    /* Do *not* warn if tee is given no file arguments.
>       POSIX requires that it work when given no arguments.  */

I checked back and there was a very similar patch nearly 4 years ago.
http://lists.gnu.org/archive/html/bug-coreutils/2008-10/msg00067.html
I think there was general agreement in the thread on its merits.

I wonder though, would a higher level option be more appropriate?
I think what's being configured here is whether to exit early on write error,
whether it is to one of the files or stdout. Why would you want
to treat them differently? Also you could get SIGPIPEs I think
if one of the files was >(a process).

The default would be to diagnose write errors,
and that could be changed with:

--write-error={[cont],ignore,exit}

cheers,
Pádraig.