autoconf: Signal Handling

1 
1 11.5 Signal Handling
1 ====================
1 
1 Portable handling of signals within the shell is another major source of
1 headaches.  This is worsened by the fact that various different,
1 mutually incompatible approaches are possible in this area, each with
1 its distinctive merits and demerits.  A detailed description of these
1 possible approaches, as well as of their pros and cons, can be found in
1 this article (http://www.cons.org/cracauer/sigint.html).
1 
1    Solaris 10 `/bin/sh' automatically traps most signals by default;
1 the shell still exits with error upon termination by one of those
1 signals, but in such a case the exit status might be somewhat
1 unexpected (even if allowed by POSIX, strictly speaking):
1 
1      $ bash -c 'kill -1 $$'; echo $? # Will exit 128 + (signal number).
1      Hangup
1      129
1      $ /bin/ksh -c 'kill -15 $$'; echo $? # Likewise.
1      Terminated
1      143
1      $ for sig in 1 2 3 15; do
1      >   echo $sig:
1      >   /bin/sh -c "kill -$s \$\$"; echo $?
1      > done
1      signal 1:
1      Hangup
1      129
1      signal 2:
1      208
1      signal 3:
1      208
1      signal 15:
1      208
1 
1    This gets even worse if one is using the POSIX `wait' interface to
1 get details about the shell process terminations: it will result in the
1 shell having exited normally, rather than by receiving a signal.
1 
1      $ cat > foo.c <<'END'
1      #include <stdio.h>    /* for printf */
1      #include <stdlib.h>   /* for system */
1      #include <sys/wait.h> /* for WIF* macros */
1      int main(void)
1      {
1        int status = system ("kill -15 $$");
1        printf ("Terminated by signal: %s\n",
1                WIFSIGNALED (status) ? "yes" : "no");
1        printf ("Exited normally: %s\n",
1                WIFEXITED (status) ? "yes" : "no");
1        return 0;
1      }
1      END
1      $ cc -o foo foo.c
1      $ ./a.out # On GNU/Linux
1      Terminated by signal: no
1      Exited normally: yes
1      $ ./a.out # On Solaris 10
1      Terminated by signal: yes
1      Exited normally: no
1 
1    Various shells seem to handle `SIGQUIT' specially: they ignore it
1 even if it is not blocked, and even if the shell is not running
1 interactively (in fact, even if the shell has no attached tty); among
1 these shells are at least Bash (from version 2 onwards), Zsh 4.3.12,
1 Solaris 10 `/bin/ksh' and `/usr/xpg4/bin/sh', and AT&T `ksh93' (2011).
1 Still, `SIGQUIT' seems to be trappable quite portably within all these
1 shells.  OTOH, some other shells doesn't special-case the handling of
1 `SIGQUIT'; among these shells are at least `pdksh' 5.2.14, Solaris 10
1 and NetBSD 5.1 `/bin/sh', and the Almquist Shell 0.5.5.1.
1 
1    Some shells (especially Korn shells and derivatives) might try to
1 propagate to themselves a signal that has killed a child process; this
1 is not a bug, but a conscious design choice (although its overall value
1 might be debatable).  The exact details of how this is attained vary
1 from shell to shell.  For example, upon running `perl -e 'kill 2, $$'',
1 after the perl process has been interrupted AT&T `ksh93' (2011) will
1 proceed to send itself a `SIGINT', while Solaris 10 `/bin/ksh' and
1 `/usr/xpg4/bin/sh' will proceed to exit with status 130 (i.e., 128 +
1 2). In any case, if there is an active trap associated with `SIGINT',
1 those shells will correctly execute it.
1 
1    Some Korn shells, when a child process die due receiving a signal
1 with signal number N, can leave in `$?' an exit status of 256+N instead
1 of the more common 128+N.  Observe the difference between AT&T `ksh93'
1 (2011) and `bash' 4.1.5 on Debian:
1 
1      $ /bin/ksh -c 'sh -c "kill -1 \$\$"; echo $?'
1      /bin/ksh: line 1: 7837: Hangup
1      257
1      $ /bin/bash -c 'sh -c "kill -1 \$\$"; echo $?'
1      /bin/bash: line 1:  7861 Hangup        (sh -c "kill -1 \$\$")
1      129
1 
1 This `ksh' behavior is allowed by POSIX, if implemented with due care;
1 see this Austin Group discussion
1 (http://www.austingroupbugs.net/view.php?id=51) for more background.
1 However, if it is not implemented with proper care, such a behavior
1 might cause problems in some corner cases.  To see why, assume we have
1 a "wrapper" script like this:
1 
1      #!/bin/sh
1      # Ignore some signals in the shell only, not in its child processes.
1      trap : 1 2 13 15
1      wrapped_command "$@"
1      ret=$?
1      other_command
1      exit $ret
1 
1 If `wrapped_command' is interrupted by a `SIGHUP' (which has signal
1 number 1), `ret' will be set to 257.  Unless the `exit' shell builtin
1 is smart enough to understand that such a value can only have
1 originated from a signal, and adjust the final wait status of the shell
1 appropriately, the value 257 will just get truncated to 1 by the
1 closing `exit' call, so that a caller of the script will have no way to
1 determine that termination by a signal was involved.  Observe the
1 different behavior of AT&T `ksh93' (2011) and `bash' 4.1.5 on Debian:
1 
1      $ cat foo.sh
1      #!/bin/sh
1      sh -c 'kill -1 $$'
1      ret=$?
1      echo $ret
1      exit $ret
1      $ /bin/ksh foo.sh; echo $?
1      foo.sh: line 2: 12479: Hangup
1      257
1      1
1      $ /bin/bash foo.sh; echo $?
1      foo.sh: line 2: 12487 Hangup        (sh -c 'kill -1 $$')
1      129
1      129
1