Bash – Prevent SIGINT from reaching child processes

bashprocesssignalstrap:

I have a bash script for running a server, which will typically be terminated by the user using Ctrl-C. On exit it runs a cleanup function, which I don't want to be interrupted by a second Ctrl-C.

#!/bin/bash

...

function cleanup {
    trap '' INT
    echo -n " Cleaning up..."
    scp $SRV:~/$DIR/server.log . && ssh -t $SRV "rm -rf ~/$DIR"
    echo " Finished."

    exit 0
}
trap cleanup EXIT

...

At the moment, a second Ctrl-C before the scp has finished causes the script to hang indefinitely. I understand this has something to do with the SIGINT being sent both to the bash script and the scp process, but I am at a loss as to why this causes the script to hang, rather than just causing cleanup to fail.

So my question is:

  1. Why does this cause the script to hang?
  2. How can I prevent the SIGINT from reaching the scp and ssh child processes?

Best Answer

trap '' INT is meant to ignore SIGINTs for the shell and all its children.

But looking at strace outputs on scp, it looks like scp installs its own SIGINT handler which cancels the SIG_IGN above.

The only way to prevent it from getting the SIGINT would be to run it in a different process group like with:

perl -MPOSIX -e 'setpgid 0,0; exec @ARGV' scp...

or

(set -m; scp ... & wait)

or tell the tty driver to stop sending SIGINT upon Ctrl-C (like with stty -isig, or stty intr '' for ^C alone), though you'd want to restore the settings afterwards:

saved=$(stty -g)
stty intr ''
scp ...
stty "$saved"