diff options
-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; |