diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-11 11:49:21 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-11 11:49:21 +0200 |
| commit | 10c0131a8a1b3db7fd6b23b72ebd7b33afc7b018 (patch) | |
| tree | 88b6afcd3614a43db767780f48a288d868cf2289 /shell | |
| parent | 12bc152b31420c3e3d441c87a995fe7b65dd23fe (diff) | |
| download | busybox-w32-10c0131a8a1b3db7fd6b23b72ebd7b33afc7b018.tar.gz busybox-w32-10c0131a8a1b3db7fd6b23b72ebd7b33afc7b018.tar.bz2 busybox-w32-10c0131a8a1b3db7fd6b23b72ebd7b33afc7b018.zip | |
hush: use SA_RESTARTed signal handlers across read.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 37 | ||||
| -rw-r--r-- | shell/shell_common.c | 34 |
2 files changed, 42 insertions, 29 deletions
diff --git a/shell/hush.c b/shell/hush.c index 71972f751..509bd415b 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -792,8 +792,13 @@ struct globals { | |||
| 792 | unsigned handled_SIGCHLD; | 792 | unsigned handled_SIGCHLD; |
| 793 | smallint we_have_children; | 793 | smallint we_have_children; |
| 794 | #endif | 794 | #endif |
| 795 | /* which signals have non-DFL handler (even with no traps set)? */ | 795 | /* Which signals have non-DFL handler (even with no traps set)? |
| 796 | unsigned non_DFL_mask; | 796 | * Set at the start to: |
| 797 | * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOB_SIGS) | ||
| 798 | * SPECIAL_INTERACTIVE_SIGS are cleared after fork. | ||
| 799 | * Other than these two times, never modified. | ||
| 800 | */ | ||
| 801 | unsigned special_sig_mask; | ||
| 797 | char **traps; /* char *traps[NSIG] */ | 802 | char **traps; /* char *traps[NSIG] */ |
| 798 | /* Signal mask on the entry to the (top-level) shell. Never modified. */ | 803 | /* Signal mask on the entry to the (top-level) shell. Never modified. */ |
| 799 | sigset_t inherited_set; | 804 | sigset_t inherited_set; |
| @@ -1341,11 +1346,11 @@ static void restore_G_args(save_arg_t *sv, char **argv) | |||
| 1341 | * After each pipe execution, we extract any pending signals via sigtimedwait() | 1346 | * After each pipe execution, we extract any pending signals via sigtimedwait() |
| 1342 | * and act on them. | 1347 | * and act on them. |
| 1343 | * | 1348 | * |
| 1344 | * unsigned non_DFL_mask: a mask of such "special" signals | 1349 | * unsigned special_sig_mask: a mask of such "special" signals |
| 1345 | * sigset_t blocked_set: current blocked signal set | 1350 | * sigset_t blocked_set: current blocked signal set |
| 1346 | * | 1351 | * |
| 1347 | * "trap - SIGxxx": | 1352 | * "trap - SIGxxx": |
| 1348 | * clear bit in blocked_set unless it is also in non_DFL_mask | 1353 | * clear bit in blocked_set unless it is also in special_sig_mask |
| 1349 | * "trap 'cmd' SIGxxx": | 1354 | * "trap 'cmd' SIGxxx": |
| 1350 | * set bit in blocked_set (even if 'cmd' is '') | 1355 | * set bit in blocked_set (even if 'cmd' is '') |
| 1351 | * after [v]fork, if we plan to be a shell: | 1356 | * after [v]fork, if we plan to be a shell: |
| @@ -5376,7 +5381,7 @@ static void reset_traps_to_defaults(void) | |||
| 5376 | * Testcase: (while :; do :; done) + ^Z should background. | 5381 | * Testcase: (while :; do :; done) + ^Z should background. |
| 5377 | * Same goes for SIGTERM, SIGHUP, SIGINT. | 5382 | * Same goes for SIGTERM, SIGHUP, SIGINT. |
| 5378 | */ | 5383 | */ |
| 5379 | if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS)) | 5384 | if (!G.traps && !(G.special_sig_mask & SPECIAL_INTERACTIVE_SIGS)) |
| 5380 | return; /* already no traps and no SPECIAL_INTERACTIVE_SIGS */ | 5385 | return; /* already no traps and no SPECIAL_INTERACTIVE_SIGS */ |
| 5381 | 5386 | ||
| 5382 | /* Switching off SPECIAL_INTERACTIVE_SIGS. | 5387 | /* Switching off SPECIAL_INTERACTIVE_SIGS. |
| @@ -5394,10 +5399,10 @@ static void reset_traps_to_defaults(void) | |||
| 5394 | } | 5399 | } |
| 5395 | } | 5400 | } |
| 5396 | /* Our homegrown sig mask is saner to work with :) */ | 5401 | /* Our homegrown sig mask is saner to work with :) */ |
| 5397 | G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS; | 5402 | G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS; |
| 5398 | 5403 | ||
| 5399 | /* Resetting all traps to default except empty ones */ | 5404 | /* Resetting all traps to default except empty ones */ |
| 5400 | mask = G.non_DFL_mask; | 5405 | mask = G.special_sig_mask; |
| 5401 | if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) { | 5406 | if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) { |
| 5402 | if (!G.traps[sig] || !G.traps[sig][0]) | 5407 | if (!G.traps[sig] || !G.traps[sig][0]) |
| 5403 | continue; | 5408 | continue; |
| @@ -7440,9 +7445,6 @@ static void init_sigmasks(void) | |||
| 7440 | 7445 | ||
| 7441 | /* POSIX allows shell to re-enable SIGCHLD | 7446 | /* POSIX allows shell to re-enable SIGCHLD |
| 7442 | * even if it was SIG_IGN on entry */ | 7447 | * even if it was SIG_IGN on entry */ |
| 7443 | #if ENABLE_HUSH_FAST | ||
| 7444 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ | ||
| 7445 | #endif | ||
| 7446 | if (!G.inherited_set_is_saved) { | 7448 | if (!G.inherited_set_is_saved) { |
| 7447 | #if ENABLE_HUSH_FAST | 7449 | #if ENABLE_HUSH_FAST |
| 7448 | signal(SIGCHLD, SIGCHLD_handler); | 7450 | signal(SIGCHLD, SIGCHLD_handler); |
| @@ -7460,7 +7462,7 @@ static void init_sigmasks(void) | |||
| 7460 | if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ | 7462 | if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ |
| 7461 | mask |= SPECIAL_JOB_SIGS; | 7463 | mask |= SPECIAL_JOB_SIGS; |
| 7462 | } | 7464 | } |
| 7463 | G.non_DFL_mask = mask; | 7465 | G.special_sig_mask = mask; |
| 7464 | 7466 | ||
| 7465 | /* Block them. And unblock SIGCHLD */ | 7467 | /* Block them. And unblock SIGCHLD */ |
| 7466 | sig = 0; | 7468 | sig = 0; |
| @@ -7504,10 +7506,10 @@ static void set_fatal_handlers_to_sigexit(void) | |||
| 7504 | /*+ (1 << SIGINT )*/ | 7506 | /*+ (1 << SIGINT )*/ |
| 7505 | ; | 7507 | ; |
| 7506 | 7508 | ||
| 7507 | /* non_DFL_mask'ed signals are, well, masked, | 7509 | /* special_sig_mask'ed signals are, well, masked, |
| 7508 | * no need to set handler for them. | 7510 | * no need to set handler for them. |
| 7509 | */ | 7511 | */ |
| 7510 | fatal_sigs &= ~G.non_DFL_mask; | 7512 | fatal_sigs &= ~G.special_sig_mask; |
| 7511 | 7513 | ||
| 7512 | /* For each sig in fatal_sigs... */ | 7514 | /* For each sig in fatal_sigs... */ |
| 7513 | sig = 0; | 7515 | sig = 0; |
| @@ -7571,8 +7573,11 @@ int hush_main(int argc, char **argv) | |||
| 7571 | struct variable *shell_ver; | 7573 | struct variable *shell_ver; |
| 7572 | 7574 | ||
| 7573 | INIT_G(); | 7575 | INIT_G(); |
| 7574 | if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */ | 7576 | if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ |
| 7575 | G.last_exitcode = EXIT_SUCCESS; | 7577 | G.last_exitcode = EXIT_SUCCESS; |
| 7578 | #if ENABLE_HUSH_FAST | ||
| 7579 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ | ||
| 7580 | #endif | ||
| 7576 | #if !BB_MMU | 7581 | #if !BB_MMU |
| 7577 | G.argv0_for_re_execing = argv[0]; | 7582 | G.argv0_for_re_execing = argv[0]; |
| 7578 | #endif | 7583 | #endif |
| @@ -8303,7 +8308,7 @@ static int FAST_FUNC builtin_trap(char **argv) | |||
| 8303 | /* There was a trap handler, we are removing it | 8308 | /* There was a trap handler, we are removing it |
| 8304 | * (if sig has non-DFL handling, | 8309 | * (if sig has non-DFL handling, |
| 8305 | * we don't need to do anything) */ | 8310 | * we don't need to do anything) */ |
| 8306 | if (sig < 32 && (G.non_DFL_mask & (1 << sig))) | 8311 | if (sig < sizeof(G.special_sig_mask)*8 && (G.special_sig_mask & (1 << sig))) |
| 8307 | continue; | 8312 | continue; |
| 8308 | sigdelset(&G.blocked_set, sig); | 8313 | sigdelset(&G.blocked_set, sig); |
| 8309 | } | 8314 | } |
| @@ -8565,7 +8570,7 @@ static int FAST_FUNC builtin_read(char **argv) | |||
| 8565 | 8570 | ||
| 8566 | memset(&sa, 0, sizeof(sa)); | 8571 | memset(&sa, 0, sizeof(sa)); |
| 8567 | sigfillset(&sa.sa_mask); | 8572 | sigfillset(&sa.sa_mask); |
| 8568 | /*sa.sa_flags = 0;*/ | 8573 | sa.sa_flags = SA_RESTART; |
| 8569 | sa.sa_handler = record_signal; | 8574 | sa.sa_handler = record_signal; |
| 8570 | 8575 | ||
| 8571 | sig = 0; | 8576 | sig = 0; |
diff --git a/shell/shell_common.c b/shell/shell_common.c index a5c455c8e..bbc22ed34 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
| @@ -159,32 +159,40 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
| 159 | bufpos = 0; | 159 | bufpos = 0; |
| 160 | do { | 160 | do { |
| 161 | char c; | 161 | char c; |
| 162 | struct pollfd pfd[1]; | ||
| 163 | int timeout; | ||
| 162 | 164 | ||
| 163 | errno = 0; | 165 | if ((bufpos & 0xff) == 0) |
| 166 | buffer = xrealloc(buffer, bufpos + 0x100); | ||
| 164 | 167 | ||
| 168 | timeout = -1; | ||
| 165 | if (end_ms) { | 169 | if (end_ms) { |
| 166 | int timeout; | ||
| 167 | struct pollfd pfd[1]; | ||
| 168 | |||
| 169 | pfd[0].fd = fd; | ||
| 170 | pfd[0].events = POLLIN; | ||
| 171 | timeout = end_ms - (unsigned)monotonic_ms(); | 170 | timeout = end_ms - (unsigned)monotonic_ms(); |
| 172 | if (timeout <= 0 /* already late? */ | 171 | if (timeout <= 0) { /* already late? */ |
| 173 | || poll(pfd, 1, timeout) != 1 /* no? wait... */ | ||
| 174 | ) { /* timed out! */ | ||
| 175 | err = errno; | ||
| 176 | retval = (const char *)(uintptr_t)1; | 172 | retval = (const char *)(uintptr_t)1; |
| 177 | goto ret; | 173 | goto ret; |
| 178 | } | 174 | } |
| 179 | } | 175 | } |
| 180 | 176 | ||
| 181 | if ((bufpos & 0xff) == 0) | 177 | /* We must poll even if timeout is -1: |
| 182 | buffer = xrealloc(buffer, bufpos + 0x100); | 178 | * we want to be interrupted if signal arrives, |
| 183 | if (nonblock_immune_read(fd, &buffer[bufpos], 1, /*loop_on_EINTR:*/ 0) != 1) { | 179 | * regardless of SA_RESTART-ness of that signal! |
| 180 | */ | ||
| 181 | errno = 0; | ||
| 182 | pfd[0].fd = fd; | ||
| 183 | pfd[0].events = POLLIN; | ||
| 184 | if (poll(pfd, 1, timeout) != 1) { | ||
| 185 | /* timed out, or EINTR */ | ||
| 186 | err = errno; | ||
| 187 | retval = (const char *)(uintptr_t)1; | ||
| 188 | goto ret; | ||
| 189 | } | ||
| 190 | if (read(fd, &buffer[bufpos], 1) != 1) { | ||
| 184 | err = errno; | 191 | err = errno; |
| 185 | retval = (const char *)(uintptr_t)1; | 192 | retval = (const char *)(uintptr_t)1; |
| 186 | break; | 193 | break; |
| 187 | } | 194 | } |
| 195 | |||
| 188 | c = buffer[bufpos]; | 196 | c = buffer[bufpos]; |
| 189 | if (c == '\0') | 197 | if (c == '\0') |
| 190 | continue; | 198 | continue; |
