ash,hush: add comment about masked SIGCHLD, handle SIG_IGNed SIGHUP as in bash
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 18 Feb 2020 15:46:01 +0000 (16:46 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 18 Feb 2020 15:46:01 +0000 (16:46 +0100)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c
shell/hush.c

index ff594050ce6c157d352afb4b79bb941b10f488c6..fea4b10a7ab4bceb2d65c184184fa9473713617c 100644 (file)
@@ -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
index 6e44d4e115f1fc18a5d3d5f38c9488ec89930a9e..bced388bff797a5ae132b578736e0b5453b6a08c 100644 (file)
@@ -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: