aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2011-05-11 23:56:11 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2011-05-11 23:56:11 +0200
commit9d6cbafe728c9100a35e29ba7a3729c5303e73ea (patch)
tree585f11bce3f1afad08ad00453fe355a460f5fff1 /shell/hush.c
parent10c0131a8a1b3db7fd6b23b72ebd7b33afc7b018 (diff)
downloadbusybox-w32-9d6cbafe728c9100a35e29ba7a3729c5303e73ea.tar.gz
busybox-w32-9d6cbafe728c9100a35e29ba7a3729c5303e73ea.tar.bz2
busybox-w32-9d6cbafe728c9100a35e29ba7a3729c5303e73ea.zip
hush: replace signal handling machinery
With new version of signal handling, read builtin should be less buggy wrt signals. function old new delta install_sighandlers - 121 +121 switch_off_special_sigs - 84 +84 pick_sighandler - 58 +58 install_special_sighandlers - 47 +47 builtin_wait 284 319 +35 record_pending_signo - 21 +21 execvp_or_die 43 48 +5 file_get 290 288 -2 run_list 1004 998 -6 static.zero_timespec 8 - -8 sigprocmask_set 14 - -14 sigwaitinfo 23 - -23 record_signal 23 - -23 __GI_sigwaitinfo 23 - -23 sigtimedwait 25 - -25 builtin_trap 417 392 -25 __GI_sigtimedwait 25 - -25 hush_main 1003 965 -38 check_and_run_traps 263 217 -46 __rt_sigtimedwait 52 - -52 reset_traps_to_defaults 213 126 -87 init_sigmasks 198 - -198 builtin_read 536 197 -339 ------------------------------------------------------------------------------ (add/remove: 5/10 grow/shrink: 2/7 up/down: 371/-934) Total: -563 bytes text data bss dec hex filename 903075 936 17736 921747 e1093 busybox_old 902547 936 17736 921219 e0e83 busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to '')
-rw-r--r--shell/hush.c510
1 files changed, 278 insertions, 232 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 509bd415b..b2c3a752e 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -106,6 +106,10 @@
106# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 106# define PIPE_BUF 4096 /* amount of buffering in a pipe */
107#endif 107#endif
108 108
109/* Not every libc has sighandler_t. Fix it */
110typedef void (*hush_sighandler_t)(int);
111#define sighandler_t hush_sighandler_t
112
109//config:config HUSH 113//config:config HUSH
110//config: bool "hush" 114//config: bool "hush"
111//config: default y 115//config: default y
@@ -764,7 +768,6 @@ struct globals {
764 smalluint last_exitcode; 768 smalluint last_exitcode;
765 /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */ 769 /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */
766 smalluint global_args_malloced; 770 smalluint global_args_malloced;
767 smalluint inherited_set_is_saved;
768 /* how many non-NULL argv's we have. NB: $# + 1 */ 771 /* how many non-NULL argv's we have. NB: $# + 1 */
769 int global_argc; 772 int global_argc;
770 char **global_argv; 773 char **global_argv;
@@ -794,21 +797,20 @@ struct globals {
794#endif 797#endif
795 /* Which signals have non-DFL handler (even with no traps set)? 798 /* Which signals have non-DFL handler (even with no traps set)?
796 * Set at the start to: 799 * Set at the start to:
797 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOB_SIGS) 800 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS)
798 * SPECIAL_INTERACTIVE_SIGS are cleared after fork. 801 * SPECIAL_INTERACTIVE_SIGS are cleared after fork.
802 * The rest is cleared right before execv syscalls.
799 * Other than these two times, never modified. 803 * Other than these two times, never modified.
800 */ 804 */
801 unsigned special_sig_mask; 805 unsigned special_sig_mask;
806#if ENABLE_HUSH_JOB
807 unsigned fatal_sig_mask;
808#define G_fatal_sig_mask G.fatal_sig_mask
809#else
810#define G_fatal_sig_mask 0
811#endif
802 char **traps; /* char *traps[NSIG] */ 812 char **traps; /* char *traps[NSIG] */
803 /* Signal mask on the entry to the (top-level) shell. Never modified. */ 813 sigset_t pending_set;
804 sigset_t inherited_set;
805 /* Starts equal to inherited_set,
806 * but shell-special signals are added and SIGCHLD is removed.
807 * When a trap is set/cleared, signal is added to/removed from it:
808 */
809 sigset_t blocked_set;
810 /* Used by read() */
811 sigset_t detected_set;
812#if HUSH_DEBUG 814#if HUSH_DEBUG
813 unsigned long memleak_value; 815 unsigned long memleak_value;
814 int debug_indent; 816 int debug_indent;
@@ -1337,8 +1339,8 @@ static void restore_G_args(save_arg_t *sv, char **argv)
1337 * (What happens to signals which are IGN on shell start?) 1339 * (What happens to signals which are IGN on shell start?)
1338 * (What happens with signal mask on shell start?) 1340 * (What happens with signal mask on shell start?)
1339 * 1341 *
1340 * Implementation in hush 1342 * Old implementation
1341 * ====================== 1343 * ==================
1342 * We use in-kernel pending signal mask to determine which signals were sent. 1344 * We use in-kernel pending signal mask to determine which signals were sent.
1343 * We block all signals which we don't want to take action immediately, 1345 * We block all signals which we don't want to take action immediately,
1344 * i.e. we block all signals which need to have special handling as described 1346 * i.e. we block all signals which need to have special handling as described
@@ -1369,6 +1371,49 @@ static void restore_G_args(save_arg_t *sv, char **argv)
1369 * Standard says "When a subshell is entered, traps that are not being ignored 1371 * Standard says "When a subshell is entered, traps that are not being ignored
1370 * are set to the default actions". bash interprets it so that traps which 1372 * are set to the default actions". bash interprets it so that traps which
1371 * are set to '' (ignore) are NOT reset to defaults. We do the same. 1373 * are set to '' (ignore) are NOT reset to defaults. We do the same.
1374 *
1375 * Problem: the above approach makes it unwieldy to catch signals while
1376 * we are in read builtin, of while we read commands from stdin:
1377 * masked signals are not visible!
1378 *
1379 * New implementation
1380 * ==================
1381 * We record each signal we are interested in by installing signal handler
1382 * for them - a bit like emulating kernel pending signal mask in userspace.
1383 * We are interested in: signals which need to have special handling
1384 * as described above, and all signals which have traps set.
1385 * Signals are rocorded in pending_set.
1386 * After each pipe execution, we extract any pending signals
1387 * and act on them.
1388 *
1389 * unsigned special_sig_mask: a mask of shell-special signals.
1390 * unsigned fatal_sig_mask: a mask of signals on which we restore tty pgrp.
1391 * char *traps[sig] if trap for sig is set (even if it's '').
1392 * sigset_t pending_set: set of sigs we received.
1393 *
1394 * "trap - SIGxxx":
1395 * if sig is in special_sig_mask, set handler back to:
1396 * record_pending_signo, or to IGN if it's a tty stop signal
1397 * if sig is in fatal_sig_mask, set handler back to sigexit.
1398 * else: set handler back to SIG_DFL
1399 * "trap 'cmd' SIGxxx":
1400 * set handler to record_pending_signo.
1401 * "trap '' SIGxxx":
1402 * set handler to SIG_IGN.
1403 * after [v]fork, if we plan to be a shell:
1404 * set signals with special interactive handling to SIG_DFL
1405 * (because child shell is not interactive),
1406 * unset all traps except '' (note: regardless of child shell's type - {}, (), etc)
1407 * after [v]fork, if we plan to exec:
1408 * POSIX says fork clears pending signal mask in child - no need to clear it.
1409 *
1410 * To make wait builtin interruptible, we handle SIGCHLD as special signal,
1411 * otherwise (if we leave it SIG_DFL) sigsuspend in wait builtin will not wake up on it.
1412 *
1413 * Note (compat):
1414 * Standard says "When a subshell is entered, traps that are not being ignored
1415 * are set to the default actions". bash interprets it so that traps which
1416 * are set to '' (ignore) are NOT reset to defaults. We do the same.
1372 */ 1417 */
1373enum { 1418enum {
1374 SPECIAL_INTERACTIVE_SIGS = 0 1419 SPECIAL_INTERACTIVE_SIGS = 0
@@ -1376,26 +1421,25 @@ enum {
1376 | (1 << SIGINT) 1421 | (1 << SIGINT)
1377 | (1 << SIGHUP) 1422 | (1 << SIGHUP)
1378 , 1423 ,
1379 SPECIAL_JOB_SIGS = 0 1424 SPECIAL_JOBSTOP_SIGS = 0
1380#if ENABLE_HUSH_JOB 1425#if ENABLE_HUSH_JOB
1381 | (1 << SIGTTIN) 1426 | (1 << SIGTTIN)
1382 | (1 << SIGTTOU) 1427 | (1 << SIGTTOU)
1383 | (1 << SIGTSTP) 1428 | (1 << SIGTSTP)
1384#endif 1429#endif
1430 ,
1385}; 1431};
1386 1432
1387static void sigprocmask_set(sigset_t *set) 1433static void record_pending_signo(int sig)
1388{ 1434{
1389 sigprocmask(SIG_SETMASK, set, NULL); 1435 sigaddset(&G.pending_set, sig);
1390}
1391
1392#if ENABLE_HUSH_FAST 1436#if ENABLE_HUSH_FAST
1393static void SIGCHLD_handler(int sig UNUSED_PARAM) 1437 if (sig == SIGCHLD) {
1394{ 1438 G.count_SIGCHLD++;
1395 G.count_SIGCHLD++;
1396//bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 1439//bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
1397} 1440 }
1398#endif 1441#endif
1442}
1399 1443
1400#if ENABLE_HUSH_JOB 1444#if ENABLE_HUSH_JOB
1401 1445
@@ -1433,6 +1477,31 @@ static void sigexit(int sig)
1433 1477
1434#endif 1478#endif
1435 1479
1480static sighandler_t pick_sighandler(unsigned sig)
1481{
1482 sighandler_t handler = SIG_DFL;
1483 if (sig < sizeof(unsigned)*8) {
1484 unsigned sigmask = (1 << sig);
1485
1486#if ENABLE_HUSH_JOB
1487 /* sig is fatal? */
1488 if (G_fatal_sig_mask & sigmask)
1489 handler = sigexit;
1490#endif
1491 /* sig has special handling? */
1492 else if (G.special_sig_mask & sigmask)
1493 handler = record_pending_signo;
1494 /* TTIN/TTOU/TSTS can't be set to record_pending_signo
1495 * in order to ignore them: they will be raised
1496 * in an endless loop then when we try to do some
1497 * terminal ioctls! We do nave to _ignore_ these.
1498 */
1499 if (SPECIAL_JOBSTOP_SIGS & sigmask)
1500 handler = SIG_IGN;
1501 }
1502 return handler;
1503}
1504
1436/* Restores tty foreground process group, and exits. */ 1505/* Restores tty foreground process group, and exits. */
1437static void hush_exit(int exitcode) NORETURN; 1506static void hush_exit(int exitcode) NORETURN;
1438static void hush_exit(int exitcode) 1507static void hush_exit(int exitcode)
@@ -1478,39 +1547,30 @@ static void hush_exit(int exitcode)
1478} 1547}
1479 1548
1480 1549
1481static int check_and_run_traps(int sig) 1550//TODO: return a mask of ALL handled sigs?
1551static int check_and_run_traps(void)
1482{ 1552{
1483 /* I want it in rodata, not in bss.
1484 * gcc 4.2.1 puts it in rodata only if it has { 0, 0 }
1485 * initializer. But other compilers may still use bss.
1486 * TODO: find more portable solution.
1487 */
1488 static const struct timespec zero_timespec = { 0, 0 };
1489 smalluint save_rcode;
1490 int last_sig = 0; 1553 int last_sig = 0;
1491 1554
1492 if (sig)
1493 goto got_sig;
1494
1495 while (1) { 1555 while (1) {
1496 if (!sigisemptyset(&G.detected_set)) { 1556 int sig;
1497 sig = 0;
1498 do {
1499 sig++;
1500 if (sigismember(&G.detected_set, sig)) {
1501 sigdelset(&G.detected_set, sig);
1502 goto got_sig;
1503 }
1504 } while (sig < NSIG);
1505 }
1506 1557
1507 sig = sigtimedwait(&G.blocked_set, NULL, &zero_timespec); 1558 if (sigisemptyset(&G.pending_set))
1508 if (sig <= 0)
1509 break; 1559 break;
1560 sig = 0;
1561 do {
1562 sig++;
1563 if (sigismember(&G.pending_set, sig)) {
1564 sigdelset(&G.pending_set, sig);
1565 goto got_sig;
1566 }
1567 } while (sig < NSIG);
1568 break;
1510 got_sig: 1569 got_sig:
1511 if (G.traps && G.traps[sig]) { 1570 if (G.traps && G.traps[sig]) {
1512 if (G.traps[sig][0]) { 1571 if (G.traps[sig][0]) {
1513 /* We have user-defined handler */ 1572 /* We have user-defined handler */
1573 smalluint save_rcode;
1514 char *argv[3]; 1574 char *argv[3];
1515 /* argv[0] is unused */ 1575 /* argv[0] is unused */
1516 argv[1] = G.traps[sig]; 1576 argv[1] = G.traps[sig];
@@ -1524,12 +1584,6 @@ static int check_and_run_traps(int sig)
1524 } 1584 }
1525 /* not a trap: special action */ 1585 /* not a trap: special action */
1526 switch (sig) { 1586 switch (sig) {
1527#if ENABLE_HUSH_FAST
1528 case SIGCHLD:
1529 G.count_SIGCHLD++;
1530//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
1531 break;
1532#endif
1533 case SIGINT: 1587 case SIGINT:
1534 /* Builtin was ^C'ed, make it look prettier: */ 1588 /* Builtin was ^C'ed, make it look prettier: */
1535 bb_putchar('\n'); 1589 bb_putchar('\n');
@@ -1551,11 +1605,21 @@ static int check_and_run_traps(int sig)
1551 sigexit(SIGHUP); 1605 sigexit(SIGHUP);
1552 } 1606 }
1553#endif 1607#endif
1608#if ENABLE_HUSH_FAST
1609 case SIGCHLD:
1610 G.count_SIGCHLD++;
1611//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
1612 /* Note:
1613 * We dont do 'last_sig = sig' here -> NOT returning this sig.
1614 * This simplifies wait builtin a bit.
1615 */
1616 break;
1617#endif
1554 default: /* ignored: */ 1618 default: /* ignored: */
1555 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */ 1619 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */
1556 /* note: 1620 /* Note:
1557 * we dont do 'last_sig = sig' here -> NOT returning this sig. 1621 * We dont do 'last_sig = sig' here -> NOT returning this sig.
1558 * example: wait is not interrupted by TERM 1622 * Example: wait is not interrupted by TERM
1559 * in interactive shell, because TERM is ignored. 1623 * in interactive shell, because TERM is ignored.
1560 */ 1624 */
1561 break; 1625 break;
@@ -1948,7 +2012,7 @@ static void get_user_input(struct in_str *i)
1948 * only after <Enter>. (^C will work) */ 2012 * only after <Enter>. (^C will work) */
1949 r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1); 2013 r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1);
1950 /* catch *SIGINT* etc (^C is handled by read_line_input) */ 2014 /* catch *SIGINT* etc (^C is handled by read_line_input) */
1951 check_and_run_traps(0); 2015 check_and_run_traps();
1952 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ 2016 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */
1953 i->eof_flag = (r < 0); 2017 i->eof_flag = (r < 0);
1954 if (i->eof_flag) { /* EOF/error detected */ 2018 if (i->eof_flag) { /* EOF/error detected */
@@ -1964,7 +2028,7 @@ static void get_user_input(struct in_str *i)
1964 * $ <[enter], repeatedly...> 2028 * $ <[enter], repeatedly...>
1965 * Without check_and_run_traps, handler never runs. 2029 * Without check_and_run_traps, handler never runs.
1966 */ 2030 */
1967 check_and_run_traps(0); 2031 check_and_run_traps();
1968 fputs(prompt_str, stdout); 2032 fputs(prompt_str, stdout);
1969 } 2033 }
1970 fflush_all(); 2034 fflush_all();
@@ -5368,6 +5432,25 @@ void re_execute_shell(char ***to_free, const char *s,
5368 char *g_argv0, char **g_argv, 5432 char *g_argv0, char **g_argv,
5369 char **builtin_argv) NORETURN; 5433 char **builtin_argv) NORETURN;
5370 5434
5435static void switch_off_special_sigs(unsigned mask)
5436{
5437 unsigned sig = 0;
5438 while ((mask >>= 1) != 0) {
5439 sig++;
5440 if (!(mask & 1))
5441 continue;
5442 if (G.traps) {
5443 if (G.traps[sig] && !G.traps[sig][0])
5444 /* trap is '', has to remain SIG_IGN */
5445 continue;
5446 free(G.traps[sig]);
5447 G.traps[sig] = NULL;
5448 }
5449 /* We are here only if no trap or trap was not '' */
5450 signal(sig, SIG_DFL);
5451 }
5452}
5453
5371static void reset_traps_to_defaults(void) 5454static void reset_traps_to_defaults(void)
5372{ 5455{
5373 /* This function is always called in a child shell 5456 /* This function is always called in a child shell
@@ -5381,44 +5464,35 @@ static void reset_traps_to_defaults(void)
5381 * Testcase: (while :; do :; done) + ^Z should background. 5464 * Testcase: (while :; do :; done) + ^Z should background.
5382 * Same goes for SIGTERM, SIGHUP, SIGINT. 5465 * Same goes for SIGTERM, SIGHUP, SIGINT.
5383 */ 5466 */
5384 if (!G.traps && !(G.special_sig_mask & SPECIAL_INTERACTIVE_SIGS)) 5467 mask = (G.special_sig_mask & SPECIAL_INTERACTIVE_SIGS) | G_fatal_sig_mask;
5385 return; /* already no traps and no SPECIAL_INTERACTIVE_SIGS */ 5468 if (!G.traps && !mask)
5386 5469 return; /* already no traps and no special sigs */
5387 /* Switching off SPECIAL_INTERACTIVE_SIGS. 5470
5388 * Stupid. It can be done with *single* &= op, but we can't use 5471 /* Switch off special sigs */
5389 * the fact that G.blocked_set is implemented as a bitmask 5472 switch_off_special_sigs(mask);
5390 * in libc... */ 5473#if ENABLE_HUSH_JOB
5391 mask = SPECIAL_INTERACTIVE_SIGS; 5474 G_fatal_sig_mask = 0;
5392 sig = 0; 5475#endif
5393 while ((mask >>= 1) != 0) {
5394 sig++;
5395 if (mask & 1) {
5396 /* Careful. Only if no trap or trap is not "" */
5397 if (!G.traps || !G.traps[sig] || G.traps[sig][0])
5398 sigdelset(&G.blocked_set, sig);
5399 }
5400 }
5401 /* Our homegrown sig mask is saner to work with :) */
5402 G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS; 5476 G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS;
5477 /* SIGQUIT and maybe SPECIAL_JOBSTOP_SIGS remain set in G.special_sig_mask */
5403 5478
5404 /* Resetting all traps to default except empty ones */ 5479 if (!G.traps)
5405 mask = G.special_sig_mask; 5480 return;
5406 if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) { 5481
5407 if (!G.traps[sig] || !G.traps[sig][0]) 5482 /* Reset all sigs to default except ones with empty traps */
5408 continue; 5483 for (sig = 0; sig < NSIG; sig++) {
5484 if (!G.traps[sig])
5485 continue; /* no trap: nothing to do */
5486 if (!G.traps[sig][0])
5487 continue; /* empty trap: has to remain SIG_IGN */
5488 /* sig has non-empty trap, reset it: */
5409 free(G.traps[sig]); 5489 free(G.traps[sig]);
5410 G.traps[sig] = NULL; 5490 G.traps[sig] = NULL;
5411 /* There is no signal for 0 (EXIT) */ 5491 /* There is no signal for trap 0 (EXIT) */
5412 if (sig == 0) 5492 if (sig == 0)
5413 continue; 5493 continue;
5414 /* There was a trap handler, we just removed it. 5494 signal(sig, pick_sighandler(sig));
5415 * But if sig still has non-DFL handling,
5416 * we should not unblock the sig. */
5417 if (mask & 1)
5418 continue;
5419 sigdelset(&G.blocked_set, sig);
5420 } 5495 }
5421 sigprocmask_set(&G.blocked_set);
5422} 5496}
5423 5497
5424#else /* !BB_MMU */ 5498#else /* !BB_MMU */
@@ -5463,6 +5537,7 @@ static void re_execute_shell(char ***to_free, const char *s,
5463 for (sig = 1; sig < NSIG; sig++) { 5537 for (sig = 1; sig < NSIG; sig++) {
5464 if (G.traps[sig] && !G.traps[sig][0]) 5538 if (G.traps[sig] && !G.traps[sig][0])
5465 empty_trap_mask |= 1LL << sig; 5539 empty_trap_mask |= 1LL << sig;
5540///vda: optimize
5466 } 5541 }
5467 } 5542 }
5468 5543
@@ -5548,7 +5623,7 @@ static void re_execute_shell(char ***to_free, const char *s,
5548 5623
5549 do_exec: 5624 do_exec:
5550 debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); 5625 debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s);
5551 sigprocmask_set(&G.inherited_set); 5626 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
5552 execve(bb_busybox_exec_path, argv, pp); 5627 execve(bb_busybox_exec_path, argv, pp);
5553 /* Fallback. Useful for init=/bin/hush usage etc */ 5628 /* Fallback. Useful for init=/bin/hush usage etc */
5554 if (argv[0][0] == '/') 5629 if (argv[0][0] == '/')
@@ -6202,7 +6277,7 @@ static void execvp_or_die(char **argv) NORETURN;
6202static void execvp_or_die(char **argv) 6277static void execvp_or_die(char **argv)
6203{ 6278{
6204 debug_printf_exec("execing '%s'\n", argv[0]); 6279 debug_printf_exec("execing '%s'\n", argv[0]);
6205 sigprocmask_set(&G.inherited_set); 6280 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
6206 execvp(argv[0], argv); 6281 execvp(argv[0], argv);
6207 bb_perror_msg("can't execute '%s'", argv[0]); 6282 bb_perror_msg("can't execute '%s'", argv[0]);
6208 _exit(127); /* bash compat */ 6283 _exit(127); /* bash compat */
@@ -6334,7 +6409,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
6334# endif 6409# endif
6335 /* Re-exec ourselves */ 6410 /* Re-exec ourselves */
6336 debug_printf_exec("re-execing applet '%s'\n", argv[0]); 6411 debug_printf_exec("re-execing applet '%s'\n", argv[0]);
6337 sigprocmask_set(&G.inherited_set); 6412 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
6338 execv(bb_busybox_exec_path, argv); 6413 execv(bb_busybox_exec_path, argv);
6339 /* If they called chroot or otherwise made the binary no longer 6414 /* If they called chroot or otherwise made the binary no longer
6340 * executable, fall through */ 6415 * executable, fall through */
@@ -7033,9 +7108,6 @@ static NOINLINE int run_pipe(struct pipe *pi)
7033 if (setup_redirects(command, NULL)) 7108 if (setup_redirects(command, NULL))
7034 _exit(1); 7109 _exit(1);
7035 7110
7036 /* Restore default handlers just prior to exec */
7037 /*signal(SIGCHLD, SIG_DFL); - so far we don't have any handlers */
7038
7039 /* Stores to nommu_save list of env vars putenv'ed 7111 /* Stores to nommu_save list of env vars putenv'ed
7040 * (NOMMU, on MMU we don't need that) */ 7112 * (NOMMU, on MMU we don't need that) */
7041 /* cast away volatility... */ 7113 /* cast away volatility... */
@@ -7313,7 +7385,7 @@ static int run_list(struct pipe *pi)
7313 * and we don't need to wait for anything. */ 7385 * and we don't need to wait for anything. */
7314 G.last_exitcode = rcode; 7386 G.last_exitcode = rcode;
7315 debug_printf_exec(": builtin/func exitcode %d\n", rcode); 7387 debug_printf_exec(": builtin/func exitcode %d\n", rcode);
7316 check_and_run_traps(0); 7388 check_and_run_traps();
7317#if ENABLE_HUSH_LOOPS 7389#if ENABLE_HUSH_LOOPS
7318 /* Was it "break" or "continue"? */ 7390 /* Was it "break" or "continue"? */
7319 if (G.flag_break_continue) { 7391 if (G.flag_break_continue) {
@@ -7345,7 +7417,7 @@ static int run_list(struct pipe *pi)
7345 /* even bash 3.2 doesn't do that well with nested bg: 7417 /* even bash 3.2 doesn't do that well with nested bg:
7346 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". 7418 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".
7347 * I'm NOT treating inner &'s as jobs */ 7419 * I'm NOT treating inner &'s as jobs */
7348 check_and_run_traps(0); 7420 check_and_run_traps();
7349#if ENABLE_HUSH_JOB 7421#if ENABLE_HUSH_JOB
7350 if (G.run_list_level == 1) 7422 if (G.run_list_level == 1)
7351 insert_bg_job(pi); 7423 insert_bg_job(pi);
@@ -7360,13 +7432,13 @@ static int run_list(struct pipe *pi)
7360 /* Waits for completion, then fg's main shell */ 7432 /* Waits for completion, then fg's main shell */
7361 rcode = checkjobs_and_fg_shell(pi); 7433 rcode = checkjobs_and_fg_shell(pi);
7362 debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode); 7434 debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode);
7363 check_and_run_traps(0); 7435 check_and_run_traps();
7364 } else 7436 } else
7365#endif 7437#endif
7366 { /* This one just waits for completion */ 7438 { /* This one just waits for completion */
7367 rcode = checkjobs(pi); 7439 rcode = checkjobs(pi);
7368 debug_printf_exec(": checkjobs exitcode %d\n", rcode); 7440 debug_printf_exec(": checkjobs exitcode %d\n", rcode);
7369 check_and_run_traps(0); 7441 check_and_run_traps();
7370 } 7442 }
7371 G.last_exitcode = rcode; 7443 G.last_exitcode = rcode;
7372 } 7444 }
@@ -7437,58 +7509,61 @@ static int run_and_free_list(struct pipe *pi)
7437} 7509}
7438 7510
7439 7511
7512static void install_sighandlers(unsigned mask)
7513{
7514 sighandler_t old_handler;
7515 unsigned sig = 0;
7516 while ((mask >>= 1) != 0) {
7517 sig++;
7518 if (!(mask & 1))
7519 continue;
7520 old_handler = signal(sig, pick_sighandler(sig));
7521 /* POSIX allows shell to re-enable SIGCHLD
7522 * even if it was SIG_IGN on entry.
7523 * Therefore we skip IGN check for it:
7524 */
7525 if (sig == SIGCHLD)
7526 continue;
7527 if (old_handler == SIG_IGN) {
7528 /* oops... restore back to IGN, and record this fact */
7529 signal(sig, old_handler);
7530 if (!G.traps)
7531 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
7532 free(G.traps[sig]);
7533 G.traps[sig] = xzalloc(1); /* == xstrdup(""); */
7534 }
7535 }
7536}
7537
7440/* Called a few times only (or even once if "sh -c") */ 7538/* Called a few times only (or even once if "sh -c") */
7441static void init_sigmasks(void) 7539static void install_special_sighandlers(void)
7442{ 7540{
7443 unsigned sig;
7444 unsigned mask; 7541 unsigned mask;
7445 7542
7446 /* POSIX allows shell to re-enable SIGCHLD 7543 if (G.special_sig_mask != 0)
7447 * even if it was SIG_IGN on entry */ 7544 return;
7448 if (!G.inherited_set_is_saved) {
7449#if ENABLE_HUSH_FAST
7450 signal(SIGCHLD, SIGCHLD_handler);
7451#else
7452 signal(SIGCHLD, SIG_DFL);
7453#endif
7454 sigprocmask(SIG_SETMASK, NULL, &G.blocked_set);
7455 G.inherited_set = G.blocked_set;
7456 }
7457 7545
7458 /* Which signals are shell-special? */ 7546 /* Which signals are shell-special? */
7459 mask = (1 << SIGQUIT); 7547 mask = (1 << SIGQUIT) | (1 << SIGCHLD);
7460 if (G_interactive_fd) { 7548 if (G_interactive_fd) {
7461 mask |= SPECIAL_INTERACTIVE_SIGS; 7549 mask |= SPECIAL_INTERACTIVE_SIGS;
7462 if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ 7550 if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */
7463 mask |= SPECIAL_JOB_SIGS; 7551 mask |= SPECIAL_JOBSTOP_SIGS;
7464 } 7552 }
7465 G.special_sig_mask = mask; 7553 G.special_sig_mask = mask;
7466 7554
7467 /* Block them. And unblock SIGCHLD */ 7555 install_sighandlers(mask);
7468 sig = 0;
7469 while ((mask >>= 1) != 0) {
7470 sig++;
7471 if (mask & 1)
7472 sigaddset(&G.blocked_set, sig);
7473 }
7474 sigdelset(&G.blocked_set, SIGCHLD);
7475
7476 if (memcmp(&G.inherited_set, &G.blocked_set, sizeof(G.inherited_set)) != 0)
7477 sigprocmask_set(&G.blocked_set);
7478
7479 G.inherited_set_is_saved = 1;
7480} 7556}
7481 7557
7482#if ENABLE_HUSH_JOB 7558#if ENABLE_HUSH_JOB
7483/* helper */ 7559/* helper */
7484/* Set handlers to restore tty pgrp and exit */ 7560/* Set handlers to restore tty pgrp and exit */
7485static void set_fatal_handlers_to_sigexit(void) 7561static void install_fatal_sighandlers(void)
7486{ 7562{
7487 void (*handler)(int); 7563 unsigned mask;
7488 unsigned fatal_sigs, sig;
7489 7564
7490 /* We will restore tty pgrp on these signals */ 7565 /* We will restore tty pgrp on these signals */
7491 fatal_sigs = 0 7566 mask = 0
7492 + (1 << SIGILL ) * HUSH_DEBUG 7567 + (1 << SIGILL ) * HUSH_DEBUG
7493 + (1 << SIGFPE ) * HUSH_DEBUG 7568 + (1 << SIGFPE ) * HUSH_DEBUG
7494 + (1 << SIGBUS ) * HUSH_DEBUG 7569 + (1 << SIGBUS ) * HUSH_DEBUG
@@ -7505,22 +7580,13 @@ static void set_fatal_handlers_to_sigexit(void)
7505 /*+ (1 << SIGTERM)*/ 7580 /*+ (1 << SIGTERM)*/
7506 /*+ (1 << SIGINT )*/ 7581 /*+ (1 << SIGINT )*/
7507 ; 7582 ;
7508 7583 /* special_sig_mask'ed signals are set to record_pending_signo
7509 /* special_sig_mask'ed signals are, well, masked,
7510 * no need to set handler for them. 7584 * no need to set handler for them.
7511 */ 7585 */
7512 fatal_sigs &= ~G.special_sig_mask; 7586 /*mask &= ~G.special_sig_mask; - they never overlap */
7587 G_fatal_sig_mask = mask;
7513 7588
7514 /* For each sig in fatal_sigs... */ 7589 install_sighandlers(mask);
7515 sig = 0;
7516 while ((fatal_sigs >>= 1) != 0) {
7517 sig++;
7518 if (!(fatal_sigs & 1))
7519 continue;
7520 handler = signal(sig, sigexit);
7521 if (handler == SIG_IGN) /* oops... restore back to IGN! */
7522 signal(sig, handler);
7523 }
7524} 7590}
7525#endif 7591#endif
7526 7592
@@ -7682,10 +7748,11 @@ int hush_main(int argc, char **argv)
7682 } 7748 }
7683 7749
7684 /* Shell is non-interactive at first. We need to call 7750 /* Shell is non-interactive at first. We need to call
7685 * init_sigmasks() if we are going to execute "sh <script>", 7751 * install_special_sighandlers() if we are going to execute "sh <script>",
7686 * "sh -c <cmds>" or login shell's /etc/profile and friends. 7752 * "sh -c <cmds>" or login shell's /etc/profile and friends.
7687 * If we later decide that we are interactive, we run init_sigmasks() 7753 * If we later decide that we are interactive, we run install_special_sighandlers()
7688 * in order to intercept (more) signals. 7754 * in order to intercept (more) signals.
7755//FIXME: re-running is currently most likely broken, it's a no-op.
7689 */ 7756 */
7690 7757
7691 /* Parse options */ 7758 /* Parse options */
@@ -7724,7 +7791,7 @@ int hush_main(int argc, char **argv)
7724 /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */ 7791 /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */
7725 const struct built_in_command *x; 7792 const struct built_in_command *x;
7726 7793
7727 init_sigmasks(); 7794 install_special_sighandlers();
7728 x = find_builtin(optarg); 7795 x = find_builtin(optarg);
7729 if (x) { /* paranoia */ 7796 if (x) { /* paranoia */
7730 G.global_argc -= builtin_argc; /* skip [BARGV...] "" */ 7797 G.global_argc -= builtin_argc; /* skip [BARGV...] "" */
@@ -7741,7 +7808,7 @@ int hush_main(int argc, char **argv)
7741 G.global_argv[0] = argv[0]; 7808 G.global_argv[0] = argv[0];
7742 G.global_argc++; 7809 G.global_argc++;
7743 } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */ 7810 } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */
7744 init_sigmasks(); 7811 install_special_sighandlers();
7745 parse_and_run_string(optarg); 7812 parse_and_run_string(optarg);
7746 goto final_return; 7813 goto final_return;
7747 case 'i': 7814 case 'i':
@@ -7773,15 +7840,15 @@ int hush_main(int argc, char **argv)
7773 empty_trap_mask = bb_strtoull(optarg, &optarg, 16); 7840 empty_trap_mask = bb_strtoull(optarg, &optarg, 16);
7774 if (empty_trap_mask != 0) { 7841 if (empty_trap_mask != 0) {
7775 int sig; 7842 int sig;
7776 init_sigmasks(); 7843 install_special_sighandlers();
7777 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); 7844 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
7778 for (sig = 1; sig < NSIG; sig++) { 7845 for (sig = 1; sig < NSIG; sig++) {
7846///vda: fixme: more efficient code
7779 if (empty_trap_mask & (1LL << sig)) { 7847 if (empty_trap_mask & (1LL << sig)) {
7780 G.traps[sig] = xzalloc(1); /* == xstrdup(""); */ 7848 G.traps[sig] = xzalloc(1); /* == xstrdup(""); */
7781 sigaddset(&G.blocked_set, sig); 7849 signal(sig, SIG_IGN);
7782 } 7850 }
7783 } 7851 }
7784 sigprocmask_set(&G.blocked_set);
7785 } 7852 }
7786# if ENABLE_HUSH_LOOPS 7853# if ENABLE_HUSH_LOOPS
7787 optarg++; 7854 optarg++;
@@ -7831,7 +7898,7 @@ int hush_main(int argc, char **argv)
7831 input = fopen_for_read("/etc/profile"); 7898 input = fopen_for_read("/etc/profile");
7832 if (input != NULL) { 7899 if (input != NULL) {
7833 close_on_exec_on(fileno(input)); 7900 close_on_exec_on(fileno(input));
7834 init_sigmasks(); 7901 install_special_sighandlers();
7835 parse_and_run_file(input); 7902 parse_and_run_file(input);
7836 fclose(input); 7903 fclose(input);
7837 } 7904 }
@@ -7856,7 +7923,7 @@ int hush_main(int argc, char **argv)
7856 G.global_argc = argc - optind; 7923 G.global_argc = argc - optind;
7857 input = xfopen_for_read(argv[optind]); 7924 input = xfopen_for_read(argv[optind]);
7858 close_on_exec_on(fileno(input)); 7925 close_on_exec_on(fileno(input));
7859 init_sigmasks(); 7926 install_special_sighandlers();
7860 parse_and_run_file(input); 7927 parse_and_run_file(input);
7861#if ENABLE_FEATURE_CLEAN_UP 7928#if ENABLE_FEATURE_CLEAN_UP
7862 fclose(input); 7929 fclose(input);
@@ -7865,7 +7932,7 @@ int hush_main(int argc, char **argv)
7865 } 7932 }
7866 7933
7867 /* Up to here, shell was non-interactive. Now it may become one. 7934 /* Up to here, shell was non-interactive. Now it may become one.
7868 * NB: don't forget to (re)run init_sigmasks() as needed. 7935 * NB: don't forget to (re)run install_special_sighandlers() as needed.
7869 */ 7936 */
7870 7937
7871 /* A shell is interactive if the '-i' flag was given, 7938 /* A shell is interactive if the '-i' flag was given,
@@ -7918,11 +7985,11 @@ int hush_main(int argc, char **argv)
7918 } 7985 }
7919 7986
7920 /* Block some signals */ 7987 /* Block some signals */
7921 init_sigmasks(); 7988 install_special_sighandlers();
7922 7989
7923 if (G_saved_tty_pgrp) { 7990 if (G_saved_tty_pgrp) {
7924 /* Set other signals to restore saved_tty_pgrp */ 7991 /* Set other signals to restore saved_tty_pgrp */
7925 set_fatal_handlers_to_sigexit(); 7992 install_fatal_sighandlers();
7926 /* Put ourselves in our own process group 7993 /* Put ourselves in our own process group
7927 * (bash, too, does this only if ctty is available) */ 7994 * (bash, too, does this only if ctty is available) */
7928 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ 7995 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
@@ -7933,7 +8000,7 @@ int hush_main(int argc, char **argv)
7933 * (we reset die_sleep = 0 whereever we [v]fork) */ 8000 * (we reset die_sleep = 0 whereever we [v]fork) */
7934 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */ 8001 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
7935 } else { 8002 } else {
7936 init_sigmasks(); 8003 install_special_sighandlers();
7937 } 8004 }
7938#elif ENABLE_HUSH_INTERACTIVE 8005#elif ENABLE_HUSH_INTERACTIVE
7939 /* No job control compiled in, only prompt/line editing */ 8006 /* No job control compiled in, only prompt/line editing */
@@ -7950,10 +8017,10 @@ int hush_main(int argc, char **argv)
7950 if (G_interactive_fd) { 8017 if (G_interactive_fd) {
7951 close_on_exec_on(G_interactive_fd); 8018 close_on_exec_on(G_interactive_fd);
7952 } 8019 }
7953 init_sigmasks(); 8020 install_special_sighandlers();
7954#else 8021#else
7955 /* We have interactiveness code disabled */ 8022 /* We have interactiveness code disabled */
7956 init_sigmasks(); 8023 install_special_sighandlers();
7957#endif 8024#endif
7958 /* bash: 8025 /* bash:
7959 * if interactive but not a login shell, sources ~/.bashrc 8026 * if interactive but not a login shell, sources ~/.bashrc
@@ -8087,7 +8154,7 @@ static int FAST_FUNC builtin_exec(char **argv)
8087 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp); 8154 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp);
8088 8155
8089 /* TODO: if exec fails, bash does NOT exit! We do. 8156 /* TODO: if exec fails, bash does NOT exit! We do.
8090 * We'll need to undo sigprocmask (it's inside execvp_or_die) 8157 * We'll need to undo trap cleanup (it's inside execvp_or_die)
8091 * and tcsetpgrp, and this is inherently racy. 8158 * and tcsetpgrp, and this is inherently racy.
8092 */ 8159 */
8093 execvp_or_die(argv); 8160 execvp_or_die(argv);
@@ -8284,6 +8351,8 @@ static int FAST_FUNC builtin_trap(char **argv)
8284 process_sig_list: 8351 process_sig_list:
8285 ret = EXIT_SUCCESS; 8352 ret = EXIT_SUCCESS;
8286 while (*argv) { 8353 while (*argv) {
8354 sighandler_t handler;
8355
8287 sig = get_signum(*argv++); 8356 sig = get_signum(*argv++);
8288 if (sig < 0 || sig >= NSIG) { 8357 if (sig < 0 || sig >= NSIG) {
8289 ret = EXIT_FAILURE; 8358 ret = EXIT_FAILURE;
@@ -8302,18 +8371,13 @@ static int FAST_FUNC builtin_trap(char **argv)
8302 if (sig == 0) 8371 if (sig == 0)
8303 continue; 8372 continue;
8304 8373
8305 if (new_cmd) { 8374 if (new_cmd)
8306 sigaddset(&G.blocked_set, sig); 8375 handler = (new_cmd[0] ? record_pending_signo : SIG_IGN);
8307 } else { 8376 else
8308 /* There was a trap handler, we are removing it 8377 /* We are removing trap handler */
8309 * (if sig has non-DFL handling, 8378 handler = pick_sighandler(sig);
8310 * we don't need to do anything) */ 8379 signal(sig, handler);
8311 if (sig < sizeof(G.special_sig_mask)*8 && (G.special_sig_mask & (1 << sig)))
8312 continue;
8313 sigdelset(&G.blocked_set, sig);
8314 }
8315 } 8380 }
8316 sigprocmask_set(&G.blocked_set);
8317 return ret; 8381 return ret;
8318 } 8382 }
8319 8383
@@ -8535,11 +8599,6 @@ static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM)
8535 * if it has non-empty trap: 8599 * if it has non-empty trap:
8536 * - executes trap and returns to read; 8600 * - executes trap and returns to read;
8537 */ 8601 */
8538/* helper */
8539static void record_signal(int sig)
8540{
8541 sigaddset(&G.detected_set, sig);
8542}
8543static int FAST_FUNC builtin_read(char **argv) 8602static int FAST_FUNC builtin_read(char **argv)
8544{ 8603{
8545 const char *r; 8604 const char *r;
@@ -8549,7 +8608,6 @@ static int FAST_FUNC builtin_read(char **argv)
8549 char *opt_u = NULL; 8608 char *opt_u = NULL;
8550 const char *ifs; 8609 const char *ifs;
8551 int read_flags; 8610 int read_flags;
8552 sigset_t saved_blkd_set;
8553 8611
8554 /* "!": do not abort on errors. 8612 /* "!": do not abort on errors.
8555 * Option string must start with "sr" to match BUILTIN_READ_xxx 8613 * Option string must start with "sr" to match BUILTIN_READ_xxx
@@ -8561,41 +8619,6 @@ static int FAST_FUNC builtin_read(char **argv)
8561 ifs = get_local_var_value("IFS"); /* can be NULL */ 8619 ifs = get_local_var_value("IFS"); /* can be NULL */
8562 8620
8563 again: 8621 again:
8564 /* We need to temporarily unblock and record signals around read */
8565
8566 saved_blkd_set = G.blocked_set;
8567 {
8568 unsigned sig;
8569 struct sigaction sa, old_sa;
8570
8571 memset(&sa, 0, sizeof(sa));
8572 sigfillset(&sa.sa_mask);
8573 sa.sa_flags = SA_RESTART;
8574 sa.sa_handler = record_signal;
8575
8576 sig = 0;
8577 do {
8578 sig++;
8579 if (sigismember(&G.blocked_set, sig)) {
8580 char *sig_trap = (G.traps && G.traps[sig]) ? G.traps[sig] : NULL;
8581 /* If has a nonempty trap... */
8582 if ((sig_trap && sig_trap[0])
8583 /* ...or has no trap and is SIGINT or SIGHUP */
8584 || (!sig_trap && (sig == SIGINT || sig == SIGHUP))
8585 ) {
8586 sigaction(sig, &sa, &old_sa);
8587 if (old_sa.sa_handler == SIG_IGN) /* oops... restore back to IGN! */
8588 sigaction_set(sig, &old_sa);
8589 else
8590 sigdelset(&G.blocked_set, sig);
8591 }
8592 }
8593 } while (sig < NSIG-1);
8594 }
8595
8596 if (memcmp(&saved_blkd_set, &G.blocked_set, sizeof(saved_blkd_set)) != 0)
8597 sigprocmask_set(&G.blocked_set);
8598
8599 r = shell_builtin_read(set_local_var_from_halves, 8622 r = shell_builtin_read(set_local_var_from_halves,
8600 argv, 8623 argv,
8601 ifs, 8624 ifs,
@@ -8606,13 +8629,8 @@ static int FAST_FUNC builtin_read(char **argv)
8606 opt_u 8629 opt_u
8607 ); 8630 );
8608 8631
8609 if (memcmp(&saved_blkd_set, &G.blocked_set, sizeof(saved_blkd_set)) != 0) {
8610 G.blocked_set = saved_blkd_set;
8611 sigprocmask_set(&G.blocked_set);
8612 }
8613
8614 if ((uintptr_t)r == 1 && errno == EINTR) { 8632 if ((uintptr_t)r == 1 && errno == EINTR) {
8615 unsigned sig = check_and_run_traps(0); 8633 unsigned sig = check_and_run_traps();
8616 if (sig && sig != SIGINT) 8634 if (sig && sig != SIGINT)
8617 goto again; 8635 goto again;
8618 } 8636 }
@@ -8849,7 +8867,7 @@ static int FAST_FUNC builtin_unset(char **argv)
8849static int FAST_FUNC builtin_wait(char **argv) 8867static int FAST_FUNC builtin_wait(char **argv)
8850{ 8868{
8851 int ret = EXIT_SUCCESS; 8869 int ret = EXIT_SUCCESS;
8852 int status, sig; 8870 int status;
8853 8871
8854 argv = skip_dash_dash(argv); 8872 argv = skip_dash_dash(argv);
8855 if (argv[0] == NULL) { 8873 if (argv[0] == NULL) {
@@ -8869,25 +8887,53 @@ static int FAST_FUNC builtin_wait(char **argv)
8869 * ^C <-- after ~4 sec from keyboard 8887 * ^C <-- after ~4 sec from keyboard
8870 * $ 8888 * $
8871 */ 8889 */
8872 sigaddset(&G.blocked_set, SIGCHLD);
8873 sigprocmask_set(&G.blocked_set);
8874 while (1) { 8890 while (1) {
8875 checkjobs(NULL); 8891 int sig;
8876 if (errno == ECHILD) 8892 sigset_t oldset, allsigs;
8893
8894 /* waitpid is not interruptible by SA_RESTARTed
8895 * signals which we use. Thus, this ugly dance:
8896 */
8897
8898 /* Make sure possible SIGCHLD is stored in kernel's
8899 * pending signal mask before we call waitpid.
8900 * Or else we may race with SIGCHLD, lose it,
8901 * and get stuck in sigwaitinfo...
8902 */
8903 sigfillset(&allsigs);
8904 sigprocmask(SIG_SETMASK, &allsigs, &oldset);
8905
8906 if (!sigisemptyset(&G.pending_set)) {
8907 /* Crap! we raced with some signal! */
8908 // sig = 0;
8909 goto restore;
8910 }
8911
8912 checkjobs(NULL); /* waitpid(WNOHANG) inside */
8913 if (errno == ECHILD) {
8914 sigprocmask(SIG_SETMASK, &oldset, NULL);
8915 break;
8916 }
8917
8918 /* Wait for SIGCHLD or any other signal */
8919 //sig = sigwaitinfo(&allsigs, NULL);
8920 /* It is vitally important for sigsuspend that SIGCHLD has non-DFL handler! */
8921 /* Note: sigsuspend invokes signal handler */
8922 sigsuspend(&oldset);
8923 restore:
8924 sigprocmask(SIG_SETMASK, &oldset, NULL);
8925
8926 /* So, did we get a signal? */
8927 //if (sig > 0)
8928 // raise(sig); /* run handler */
8929 sig = check_and_run_traps();
8930 if (sig /*&& sig != SIGCHLD - always true */) {
8931 /* see note 2 */
8932 ret = 128 + sig;
8877 break; 8933 break;
8878 /* Wait for SIGCHLD or any other signal of interest */
8879 /* sigtimedwait with infinite timeout: */
8880 sig = sigwaitinfo(&G.blocked_set, NULL);
8881 if (sig > 0) {
8882 sig = check_and_run_traps(sig);
8883 if (sig && sig != SIGCHLD) { /* see note 2 */
8884 ret = 128 + sig;
8885 break;
8886 }
8887 } 8934 }
8935 /* SIGCHLD, or no signal, or ignored one, such as SIGQUIT. Repeat */
8888 } 8936 }
8889 sigdelset(&G.blocked_set, SIGCHLD);
8890 sigprocmask_set(&G.blocked_set);
8891 return ret; 8937 return ret;
8892 } 8938 }
8893 8939