On 10/15/19 5:22 AM, Isaac To wrote: > Bash Version: 5.0 > Patch Level: 3 > Release Status: release > > Description: > > When trying to write a program and start it in an initrc script, I observed > a strange behavior: if a subshell is started by a subshell of that script, > and the inner subshell runs "trap ... EXIT", it unsets the signal ignore > flag of other signals. I'm not sure whether this should be called a bug, > or whether it is a problem caused by my own configuration. Anyway here is > how I reproduce my problem.
OK, let's go through what happens to signals when you run this. > $ cat t.sh > echo t $BASHPID > trap '' USR1 This bash process, lets say pid 806, sets the disposition of SIGUSR1 to SIG_IGN. > grep SigIgn /proc/$BASHPID/status Presumably this reflects it; I don't know how to interpret the output. > bash --rcfile t2.sh You start an interactive shell, say pid 809. This means that the shell remembers that SIGUSR1 was ignored when it started but sets the handler to a fatal signal catcher function. It will set the disposition to SIG_IGN in a child proess immediately after it forks. This means, for instance, that the greps run with SIGUSR1 set to SIG_IGN. The other thing an interactive shell does is catch all fatal signals so it can clean up. This means that a subshell has to undo this by setting all these signals to SIG_DFL when it starts. Since this shell is interactive, all subshells it runs know they are children of an interactive shell. > $ cat t2.sh > echo t2 $BASHPID > grep SigIgn /proc/$BASHPID/status This gives you the normal set of ignored signals for an interactive shell: SIGQUIT/SIGTSTP/SIGTTOU/SIGTTIN. SIGUSR1, a fatal signal, is caught. > ( > echo subshell $BASHPID > grep SigIgn /proc/$BASHPID/status After setting all the caught signals back to SIG_DFL, this shell, call it pid 811, sets SIGUSR1 to SIG_IGN, since that is the disposition it had when its parent was started. This happens before pretty much anything else. Bash will install signal handlers for everything it needs to catch, and, since this is still an interactive shell, it will catch signals that are ignored when it starts. It does this lazily -- when it needs to do something with signal handlers. This turns out to matter; see below. > ( > echo subsubshell $BASHPID Let's say this process has pid 813. In this subshell, there shouldn't be any ignored signals after the shell initializes (it's interactive), but it does this lazily. This is probably where the confusion arises. It's arguably a bug that bash doesn't change the signals to caught right away. > grep SigIgn /proc/$BASHPID/status > echo trap $BASHPID > trap 'echo hello' EXIT When the exit trap is installed, bash needs to install handlers for all the fatal signals, so it can run the exit trap (if possible) if it receives one. Since it's an interactive shell, it installs handlers for everything, even signals, like SIGUSR1, that were ignored when the shell started. Once it's done that, there are no longer any ignored signals. > Note that the final SigIgn flag is completely reset, which is what I won't > expect. The same problem won't occur if --rcfile is not used in t.sh. And > the problem also didn't show up in bash 4.4. I get exactly the same results in bash-4.4 running on RHEL7. -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, UTech, CWRU c...@case.edu http://tiswww.cwru.edu/~chet/