bug-gnulib
[Top][All Lists]
Advanced

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

new module 'sigpipe-die'


From: Bruno Haible
Subject: new module 'sigpipe-die'
Date: Sun, 31 Aug 2008 16:17:15 +0200
User-agent: KMail/1.5.4

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  <address@hidden>

        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 <address@hidden>, 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 <address@hidden>, 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"





reply via email to

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