hush: unblock TERM, INT, HUP in child shells too.

This commit is contained in:
Denis Vlasenko 2009-04-17 13:52:51 +00:00
parent f8c1f02d2f
commit e4bd4f2cc8

View File

@ -1022,6 +1022,15 @@ static void free_strings(char **strings)
* are to count SIGCHLDs [disabled - bug somewhere, + bloat] * are to count SIGCHLDs [disabled - bug somewhere, + bloat]
* and to restore tty pgrp on signal-induced exit. * and to restore tty pgrp on signal-induced exit.
*/ */
enum {
SPECIAL_INTERACTIVE_SIGS = 0
#if ENABLE_HUSH_JOB
| (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
#endif
| (1 << SIGTERM)
//TODO | (1 << SIGHUP)
| (1 << SIGINT)
};
//static void SIGCHLD_handler(int sig UNUSED_PARAM) //static void SIGCHLD_handler(int sig UNUSED_PARAM)
//{ //{
@ -1059,6 +1068,8 @@ static int check_and_run_traps(int sig)
// G.count_SIGCHLD++; // G.count_SIGCHLD++;
// break; // break;
case SIGINT: case SIGINT:
//TODO: add putchar('\n') also when we detect that child was killed (sleep 5 + ^C)
/* Builtin was ^C'ed, make it look prettier: */
bb_putchar('\n'); bb_putchar('\n');
G.flag_SIGINT = 1; G.flag_SIGINT = 1;
break; break;
@ -2284,37 +2295,46 @@ void re_execute_shell(char ***to_free, const char *s, char *argv0, char **argv);
static void reset_traps_to_defaults(void) static void reset_traps_to_defaults(void)
{ {
enum { /* This function is always called in a child shell
JOBSIGS = (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP) * after fork (not vfork, NOMMU doesn't use this function).
};
unsigned sig;
if (!G.traps && !(G.non_DFL_mask & JOBSIGS))
return;
/* This function is always called in a child shell.
* Child shells are not interactive. * Child shells are not interactive.
* SIGTTIN/SIGTTOU/SIGTSTP should not have special handling. * SIGTTIN/SIGTTOU/SIGTSTP should not have special handling.
* Testcase: (while :; do :; done) + ^Z should background. * Testcase: (while :; do :; done) + ^Z should background.
* Same goes for SIGTERM, SIGHUP, SIGINT.
*/ */
G.non_DFL_mask &= ~JOBSIGS; unsigned sig;
sigdelset(&G.blocked_set, SIGTTIN); unsigned mask;
sigdelset(&G.blocked_set, SIGTTOU);
sigdelset(&G.blocked_set, SIGTSTP);
if (G.traps) for (sig = 0; sig < NSIG; sig++) { if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS))
if (!G.traps[sig]) { return;
continue;
/* Stupid. It can be done with *single* &= op, but we can't use
* the fact that G.blocked_set is implemented as a bitmask... */
mask = (SPECIAL_INTERACTIVE_SIGS >> 1);
sig = 1;
while (1) {
if (mask & 1)
sigdelset(&G.blocked_set, sig);
mask >>= 1;
if (!mask)
break;
sig++;
} }
G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS;
mask = G.non_DFL_mask;
if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) {
if (!G.traps[sig])
continue;
free(G.traps[sig]); free(G.traps[sig]);
G.traps[sig] = NULL; G.traps[sig] = NULL;
/* There is no signal for 0 (EXIT) */ /* There is no signal for 0 (EXIT) */
if (sig == 0) if (sig == 0)
continue; continue;
/* there was a trap handler, we are removing it /* There was a trap handler, we are removing it.
* (if sig has non-DFL handling, * But if sig still has non-DFL handling,
* we don't need to do anything) */ * we should not unblock it. */
if (sig < 32 && (G.non_DFL_mask & (1 << sig))) if (mask & 1)
continue; continue;
sigdelset(&G.blocked_set, sig); sigdelset(&G.blocked_set, sig);
} }
@ -5740,17 +5760,8 @@ static void block_signals(int second_time)
unsigned mask; unsigned mask;
mask = (1 << SIGQUIT); mask = (1 << SIGQUIT);
if (G_interactive_fd) { if (G_interactive_fd)
mask = 0 mask = (1 << SIGQUIT) | SPECIAL_INTERACTIVE_SIGS;
| (1 << SIGQUIT)
| (1 << SIGTERM)
//TODO | (1 << SIGHUP)
#if ENABLE_HUSH_JOB
| (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
#endif
| (1 << SIGINT)
;
}
G.non_DFL_mask = mask; G.non_DFL_mask = mask;
if (!second_time) if (!second_time)