The discussion around SIGPIPE (on this list and on bug-coreutils) around 2008-06-30 convinced me that in general the reasonable reaction on SIGPIPE is: - if the program only produces output to stdout, then the default behaviour (terminate the process without an error message) is the right thing; - if the program also does side effects, then the program should either exit with an error message or continue the operation, ignoring the SIGPIPE.
For the latter case, an ad-hoc coding is necessary. But for the former case, it's possible to write the code once only. I'm adding a module 'sigpipe-die' for this purpose, similar to 'xalloc-die'. Comments welcome, as always. 2008-08-31 Bruno Haible <[EMAIL PROTECTED]> New module 'sigpipe-die'. * modules/sigpipe-die: New file. * lib/sigpipe-die.h: New file. * lib/sigpipe-die.c: New file. * MODULES.html.sh (Signal handling): Add sigpipe-die. ========================== modules/sigpipe-die ============================= Description: Report a SIGPIPE signal and exit. Files: lib/sigpipe-die.h lib/sigpipe-die.c Depends-on: error gettext-h exitfail sigprocmask sigaction configure.ac: Makefile.am: lib_SOURCES += sigpipe-die.h sigpipe-die.c Include: "sigpipe-die.h" License: GPL Maintainer: Bruno Haible =========================== lib/sigpipe-die.h ============================== /* Report a SIGPIPE signal and exit. Copyright (C) 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 the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* Written by Bruno Haible <[EMAIL PROTECTED]>, 2008. */ /* SIGPIPE is the signal sent to a process calling write() on a pipe with no readers. Together with the signal, the write() call is terminated with return value -1, errno = EPIPE. Note that SIGPIPE is a *synchronous* signal: it occurs only during write(), without delay (unless blocked). The default reaction on SIGPIPE, namely terminating the process without an error message, is suitable for programs which only produce output to standard output and don't have side effects. When a program has side effects, other than writing to standard output, the suitable behaviour is either (a) to exit with an error message or - in certain cases, for example when writing to subprocesses - (b) to continue the operation without writing to the pipe/socket with no readers. This file provides support for (a). For (b), the program needs to know which of the output file descriptors has no readers. This is usually implemented by blocking the SIGPIPE signal and handling an EPIPE error indicator in all affected library calls (write(), send(), fwrite(), fflush(), fclose(), etc.). */ #ifndef _SIGPIPE_DIE_H #define _SIGPIPE_DIE_H #ifdef __cplusplus extern "C" { #endif # ifndef __attribute__ # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) # define __attribute__(x) # endif # endif # ifndef ATTRIBUTE_NORETURN # define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) # endif /* Emit an error message indicating a SIGPIPE signal, and terminate the process with an error code. */ extern void sigpipe_die (void) ATTRIBUTE_NORETURN; /* Install a SIGPIPE handler that invokes PREPARE_DIE and then emits an error message and exits. PREPARE_DIE may be NULL, meaning a no-op. */ extern void install_sigpipe_die_handler (void (*prepare_die) (void)); #ifdef __cplusplus } #endif #endif /* _SIGPIPE_DIE_H */ =========================== lib/sigpipe-die.c ============================== /* Report a SIGPIPE signal and exit. Copyright (C) 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 the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* Written by Bruno Haible <[EMAIL PROTECTED]>, 2008. */ #include <config.h> /* Specification. */ #include "sigpipe-die.h" #include <signal.h> #include <stdlib.h> #include "error.h" #include "exitfail.h" #include "gettext.h" #define _(msgid) gettext (msgid) void sigpipe_die (void) { error (exit_failure, 0, "%s", _("error writing to a closed pipe or socket")); /* Ensure that this function really does not return. */ abort (); } static void (*prepare_die_hook) (void); /* This is the signal handler for SIGPIPE. It is invoked synchronously, therefore it can make library calls to malloc(), gettext(), exit() etc. - although in general it is undefined behaviour to do such calls from within signal handlers. */ static void sigpipe_die_handler (int sig) { if (prepare_die_hook != NULL) (*prepare_die_hook) (); sigpipe_die (); } void install_sigpipe_die_handler (void (*prepare_die) (void)) { prepare_die_hook = prepare_die; /* Install the handler. */ { struct sigaction action; action.sa_handler = sigpipe_die_handler; action.sa_flags = 0; sigemptyset (&action.sa_mask); if (sigaction (SIGPIPE, &action, NULL) >= 0) { /* Unblock the signal (just in case). This is needed because if the signal was blocked in the parent process, it is also blocked in this process: the mask of blocked signals is inherited across fork/exec (except for SIGCHLD). */ sigset_t sigpipe_set; sigemptyset (&sigpipe_set); sigaddset (&sigpipe_set, SIGPIPE); sigprocmask (SIG_UNBLOCK, &sigpipe_set, NULL); } } } ============================================================================ *** MODULES.html.sh.orig 2008-08-31 16:10:39.000000000 +0200 --- MODULES.html.sh 2008-08-31 15:59:53.000000000 +0200 *************** *** 2390,2395 **** --- 2390,2396 ---- func_module c-stack func_module libsigsegv func_module sig2str + func_module sigpipe-die func_end_table element="Internationalization functions"