groff
[Top][All Lists]
Advanced

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

the exquisite pain of signal handling in shell scripts


From: G. Branden Robinson
Subject: the exquisite pain of signal handling in shell scripts
Date: Fri, 1 May 2020 04:48:54 +1000
User-agent: NeoMutt/20180716

[was: Potential enhancements to install-font.sh from
 https://www.schaffter.ca/mom/bin/install-font.sh]

At 2020-04-30T12:20:20-0400, Peter Schaffter wrote:
> On Wed, Apr 29, 2020, James K. Lowden wrote:
> > I just took a look, Peter, because I have some experience writing
> > Bourne shell scripts.  I don't see anything bash-specific, just
> > looking over it.  You might just change #!/bin/bash to #!/bin/sh;
> > I think it will run pretty well, maybe perfectly.
> 
> On Debian derivatives, dash(1) has a bug in its signal handling,
> hence !#/bin/bash rather than the generic !#/bin/sh.

I noticed the same thing, hence the comment in that same script I
pointed to earlier[1].  The bug has escaped the Debian sandbox and is
wreaking havoc elsewhere:

        # Note: This script uses bash for its execution, but not because
        # it uses any Bashisms; instead, it is to work around a
        # POSIX-violating bug in signal handling in dash, which is the
        # /bin/sh on most Debian-based systems.  See
        # <https://bugs.debian.org/779416>, filed in 2015 and still not
        # fixed (posh has the same problem; ksh, mksh, yash, and zsh do
        # not).

> In turn, bash(1) requires the bash-specific 'set -o posix' in order
> for ctrl-C to work.

This, I did not find to be the case.  Hmm.  It seems like the main
difference between our signal handlers is that you do not reset the
handler, and rely on exiting with a status greater than 127 to notify
the shell that the process was killed with a signal.  I'm not sure that
is reliable, or supposed to be.  And that's no euphemism--I honestly
don't know.  When I try to understand this part of POSIX my mind becomes
a pretzel.  Here's what I do, and it has worked so far.

show_platform_help () {
[...]
    # We give `rm` the `-f` option in the trap handler in the event we
    # end up racing against the ordinary cleanup scenario.  Consider:
    #   # Clean up the temporary file and deregister the signal handler.
    #   rm "$TEMP"
    #   <CTRL-C>
    #   trap - HUP INT QUIT TERM
    # When the user interrupts the script, the temporary file has been
    # removed but the signal handler has not yet been deregistered.
[...]
    TEMP=$(mktemp)

    # In our trap handler, we have to (1) do our cleanup work; (2) clear
    # the trap handler (restoring the default signal handler); and (3)
    # commit suicide so that the shell knows we exited abnormally.
    # Unfortunately POSIX shell offers no way of knowing which signal we
    # are handling, short of writing the trap handler multiple times
    # (once for each signal); we choose INT as our final disposition
    # somewhat arbitrarily.
    #
    # See <https://www.cons.org/cracauer/sigint.html> for a detailed
    # exploration of this issue.
    trap 'rm -f "$TEMP"; trap - HUP INT QUIT TERM; kill -s INT $$' \
        HUP INT QUIT TERM

[...]
    # Clean up the temporary file and deregister the signal handler.
    rm "$TEMP"
    trap - HUP INT QUIT TERM
[...]
}

Note 1: The foregoing is why I have an extreme allergy to writing
temporaries to the file system in shell scripts.  I will jump through
flaming hoops with here documents and other contrivances to avoid this
mess.

Note 2: It may seem odd to some that I am registering and deregistering
signal handlers all within the context of one function, when their
effect is "global" to the script.  That is true and I am aware of it.
It is because this function is the only place in the entire script that
I needed to mess with traps at all, because of Note 1 above.  As far as
I understand, the function scope has no impact at all on the trap
semantics.  There is of course room for buggy implementations to
introduce some...

Regards,
Branden

[1] https://github.com/seL4/seL4_tools/blob/master/cmake-tool/griddle

Attachment: signature.asc
Description: PGP signature


reply via email to

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