aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2011-05-11 11:49:21 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2011-05-11 11:49:21 +0200
commit10c0131a8a1b3db7fd6b23b72ebd7b33afc7b018 (patch)
tree88b6afcd3614a43db767780f48a288d868cf2289
parent12bc152b31420c3e3d441c87a995fe7b65dd23fe (diff)
downloadbusybox-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>
-rw-r--r--shell/hush.c37
-rw-r--r--shell/shell_common.c34
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;