hush: stop ignoring ^Z in child shells
authorDenis Vlasenko <vda.linux@googlemail.com>
Wed, 15 Apr 2009 23:29:44 +0000 (23:29 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Wed, 15 Apr 2009 23:29:44 +0000 (23:29 -0000)
shell/hush.c

index 16f304d81ad9163cde9c3333ba3cc6504b49f422..a5d5741da162a6c2716c5e5043d8c8a73501f3c5 100644 (file)
@@ -2276,15 +2276,28 @@ void re_execute_shell(char ***to_free, const char *s, char *argv0, char **argv);
 
 static void reset_traps_to_defaults(void)
 {
+       enum {
+               JOBSIGS = (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
+       };
        unsigned sig;
-       int dirty;
 
-       if (!G.traps)
+       if (!G.traps && !(G.non_DFL_mask & JOBSIGS))
                return;
-       dirty = 0;
-       for (sig = 0; sig < NSIG; sig++) {
-               if (!G.traps[sig])
+
+       /* This function is always called in a child shell.
+        * Child shells are not interactive.
+        * SIGTTIN/SIGTTOU/SIGTSTP should not have special handling.
+        * Testcase: (while :; do :; done) + ^Z should background.
+        */
+       G.non_DFL_mask &= ~JOBSIGS;
+       sigdelset(&G.blocked_set, SIGTTIN);
+       sigdelset(&G.blocked_set, SIGTTOU);
+       sigdelset(&G.blocked_set, SIGTSTP);
+
+       if (G.traps) for (sig = 0; sig < NSIG; sig++) {
+               if (!G.traps[sig]) {
                        continue;
+               }
                free(G.traps[sig]);
                G.traps[sig] = NULL;
                /* There is no signal for 0 (EXIT) */
@@ -2296,10 +2309,8 @@ static void reset_traps_to_defaults(void)
                if (sig < 32 && (G.non_DFL_mask & (1 << sig)))
                        continue;
                sigdelset(&G.blocked_set, sig);
-               dirty = 1;
        }
-       if (dirty)
-               sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
+       sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
 }
 
 #else /* !BB_MMU */