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