diff options
author | Denys Vlasenko | 2020-02-18 16:46:01 +0100 |
---|---|---|
committer | Denys Vlasenko | 2020-02-18 16:46:01 +0100 |
commit | 23bc562a0556d1c0ddad4252fa8d46c863b5fa88 (patch) | |
tree | 3ad95cdddd273d569f55c57dcb6fe8f6ae488d51 | |
parent | 47eb979404735b9528538968cb5eaac7355a0c5a (diff) | |
download | busybox-23bc562a0556d1c0ddad4252fa8d46c863b5fa88.zip busybox-23bc562a0556d1c0ddad4252fa8d46c863b5fa88.tar.gz |
ash,hush: add comment about masked SIGCHLD, handle SIG_IGNed SIGHUP as in bash
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/ash.c | 26 | ||||
-rw-r--r-- | shell/hush.c | 20 |
2 files changed, 37 insertions, 9 deletions
diff --git a/shell/ash.c b/shell/ash.c index ff59405..fea4b10 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -4307,8 +4307,19 @@ wait_block_or_sig(int *status) #if 1 sigfillset(&mask); sigprocmask2(SIG_SETMASK, &mask); /* mask is updated */ - while (!got_sigchld && !pending_sig) + while (!got_sigchld && !pending_sig) { sigsuspend(&mask); + /* ^^^ add "sigdelset(&mask, SIGCHLD);" before sigsuspend + * to make sure SIGCHLD is not masked off? + * It was reported that this: + * fn() { : | return; } + * shopt -s lastpipe + * fn + * exec ash SCRIPT + * under bash 4.4.23 runs SCRIPT with SIGCHLD masked, + * making "wait" commands in SCRIPT block forever. + */ + } sigprocmask(SIG_SETMASK, &mask, NULL); #else /* unsafe: a signal can set pending_sig after check, but before pause() */ while (!got_sigchld && !pending_sig) @@ -14170,11 +14181,6 @@ init(void) sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ setsignal(SIGCHLD); - /* bash re-enables SIGHUP which is SIG_IGNed on entry. - * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" - */ - signal(SIGHUP, SIG_DFL); - { char **envp; const char *p; @@ -14512,6 +14518,14 @@ int ash_main(int argc UNUSED_PARAM, char **argv) } #endif state4: /* XXX ??? - why isn't this before the "if" statement */ + + /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry. + * Try: + * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect + * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed + */ + signal(SIGHUP, SIG_DFL); + cmdloop(1); } #if PROFILE diff --git a/shell/hush.c b/shell/hush.c index 6e44d4e..bced388 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -9775,10 +9775,14 @@ static void install_sighandlers(unsigned mask) */ if (sig == SIGCHLD) continue; - /* bash re-enables SIGHUP which is SIG_IGNed on entry. - * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" + /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry. + * Try: + * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect + * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed */ - //if (sig == SIGHUP) continue; - TODO? + if (sig == SIGHUP && G_interactive_fd) + continue; + /* Unless one of the above signals, is it SIG_IGN? */ if (old_handler == SIG_IGN) { /* oops... restore back to IGN, and record this fact */ install_sighandler(sig, old_handler); @@ -11554,6 +11558,16 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid /* It is vitally important for sigsuspend that SIGCHLD has non-DFL handler! */ /* Note: sigsuspend invokes signal handler */ sigsuspend(&oldset); + /* ^^^ add "sigdelset(&oldset, SIGCHLD)" before sigsuspend + * to make sure SIGCHLD is not masked off? + * It was reported that this: + * fn() { : | return; } + * shopt -s lastpipe + * fn + * exec hush SCRIPT + * under bash 4.4.23 runs SCRIPT with SIGCHLD masked, + * making "wait" commands in SCRIPT block forever. + */ restore: sigprocmask(SIG_SETMASK, &oldset, NULL); check_sig: |