aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2012-03-22 15:21:20 +0000
committerRon Yorston <rmy@pobox.com>2012-03-22 15:21:20 +0000
commit0d8b2c4a929ea9d3ac37499319fe0d8e7941a0c2 (patch)
tree6709ddd6071a9c238ba69233540bbcfe560c6a44 /shell
parent67758035a4fe040c6ac69b39d61bcd6bddd7b827 (diff)
parent56a3b82e9692a25ef9c9269e88feac0d579ce8e8 (diff)
downloadbusybox-w32-0d8b2c4a929ea9d3ac37499319fe0d8e7941a0c2.tar.gz
busybox-w32-0d8b2c4a929ea9d3ac37499319fe0d8e7941a0c2.tar.bz2
busybox-w32-0d8b2c4a929ea9d3ac37499319fe0d8e7941a0c2.zip
Merge commit '56a3b82e9692a25ef9c9269e88feac0d579ce8e8' into merge
Conflicts: coreutils/ls.c include/platform.h libbb/bb_basename.c
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c8
-rw-r--r--shell/hush.c717
-rw-r--r--shell/hush_test/hush-misc/assignment4.right1
-rwxr-xr-xshell/hush_test/hush-misc/assignment4.tests3
-rw-r--r--shell/hush_test/hush-misc/while3.right1
-rwxr-xr-xshell/hush_test/hush-misc/while3.tests4
-rw-r--r--shell/hush_test/hush-trap/signal_read1.right1
-rwxr-xr-xshell/hush_test/hush-trap/signal_read1.tests5
-rw-r--r--shell/hush_test/hush-trap/signal_read2.right2
-rwxr-xr-xshell/hush_test/hush-trap/signal_read2.tests7
-rwxr-xr-xshell/hush_test/run-all10
-rw-r--r--shell/shell_common.c43
12 files changed, 537 insertions, 265 deletions
diff --git a/shell/ash.c b/shell/ash.c
index eaaa71967..a809bf181 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6276,7 +6276,7 @@ expbackq(union node *cmd, int quoted, int quotes)
6276 read: 6276 read:
6277 if (in.fd < 0) 6277 if (in.fd < 0)
6278 break; 6278 break;
6279 i = nonblock_safe_read(in.fd, buf, sizeof(buf)); 6279 i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1);
6280 TRACE(("expbackq: read returns %d\n", i)); 6280 TRACE(("expbackq: read returns %d\n", i));
6281 if (i <= 0) 6281 if (i <= 0)
6282 break; 6282 break;
@@ -10120,7 +10120,7 @@ preadfd(void)
10120#if ENABLE_FEATURE_EDITING 10120#if ENABLE_FEATURE_EDITING
10121 retry: 10121 retry:
10122 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) 10122 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10123 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 10123 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
10124 else { 10124 else {
10125 int timeout = -1; 10125 int timeout = -1;
10126# if ENABLE_ASH_IDLE_TIMEOUT 10126# if ENABLE_ASH_IDLE_TIMEOUT
@@ -10166,10 +10166,10 @@ preadfd(void)
10166 } 10166 }
10167 } 10167 }
10168#else 10168#else
10169 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 10169 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
10170#endif 10170#endif
10171 10171
10172#if 0 /* disabled: nonblock_safe_read() handles this problem */ 10172#if 0 /* disabled: nonblock_immune_read() handles this problem */
10173 if (nr < 0) { 10173 if (nr < 0) {
10174 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 10174 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
10175 int flags = fcntl(0, F_GETFL); 10175 int flags = fcntl(0, F_GETFL);
diff --git a/shell/hush.c b/shell/hush.c
index d3e957c2f..1082738a2 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
@@ -256,7 +260,7 @@
256 * therefore we don't show them either. 260 * therefore we don't show them either.
257 */ 261 */
258//usage:#define hush_trivial_usage 262//usage:#define hush_trivial_usage
259//usage: "[-nx] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" 263//usage: "[-nxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
260//usage:#define hush_full_usage "\n\n" 264//usage:#define hush_full_usage "\n\n"
261//usage: "Unix shell interpreter" 265//usage: "Unix shell interpreter"
262 266
@@ -445,6 +449,15 @@ enum {
445/* Used for initialization: o_string foo = NULL_O_STRING; */ 449/* Used for initialization: o_string foo = NULL_O_STRING; */
446#define NULL_O_STRING { NULL } 450#define NULL_O_STRING { NULL }
447 451
452#ifndef debug_printf_parse
453static const char *const assignment_flag[] = {
454 "MAYBE_ASSIGNMENT",
455 "DEFINITELY_ASSIGNMENT",
456 "NOT_ASSIGNMENT",
457 "WORD_IS_KEYWORD",
458};
459#endif
460
448typedef struct in_str { 461typedef struct in_str {
449 const char *p; 462 const char *p;
450 /* eof_flag=1: last char in ->p is really an EOF */ 463 /* eof_flag=1: last char in ->p is really an EOF */
@@ -764,7 +777,6 @@ struct globals {
764 smalluint last_exitcode; 777 smalluint last_exitcode;
765 /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */ 778 /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */
766 smalluint global_args_malloced; 779 smalluint global_args_malloced;
767 smalluint inherited_set_is_saved;
768 /* how many non-NULL argv's we have. NB: $# + 1 */ 780 /* how many non-NULL argv's we have. NB: $# + 1 */
769 int global_argc; 781 int global_argc;
770 char **global_argv; 782 char **global_argv;
@@ -792,15 +804,27 @@ struct globals {
792 unsigned handled_SIGCHLD; 804 unsigned handled_SIGCHLD;
793 smallint we_have_children; 805 smallint we_have_children;
794#endif 806#endif
795 /* which signals have non-DFL handler (even with no traps set)? */ 807 /* Which signals have non-DFL handler (even with no traps set)?
796 unsigned non_DFL_mask; 808 * Set at the start to:
809 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS)
810 * SPECIAL_INTERACTIVE_SIGS are cleared after fork.
811 * The rest is cleared right before execv syscalls.
812 * Other than these two times, never modified.
813 */
814 unsigned special_sig_mask;
815#if ENABLE_HUSH_JOB
816 unsigned fatal_sig_mask;
817# define G_fatal_sig_mask G.fatal_sig_mask
818#else
819# define G_fatal_sig_mask 0
820#endif
797 char **traps; /* char *traps[NSIG] */ 821 char **traps; /* char *traps[NSIG] */
798 sigset_t blocked_set; 822 sigset_t pending_set;
799 sigset_t inherited_set;
800#if HUSH_DEBUG 823#if HUSH_DEBUG
801 unsigned long memleak_value; 824 unsigned long memleak_value;
802 int debug_indent; 825 int debug_indent;
803#endif 826#endif
827 struct sigaction sa;
804 char user_input_buf[ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 2]; 828 char user_input_buf[ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 2];
805}; 829};
806#define G (*ptr_to_globals) 830#define G (*ptr_to_globals)
@@ -809,6 +833,9 @@ struct globals {
809 * is global, thus "G." prefix is a useful hint */ 833 * is global, thus "G." prefix is a useful hint */
810#define INIT_G() do { \ 834#define INIT_G() do { \
811 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 835 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
836 /* memset(&G.sa, 0, sizeof(G.sa)); */ \
837 sigfillset(&G.sa.sa_mask); \
838 G.sa.sa_flags = SA_RESTART; \
812} while (0) 839} while (0)
813 840
814 841
@@ -1319,12 +1346,14 @@ static void restore_G_args(save_arg_t *sv, char **argv)
1319 * "echo $$; sleep 5 & wait; ls -l" + "kill -INT <pid>" 1346 * "echo $$; sleep 5 & wait; ls -l" + "kill -INT <pid>"
1320 * Example 3: this does not wait 5 sec, but executes ls: 1347 * Example 3: this does not wait 5 sec, but executes ls:
1321 * "sleep 5; ls -l" + press ^C 1348 * "sleep 5; ls -l" + press ^C
1349 * Example 4: this does not wait and does not execute ls:
1350 * "sleep 5 & wait; ls -l" + press ^C
1322 * 1351 *
1323 * (What happens to signals which are IGN on shell start?) 1352 * (What happens to signals which are IGN on shell start?)
1324 * (What happens with signal mask on shell start?) 1353 * (What happens with signal mask on shell start?)
1325 * 1354 *
1326 * Implementation in hush 1355 * Old implementation
1327 * ====================== 1356 * ==================
1328 * We use in-kernel pending signal mask to determine which signals were sent. 1357 * We use in-kernel pending signal mask to determine which signals were sent.
1329 * We block all signals which we don't want to take action immediately, 1358 * We block all signals which we don't want to take action immediately,
1330 * i.e. we block all signals which need to have special handling as described 1359 * i.e. we block all signals which need to have special handling as described
@@ -1332,11 +1361,11 @@ static void restore_G_args(save_arg_t *sv, char **argv)
1332 * After each pipe execution, we extract any pending signals via sigtimedwait() 1361 * After each pipe execution, we extract any pending signals via sigtimedwait()
1333 * and act on them. 1362 * and act on them.
1334 * 1363 *
1335 * unsigned non_DFL_mask: a mask of such "special" signals 1364 * unsigned special_sig_mask: a mask of such "special" signals
1336 * sigset_t blocked_set: current blocked signal set 1365 * sigset_t blocked_set: current blocked signal set
1337 * 1366 *
1338 * "trap - SIGxxx": 1367 * "trap - SIGxxx":
1339 * clear bit in blocked_set unless it is also in non_DFL_mask 1368 * clear bit in blocked_set unless it is also in special_sig_mask
1340 * "trap 'cmd' SIGxxx": 1369 * "trap 'cmd' SIGxxx":
1341 * set bit in blocked_set (even if 'cmd' is '') 1370 * set bit in blocked_set (even if 'cmd' is '')
1342 * after [v]fork, if we plan to be a shell: 1371 * after [v]fork, if we plan to be a shell:
@@ -1355,6 +1384,49 @@ static void restore_G_args(save_arg_t *sv, char **argv)
1355 * Standard says "When a subshell is entered, traps that are not being ignored 1384 * Standard says "When a subshell is entered, traps that are not being ignored
1356 * are set to the default actions". bash interprets it so that traps which 1385 * are set to the default actions". bash interprets it so that traps which
1357 * are set to '' (ignore) are NOT reset to defaults. We do the same. 1386 * are set to '' (ignore) are NOT reset to defaults. We do the same.
1387 *
1388 * Problem: the above approach makes it unwieldy to catch signals while
1389 * we are in read builtin, of while we read commands from stdin:
1390 * masked signals are not visible!
1391 *
1392 * New implementation
1393 * ==================
1394 * We record each signal we are interested in by installing signal handler
1395 * for them - a bit like emulating kernel pending signal mask in userspace.
1396 * We are interested in: signals which need to have special handling
1397 * as described above, and all signals which have traps set.
1398 * Signals are rocorded in pending_set.
1399 * After each pipe execution, we extract any pending signals
1400 * and act on them.
1401 *
1402 * unsigned special_sig_mask: a mask of shell-special signals.
1403 * unsigned fatal_sig_mask: a mask of signals on which we restore tty pgrp.
1404 * char *traps[sig] if trap for sig is set (even if it's '').
1405 * sigset_t pending_set: set of sigs we received.
1406 *
1407 * "trap - SIGxxx":
1408 * if sig is in special_sig_mask, set handler back to:
1409 * record_pending_signo, or to IGN if it's a tty stop signal
1410 * if sig is in fatal_sig_mask, set handler back to sigexit.
1411 * else: set handler back to SIG_DFL
1412 * "trap 'cmd' SIGxxx":
1413 * set handler to record_pending_signo.
1414 * "trap '' SIGxxx":
1415 * set handler to SIG_IGN.
1416 * after [v]fork, if we plan to be a shell:
1417 * set signals with special interactive handling to SIG_DFL
1418 * (because child shell is not interactive),
1419 * unset all traps except '' (note: regardless of child shell's type - {}, (), etc)
1420 * after [v]fork, if we plan to exec:
1421 * POSIX says fork clears pending signal mask in child - no need to clear it.
1422 *
1423 * To make wait builtin interruptible, we handle SIGCHLD as special signal,
1424 * otherwise (if we leave it SIG_DFL) sigsuspend in wait builtin will not wake up on it.
1425 *
1426 * Note (compat):
1427 * Standard says "When a subshell is entered, traps that are not being ignored
1428 * are set to the default actions". bash interprets it so that traps which
1429 * are set to '' (ignore) are NOT reset to defaults. We do the same.
1358 */ 1430 */
1359enum { 1431enum {
1360 SPECIAL_INTERACTIVE_SIGS = 0 1432 SPECIAL_INTERACTIVE_SIGS = 0
@@ -1362,21 +1434,43 @@ enum {
1362 | (1 << SIGINT) 1434 | (1 << SIGINT)
1363 | (1 << SIGHUP) 1435 | (1 << SIGHUP)
1364 , 1436 ,
1365 SPECIAL_JOB_SIGS = 0 1437 SPECIAL_JOBSTOP_SIGS = 0
1366#if ENABLE_HUSH_JOB 1438#if ENABLE_HUSH_JOB
1367 | (1 << SIGTTIN) 1439 | (1 << SIGTTIN)
1368 | (1 << SIGTTOU) 1440 | (1 << SIGTTOU)
1369 | (1 << SIGTSTP) 1441 | (1 << SIGTSTP)
1370#endif 1442#endif
1443 ,
1371}; 1444};
1372 1445
1373#if ENABLE_HUSH_FAST 1446static void record_pending_signo(int sig)
1374static void SIGCHLD_handler(int sig UNUSED_PARAM)
1375{ 1447{
1376 G.count_SIGCHLD++; 1448 sigaddset(&G.pending_set, sig);
1449#if ENABLE_HUSH_FAST
1450 if (sig == SIGCHLD) {
1451 G.count_SIGCHLD++;
1377//bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 1452//bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
1378} 1453 }
1379#endif 1454#endif
1455}
1456
1457static sighandler_t install_sighandler(int sig, sighandler_t handler)
1458{
1459 struct sigaction old_sa;
1460
1461 /* We could use signal() to install handlers... almost:
1462 * except that we need to mask ALL signals while handlers run.
1463 * I saw signal nesting in strace, race window isn't small.
1464 * SA_RESTART is also needed, but in Linux, signal()
1465 * sets SA_RESTART too.
1466 */
1467 /* memset(&G.sa, 0, sizeof(G.sa)); - already done */
1468 /* sigfillset(&G.sa.sa_mask); - already done */
1469 /* G.sa.sa_flags = SA_RESTART; - already done */
1470 G.sa.sa_handler = handler;
1471 sigaction(sig, &G.sa, &old_sa);
1472 return old_sa.sa_handler;
1473}
1380 1474
1381#if ENABLE_HUSH_JOB 1475#if ENABLE_HUSH_JOB
1382 1476
@@ -1393,13 +1487,15 @@ static void SIGCHLD_handler(int sig UNUSED_PARAM)
1393static void sigexit(int sig) NORETURN; 1487static void sigexit(int sig) NORETURN;
1394static void sigexit(int sig) 1488static void sigexit(int sig)
1395{ 1489{
1396 /* Disable all signals: job control, SIGPIPE, etc. */
1397 sigprocmask_allsigs(SIG_BLOCK);
1398
1399 /* Careful: we can end up here after [v]fork. Do not restore 1490 /* Careful: we can end up here after [v]fork. Do not restore
1400 * tty pgrp then, only top-level shell process does that */ 1491 * tty pgrp then, only top-level shell process does that */
1401 if (G_saved_tty_pgrp && getpid() == G.root_pid) 1492 if (G_saved_tty_pgrp && getpid() == G.root_pid) {
1493 /* Disable all signals: job control, SIGPIPE, etc.
1494 * Mostly paranoid measure, to prevent infinite SIGTTOU.
1495 */
1496 sigprocmask_allsigs(SIG_BLOCK);
1402 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp); 1497 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp);
1498 }
1403 1499
1404 /* Not a signal, just exit */ 1500 /* Not a signal, just exit */
1405 if (sig <= 0) 1501 if (sig <= 0)
@@ -1414,15 +1510,39 @@ static void sigexit(int sig)
1414 1510
1415#endif 1511#endif
1416 1512
1513static sighandler_t pick_sighandler(unsigned sig)
1514{
1515 sighandler_t handler = SIG_DFL;
1516 if (sig < sizeof(unsigned)*8) {
1517 unsigned sigmask = (1 << sig);
1518
1519#if ENABLE_HUSH_JOB
1520 /* is sig fatal? */
1521 if (G_fatal_sig_mask & sigmask)
1522 handler = sigexit;
1523 else
1524#endif
1525 /* sig has special handling? */
1526 if (G.special_sig_mask & sigmask) {
1527 handler = record_pending_signo;
1528 /* TTIN/TTOU/TSTP can't be set to record_pending_signo
1529 * in order to ignore them: they will be raised
1530 * in an endless loop when we try to do some
1531 * terminal ioctls! We do have to _ignore_ these.
1532 */
1533 if (SPECIAL_JOBSTOP_SIGS & sigmask)
1534 handler = SIG_IGN;
1535 }
1536 }
1537 return handler;
1538}
1539
1417/* Restores tty foreground process group, and exits. */ 1540/* Restores tty foreground process group, and exits. */
1418static void hush_exit(int exitcode) NORETURN; 1541static void hush_exit(int exitcode) NORETURN;
1419static void hush_exit(int exitcode) 1542static void hush_exit(int exitcode)
1420{ 1543{
1421 fflush_all(); 1544 fflush_all();
1422 if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { 1545 if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) {
1423 /* Prevent recursion:
1424 * trap "echo Hi; exit" EXIT; exit
1425 */
1426 char *argv[3]; 1546 char *argv[3];
1427 /* argv[0] is unused */ 1547 /* argv[0] is unused */
1428 argv[1] = G.traps[0]; 1548 argv[1] = G.traps[0];
@@ -1459,28 +1579,30 @@ static void hush_exit(int exitcode)
1459} 1579}
1460 1580
1461 1581
1462static int check_and_run_traps(int sig) 1582//TODO: return a mask of ALL handled sigs?
1583static int check_and_run_traps(void)
1463{ 1584{
1464 /* I want it in rodata, not in bss.
1465 * gcc 4.2.1 puts it in rodata only if it has { 0, 0 }
1466 * initializer. But other compilers may still use bss.
1467 * TODO: find more portable solution.
1468 */
1469 static const struct timespec zero_timespec = { 0, 0 };
1470 smalluint save_rcode;
1471 int last_sig = 0; 1585 int last_sig = 0;
1472 1586
1473 if (sig)
1474 goto jump_in;
1475 while (1) { 1587 while (1) {
1476 sig = sigtimedwait(&G.blocked_set, NULL, &zero_timespec); 1588 int sig;
1477 if (sig <= 0) 1589
1590 if (sigisemptyset(&G.pending_set))
1478 break; 1591 break;
1479 jump_in: 1592 sig = 0;
1480 last_sig = sig; 1593 do {
1594 sig++;
1595 if (sigismember(&G.pending_set, sig)) {
1596 sigdelset(&G.pending_set, sig);
1597 goto got_sig;
1598 }
1599 } while (sig < NSIG);
1600 break;
1601 got_sig:
1481 if (G.traps && G.traps[sig]) { 1602 if (G.traps && G.traps[sig]) {
1482 if (G.traps[sig][0]) { 1603 if (G.traps[sig][0]) {
1483 /* We have user-defined handler */ 1604 /* We have user-defined handler */
1605 smalluint save_rcode;
1484 char *argv[3]; 1606 char *argv[3];
1485 /* argv[0] is unused */ 1607 /* argv[0] is unused */
1486 argv[1] = G.traps[sig]; 1608 argv[1] = G.traps[sig];
@@ -1488,21 +1610,17 @@ static int check_and_run_traps(int sig)
1488 save_rcode = G.last_exitcode; 1610 save_rcode = G.last_exitcode;
1489 builtin_eval(argv); 1611 builtin_eval(argv);
1490 G.last_exitcode = save_rcode; 1612 G.last_exitcode = save_rcode;
1613 last_sig = sig;
1491 } /* else: "" trap, ignoring signal */ 1614 } /* else: "" trap, ignoring signal */
1492 continue; 1615 continue;
1493 } 1616 }
1494 /* not a trap: special action */ 1617 /* not a trap: special action */
1495 switch (sig) { 1618 switch (sig) {
1496#if ENABLE_HUSH_FAST
1497 case SIGCHLD:
1498 G.count_SIGCHLD++;
1499//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
1500 break;
1501#endif
1502 case SIGINT: 1619 case SIGINT:
1503 /* Builtin was ^C'ed, make it look prettier: */ 1620 /* Builtin was ^C'ed, make it look prettier: */
1504 bb_putchar('\n'); 1621 bb_putchar('\n');
1505 G.flag_SIGINT = 1; 1622 G.flag_SIGINT = 1;
1623 last_sig = sig;
1506 break; 1624 break;
1507#if ENABLE_HUSH_JOB 1625#if ENABLE_HUSH_JOB
1508 case SIGHUP: { 1626 case SIGHUP: {
@@ -1519,8 +1637,23 @@ static int check_and_run_traps(int sig)
1519 sigexit(SIGHUP); 1637 sigexit(SIGHUP);
1520 } 1638 }
1521#endif 1639#endif
1640#if ENABLE_HUSH_FAST
1641 case SIGCHLD:
1642 G.count_SIGCHLD++;
1643//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
1644 /* Note:
1645 * We dont do 'last_sig = sig' here -> NOT returning this sig.
1646 * This simplifies wait builtin a bit.
1647 */
1648 break;
1649#endif
1522 default: /* ignored: */ 1650 default: /* ignored: */
1523 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */ 1651 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */
1652 /* Note:
1653 * We dont do 'last_sig = sig' here -> NOT returning this sig.
1654 * Example: wait is not interrupted by TERM
1655 * in interactive shell, because TERM is ignored.
1656 */
1524 break; 1657 break;
1525 } 1658 }
1526 } 1659 }
@@ -1911,7 +2044,7 @@ static void get_user_input(struct in_str *i)
1911 * only after <Enter>. (^C will work) */ 2044 * only after <Enter>. (^C will work) */
1912 r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1); 2045 r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1);
1913 /* catch *SIGINT* etc (^C is handled by read_line_input) */ 2046 /* catch *SIGINT* etc (^C is handled by read_line_input) */
1914 check_and_run_traps(0); 2047 check_and_run_traps();
1915 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ 2048 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */
1916 i->eof_flag = (r < 0); 2049 i->eof_flag = (r < 0);
1917 if (i->eof_flag) { /* EOF/error detected */ 2050 if (i->eof_flag) { /* EOF/error detected */
@@ -1921,11 +2054,18 @@ static void get_user_input(struct in_str *i)
1921# else 2054# else
1922 do { 2055 do {
1923 G.flag_SIGINT = 0; 2056 G.flag_SIGINT = 0;
1924 fputs(prompt_str, stdout); 2057 if (i->last_char == '\0' || i->last_char == '\n') {
2058 /* Why check_and_run_traps here? Try this interactively:
2059 * $ trap 'echo INT' INT; (sleep 2; kill -INT $$) &
2060 * $ <[enter], repeatedly...>
2061 * Without check_and_run_traps, handler never runs.
2062 */
2063 check_and_run_traps();
2064 fputs(prompt_str, stdout);
2065 }
1925 fflush_all(); 2066 fflush_all();
1926 G.user_input_buf[0] = r = fgetc(i->file); 2067 G.user_input_buf[0] = r = fgetc(i->file);
1927 /*G.user_input_buf[1] = '\0'; - already is and never changed */ 2068 /*G.user_input_buf[1] = '\0'; - already is and never changed */
1928//do we need check_and_run_traps(0)? (maybe only if stdin)
1929 } while (G.flag_SIGINT); 2069 } while (G.flag_SIGINT);
1930 i->eof_flag = (r == EOF); 2070 i->eof_flag = (r == EOF);
1931# endif 2071# endif
@@ -2902,24 +3042,24 @@ static const struct reserved_combo* match_reserved_word(o_string *word)
2902 */ 3042 */
2903 static const struct reserved_combo reserved_list[] = { 3043 static const struct reserved_combo reserved_list[] = {
2904# if ENABLE_HUSH_IF 3044# if ENABLE_HUSH_IF
2905 { "!", RES_NONE, NOT_ASSIGNMENT , 0 }, 3045 { "!", RES_NONE, NOT_ASSIGNMENT , 0 },
2906 { "if", RES_IF, WORD_IS_KEYWORD, FLAG_THEN | FLAG_START }, 3046 { "if", RES_IF, MAYBE_ASSIGNMENT, FLAG_THEN | FLAG_START },
2907 { "then", RES_THEN, WORD_IS_KEYWORD, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, 3047 { "then", RES_THEN, MAYBE_ASSIGNMENT, FLAG_ELIF | FLAG_ELSE | FLAG_FI },
2908 { "elif", RES_ELIF, WORD_IS_KEYWORD, FLAG_THEN }, 3048 { "elif", RES_ELIF, MAYBE_ASSIGNMENT, FLAG_THEN },
2909 { "else", RES_ELSE, WORD_IS_KEYWORD, FLAG_FI }, 3049 { "else", RES_ELSE, MAYBE_ASSIGNMENT, FLAG_FI },
2910 { "fi", RES_FI, NOT_ASSIGNMENT , FLAG_END }, 3050 { "fi", RES_FI, NOT_ASSIGNMENT , FLAG_END },
2911# endif 3051# endif
2912# if ENABLE_HUSH_LOOPS 3052# if ENABLE_HUSH_LOOPS
2913 { "for", RES_FOR, NOT_ASSIGNMENT , FLAG_IN | FLAG_DO | FLAG_START }, 3053 { "for", RES_FOR, NOT_ASSIGNMENT , FLAG_IN | FLAG_DO | FLAG_START },
2914 { "while", RES_WHILE, WORD_IS_KEYWORD, FLAG_DO | FLAG_START }, 3054 { "while", RES_WHILE, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START },
2915 { "until", RES_UNTIL, WORD_IS_KEYWORD, FLAG_DO | FLAG_START }, 3055 { "until", RES_UNTIL, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START },
2916 { "in", RES_IN, NOT_ASSIGNMENT , FLAG_DO }, 3056 { "in", RES_IN, NOT_ASSIGNMENT , FLAG_DO },
2917 { "do", RES_DO, WORD_IS_KEYWORD, FLAG_DONE }, 3057 { "do", RES_DO, MAYBE_ASSIGNMENT, FLAG_DONE },
2918 { "done", RES_DONE, NOT_ASSIGNMENT , FLAG_END }, 3058 { "done", RES_DONE, NOT_ASSIGNMENT , FLAG_END },
2919# endif 3059# endif
2920# if ENABLE_HUSH_CASE 3060# if ENABLE_HUSH_CASE
2921 { "case", RES_CASE, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_START }, 3061 { "case", RES_CASE, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_START },
2922 { "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END }, 3062 { "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END },
2923# endif 3063# endif
2924 }; 3064 };
2925 const struct reserved_combo *r; 3065 const struct reserved_combo *r;
@@ -2985,6 +3125,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
2985 ctx->ctx_res_w = r->res; 3125 ctx->ctx_res_w = r->res;
2986 ctx->old_flag = r->flag; 3126 ctx->old_flag = r->flag;
2987 word->o_assignment = r->assignment_flag; 3127 word->o_assignment = r->assignment_flag;
3128 debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]);
2988 3129
2989 if (ctx->old_flag & FLAG_END) { 3130 if (ctx->old_flag & FLAG_END) {
2990 struct parse_context *old; 3131 struct parse_context *old;
@@ -3051,18 +3192,6 @@ static int done_word(o_string *word, struct parse_context *ctx)
3051 debug_printf_parse("word stored in rd_filename: '%s'\n", word->data); 3192 debug_printf_parse("word stored in rd_filename: '%s'\n", word->data);
3052 ctx->pending_redirect = NULL; 3193 ctx->pending_redirect = NULL;
3053 } else { 3194 } else {
3054 /* If this word wasn't an assignment, next ones definitely
3055 * can't be assignments. Even if they look like ones. */
3056 if (word->o_assignment != DEFINITELY_ASSIGNMENT
3057 && word->o_assignment != WORD_IS_KEYWORD
3058 ) {
3059 word->o_assignment = NOT_ASSIGNMENT;
3060 } else {
3061 if (word->o_assignment == DEFINITELY_ASSIGNMENT)
3062 command->assignment_cnt++;
3063 word->o_assignment = MAYBE_ASSIGNMENT;
3064 }
3065
3066#if HAS_KEYWORDS 3195#if HAS_KEYWORDS
3067# if ENABLE_HUSH_CASE 3196# if ENABLE_HUSH_CASE
3068 if (ctx->ctx_dsemicolon 3197 if (ctx->ctx_dsemicolon
@@ -3082,8 +3211,9 @@ static int done_word(o_string *word, struct parse_context *ctx)
3082 && ctx->ctx_res_w != RES_CASE 3211 && ctx->ctx_res_w != RES_CASE
3083# endif 3212# endif
3084 ) { 3213 ) {
3085 debug_printf_parse("checking '%s' for reserved-ness\n", word->data); 3214 int reserved = reserved_word(word, ctx);
3086 if (reserved_word(word, ctx)) { 3215 debug_printf_parse("checking for reserved-ness: %d\n", reserved);
3216 if (reserved) {
3087 o_reset_to_empty_unquoted(word); 3217 o_reset_to_empty_unquoted(word);
3088 debug_printf_parse("done_word return %d\n", 3218 debug_printf_parse("done_word return %d\n",
3089 (ctx->ctx_res_w == RES_SNTX)); 3219 (ctx->ctx_res_w == RES_SNTX));
@@ -3104,6 +3234,23 @@ static int done_word(o_string *word, struct parse_context *ctx)
3104 "groups and arglists don't mix\n"); 3234 "groups and arglists don't mix\n");
3105 return 1; 3235 return 1;
3106 } 3236 }
3237
3238 /* If this word wasn't an assignment, next ones definitely
3239 * can't be assignments. Even if they look like ones. */
3240 if (word->o_assignment != DEFINITELY_ASSIGNMENT
3241 && word->o_assignment != WORD_IS_KEYWORD
3242 ) {
3243 word->o_assignment = NOT_ASSIGNMENT;
3244 } else {
3245 if (word->o_assignment == DEFINITELY_ASSIGNMENT) {
3246 command->assignment_cnt++;
3247 debug_printf_parse("++assignment_cnt=%d\n", command->assignment_cnt);
3248 }
3249 debug_printf_parse("word->o_assignment was:'%s'\n", assignment_flag[word->o_assignment]);
3250 word->o_assignment = MAYBE_ASSIGNMENT;
3251 }
3252 debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]);
3253
3107 if (word->has_quoted_part 3254 if (word->has_quoted_part
3108 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ 3255 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */
3109 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) 3256 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL)
@@ -3322,6 +3469,7 @@ static char *fetch_till_str(o_string *as_string,
3322 int ch; 3469 int ch;
3323 3470
3324 goto jump_in; 3471 goto jump_in;
3472
3325 while (1) { 3473 while (1) {
3326 ch = i_getch(input); 3474 ch = i_getch(input);
3327 if (ch != EOF) 3475 if (ch != EOF)
@@ -4127,6 +4275,7 @@ static struct pipe *parse_stream(char **pstring,
4127 && is_well_formed_var_name(dest.data, '=') 4275 && is_well_formed_var_name(dest.data, '=')
4128 ) { 4276 ) {
4129 dest.o_assignment = DEFINITELY_ASSIGNMENT; 4277 dest.o_assignment = DEFINITELY_ASSIGNMENT;
4278 debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]);
4130 } 4279 }
4131 continue; 4280 continue;
4132 } 4281 }
@@ -4176,6 +4325,7 @@ static struct pipe *parse_stream(char **pstring,
4176 heredoc_cnt = 0; 4325 heredoc_cnt = 0;
4177 } 4326 }
4178 dest.o_assignment = MAYBE_ASSIGNMENT; 4327 dest.o_assignment = MAYBE_ASSIGNMENT;
4328 debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]);
4179 ch = ';'; 4329 ch = ';';
4180 /* note: if (is_blank) continue; 4330 /* note: if (is_blank) continue;
4181 * will still trigger for us */ 4331 * will still trigger for us */
@@ -4225,6 +4375,7 @@ static struct pipe *parse_stream(char **pstring,
4225 } 4375 }
4226 done_pipe(&ctx, PIPE_SEQ); 4376 done_pipe(&ctx, PIPE_SEQ);
4227 dest.o_assignment = MAYBE_ASSIGNMENT; 4377 dest.o_assignment = MAYBE_ASSIGNMENT;
4378 debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]);
4228 /* Do we sit outside of any if's, loops or case's? */ 4379 /* Do we sit outside of any if's, loops or case's? */
4229 if (!HAS_KEYWORDS 4380 if (!HAS_KEYWORDS
4230 IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) 4381 IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0))
@@ -4331,6 +4482,7 @@ static struct pipe *parse_stream(char **pstring,
4331 /* ch is a special char and thus this word 4482 /* ch is a special char and thus this word
4332 * cannot be an assignment */ 4483 * cannot be an assignment */
4333 dest.o_assignment = NOT_ASSIGNMENT; 4484 dest.o_assignment = NOT_ASSIGNMENT;
4485 debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]);
4334 } 4486 }
4335 4487
4336 /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ 4488 /* Note: nommu_addchr(&ctx.as_string, ch) is already done */
@@ -4385,11 +4537,11 @@ static struct pipe *parse_stream(char **pstring,
4385 break; 4537 break;
4386#if ENABLE_HUSH_TICK 4538#if ENABLE_HUSH_TICK
4387 case '`': { 4539 case '`': {
4388 unsigned pos; 4540 USE_FOR_NOMMU(unsigned pos;)
4389 4541
4390 o_addchr(&dest, SPECIAL_VAR_SYMBOL); 4542 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
4391 o_addchr(&dest, '`'); 4543 o_addchr(&dest, '`');
4392 pos = dest.length; 4544 USE_FOR_NOMMU(pos = dest.length;)
4393 if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0)) 4545 if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0))
4394 goto parse_error; 4546 goto parse_error;
4395# if !BB_MMU 4547# if !BB_MMU
@@ -4429,6 +4581,7 @@ static struct pipe *parse_stream(char **pstring,
4429 /* We just finished a cmd. New one may start 4581 /* We just finished a cmd. New one may start
4430 * with an assignment */ 4582 * with an assignment */
4431 dest.o_assignment = MAYBE_ASSIGNMENT; 4583 dest.o_assignment = MAYBE_ASSIGNMENT;
4584 debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]);
4432 break; 4585 break;
4433 case '&': 4586 case '&':
4434 if (done_word(&dest, &ctx)) { 4587 if (done_word(&dest, &ctx)) {
@@ -5323,6 +5476,25 @@ void re_execute_shell(char ***to_free, const char *s,
5323 char *g_argv0, char **g_argv, 5476 char *g_argv0, char **g_argv,
5324 char **builtin_argv) NORETURN; 5477 char **builtin_argv) NORETURN;
5325 5478
5479static void switch_off_special_sigs(unsigned mask)
5480{
5481 unsigned sig = 0;
5482 while ((mask >>= 1) != 0) {
5483 sig++;
5484 if (!(mask & 1))
5485 continue;
5486 if (G.traps) {
5487 if (G.traps[sig] && !G.traps[sig][0])
5488 /* trap is '', has to remain SIG_IGN */
5489 continue;
5490 free(G.traps[sig]);
5491 G.traps[sig] = NULL;
5492 }
5493 /* We are here only if no trap or trap was not '' */
5494 install_sighandler(sig, SIG_DFL);
5495 }
5496}
5497
5326static void reset_traps_to_defaults(void) 5498static void reset_traps_to_defaults(void)
5327{ 5499{
5328 /* This function is always called in a child shell 5500 /* This function is always called in a child shell
@@ -5336,47 +5508,36 @@ static void reset_traps_to_defaults(void)
5336 * Testcase: (while :; do :; done) + ^Z should background. 5508 * Testcase: (while :; do :; done) + ^Z should background.
5337 * Same goes for SIGTERM, SIGHUP, SIGINT. 5509 * Same goes for SIGTERM, SIGHUP, SIGINT.
5338 */ 5510 */
5339 if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS)) 5511 mask = (G.special_sig_mask & SPECIAL_INTERACTIVE_SIGS) | G_fatal_sig_mask;
5340 return; /* already no traps and no SPECIAL_INTERACTIVE_SIGS */ 5512 if (!G.traps && !mask)
5341 5513 return; /* already no traps and no special sigs */
5342 /* Switching off SPECIAL_INTERACTIVE_SIGS.
5343 * Stupid. It can be done with *single* &= op, but we can't use
5344 * the fact that G.blocked_set is implemented as a bitmask
5345 * in libc... */
5346 mask = (SPECIAL_INTERACTIVE_SIGS >> 1);
5347 sig = 1;
5348 while (1) {
5349 if (mask & 1) {
5350 /* Careful. Only if no trap or trap is not "" */
5351 if (!G.traps || !G.traps[sig] || G.traps[sig][0])
5352 sigdelset(&G.blocked_set, sig);
5353 }
5354 mask >>= 1;
5355 if (!mask)
5356 break;
5357 sig++;
5358 }
5359 /* Our homegrown sig mask is saner to work with :) */
5360 G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS;
5361 5514
5362 /* Resetting all traps to default except empty ones */ 5515 /* Switch off special sigs */
5363 mask = G.non_DFL_mask; 5516 switch_off_special_sigs(mask);
5364 if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) { 5517#if ENABLE_HUSH_JOB
5365 if (!G.traps[sig] || !G.traps[sig][0]) 5518 G_fatal_sig_mask = 0;
5366 continue; 5519#endif
5520 G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS;
5521 /* SIGQUIT,SIGCHLD and maybe SPECIAL_JOBSTOP_SIGS
5522 * remain set in G.special_sig_mask */
5523
5524 if (!G.traps)
5525 return;
5526
5527 /* Reset all sigs to default except ones with empty traps */
5528 for (sig = 0; sig < NSIG; sig++) {
5529 if (!G.traps[sig])
5530 continue; /* no trap: nothing to do */
5531 if (!G.traps[sig][0])
5532 continue; /* empty trap: has to remain SIG_IGN */
5533 /* sig has non-empty trap, reset it: */
5367 free(G.traps[sig]); 5534 free(G.traps[sig]);
5368 G.traps[sig] = NULL; 5535 G.traps[sig] = NULL;
5369 /* There is no signal for 0 (EXIT) */ 5536 /* There is no signal for trap 0 (EXIT) */
5370 if (sig == 0) 5537 if (sig == 0)
5371 continue; 5538 continue;
5372 /* There was a trap handler, we just removed it. 5539 install_sighandler(sig, pick_sighandler(sig));
5373 * But if sig still has non-DFL handling,
5374 * we should not unblock the sig. */
5375 if (mask & 1)
5376 continue;
5377 sigdelset(&G.blocked_set, sig);
5378 } 5540 }
5379 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
5380} 5541}
5381 5542
5382#else /* !BB_MMU */ 5543#else /* !BB_MMU */
@@ -5487,9 +5648,6 @@ static void re_execute_shell(char ***to_free, const char *s,
5487 * _inside_ group (just before echo 1), it works. 5648 * _inside_ group (just before echo 1), it works.
5488 * 5649 *
5489 * I conclude it means we don't need to pass active traps here. 5650 * I conclude it means we don't need to pass active traps here.
5490 * Even if we would use signal handlers instead of signal masking
5491 * in order to implement trap handling,
5492 * exec syscall below resets signals to SIG_DFL for us.
5493 */ 5651 */
5494 *pp++ = (char *) "-c"; 5652 *pp++ = (char *) "-c";
5495 *pp++ = (char *) s; 5653 *pp++ = (char *) s;
@@ -5506,7 +5664,9 @@ static void re_execute_shell(char ***to_free, const char *s,
5506 5664
5507 do_exec: 5665 do_exec:
5508 debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); 5666 debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s);
5509 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 5667 /* Don't propagate SIG_IGN to the child */
5668 if (SPECIAL_JOBSTOP_SIGS != 0)
5669 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
5510 execve(bb_busybox_exec_path, argv, pp); 5670 execve(bb_busybox_exec_path, argv, pp);
5511 /* Fallback. Useful for init=/bin/hush usage etc */ 5671 /* Fallback. Useful for init=/bin/hush usage etc */
5512 if (argv[0][0] == '/') 5672 if (argv[0][0] == '/')
@@ -6160,7 +6320,9 @@ static void execvp_or_die(char **argv) NORETURN;
6160static void execvp_or_die(char **argv) 6320static void execvp_or_die(char **argv)
6161{ 6321{
6162 debug_printf_exec("execing '%s'\n", argv[0]); 6322 debug_printf_exec("execing '%s'\n", argv[0]);
6163 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 6323 /* Don't propagate SIG_IGN to the child */
6324 if (SPECIAL_JOBSTOP_SIGS != 0)
6325 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
6164 execvp(argv[0], argv); 6326 execvp(argv[0], argv);
6165 bb_perror_msg("can't execute '%s'", argv[0]); 6327 bb_perror_msg("can't execute '%s'", argv[0]);
6166 _exit(127); /* bash compat */ 6328 _exit(127); /* bash compat */
@@ -6292,7 +6454,9 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
6292# endif 6454# endif
6293 /* Re-exec ourselves */ 6455 /* Re-exec ourselves */
6294 debug_printf_exec("re-execing applet '%s'\n", argv[0]); 6456 debug_printf_exec("re-execing applet '%s'\n", argv[0]);
6295 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 6457 /* Don't propagate SIG_IGN to the child */
6458 if (SPECIAL_JOBSTOP_SIGS != 0)
6459 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
6296 execv(bb_busybox_exec_path, argv); 6460 execv(bb_busybox_exec_path, argv);
6297 /* If they called chroot or otherwise made the binary no longer 6461 /* If they called chroot or otherwise made the binary no longer
6298 * executable, fall through */ 6462 * executable, fall through */
@@ -6991,9 +7155,6 @@ static NOINLINE int run_pipe(struct pipe *pi)
6991 if (setup_redirects(command, NULL)) 7155 if (setup_redirects(command, NULL))
6992 _exit(1); 7156 _exit(1);
6993 7157
6994 /* Restore default handlers just prior to exec */
6995 /*signal(SIGCHLD, SIG_DFL); - so far we don't have any handlers */
6996
6997 /* Stores to nommu_save list of env vars putenv'ed 7158 /* Stores to nommu_save list of env vars putenv'ed
6998 * (NOMMU, on MMU we don't need that) */ 7159 * (NOMMU, on MMU we don't need that) */
6999 /* cast away volatility... */ 7160 /* cast away volatility... */
@@ -7271,7 +7432,7 @@ static int run_list(struct pipe *pi)
7271 * and we don't need to wait for anything. */ 7432 * and we don't need to wait for anything. */
7272 G.last_exitcode = rcode; 7433 G.last_exitcode = rcode;
7273 debug_printf_exec(": builtin/func exitcode %d\n", rcode); 7434 debug_printf_exec(": builtin/func exitcode %d\n", rcode);
7274 check_and_run_traps(0); 7435 check_and_run_traps();
7275#if ENABLE_HUSH_LOOPS 7436#if ENABLE_HUSH_LOOPS
7276 /* Was it "break" or "continue"? */ 7437 /* Was it "break" or "continue"? */
7277 if (G.flag_break_continue) { 7438 if (G.flag_break_continue) {
@@ -7303,7 +7464,7 @@ static int run_list(struct pipe *pi)
7303 /* even bash 3.2 doesn't do that well with nested bg: 7464 /* even bash 3.2 doesn't do that well with nested bg:
7304 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". 7465 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".
7305 * I'm NOT treating inner &'s as jobs */ 7466 * I'm NOT treating inner &'s as jobs */
7306 check_and_run_traps(0); 7467 check_and_run_traps();
7307#if ENABLE_HUSH_JOB 7468#if ENABLE_HUSH_JOB
7308 if (G.run_list_level == 1) 7469 if (G.run_list_level == 1)
7309 insert_bg_job(pi); 7470 insert_bg_job(pi);
@@ -7318,13 +7479,13 @@ static int run_list(struct pipe *pi)
7318 /* Waits for completion, then fg's main shell */ 7479 /* Waits for completion, then fg's main shell */
7319 rcode = checkjobs_and_fg_shell(pi); 7480 rcode = checkjobs_and_fg_shell(pi);
7320 debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode); 7481 debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode);
7321 check_and_run_traps(0); 7482 check_and_run_traps();
7322 } else 7483 } else
7323#endif 7484#endif
7324 { /* This one just waits for completion */ 7485 { /* This one just waits for completion */
7325 rcode = checkjobs(pi); 7486 rcode = checkjobs(pi);
7326 debug_printf_exec(": checkjobs exitcode %d\n", rcode); 7487 debug_printf_exec(": checkjobs exitcode %d\n", rcode);
7327 check_and_run_traps(0); 7488 check_and_run_traps();
7328 } 7489 }
7329 G.last_exitcode = rcode; 7490 G.last_exitcode = rcode;
7330 } 7491 }
@@ -7337,7 +7498,10 @@ static int run_list(struct pipe *pi)
7337#endif 7498#endif
7338#if ENABLE_HUSH_LOOPS 7499#if ENABLE_HUSH_LOOPS
7339 /* Beware of "while false; true; do ..."! */ 7500 /* Beware of "while false; true; do ..."! */
7340 if (pi->next && pi->next->res_word == RES_DO) { 7501 if (pi->next
7502 && (pi->next->res_word == RES_DO || pi->next->res_word == RES_DONE)
7503 /* check for RES_DONE is needed for "while ...; do \n done" case */
7504 ) {
7341 if (rword == RES_WHILE) { 7505 if (rword == RES_WHILE) {
7342 if (rcode) { 7506 if (rcode) {
7343 /* "while false; do...done" - exitcode 0 */ 7507 /* "while false; do...done" - exitcode 0 */
@@ -7395,88 +7559,81 @@ static int run_and_free_list(struct pipe *pi)
7395} 7559}
7396 7560
7397 7561
7562static void install_sighandlers(unsigned mask)
7563{
7564 sighandler_t old_handler;
7565 unsigned sig = 0;
7566 while ((mask >>= 1) != 0) {
7567 sig++;
7568 if (!(mask & 1))
7569 continue;
7570 old_handler = install_sighandler(sig, pick_sighandler(sig));
7571 /* POSIX allows shell to re-enable SIGCHLD
7572 * even if it was SIG_IGN on entry.
7573 * Therefore we skip IGN check for it:
7574 */
7575 if (sig == SIGCHLD)
7576 continue;
7577 if (old_handler == SIG_IGN) {
7578 /* oops... restore back to IGN, and record this fact */
7579 install_sighandler(sig, old_handler);
7580 if (!G.traps)
7581 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
7582 free(G.traps[sig]);
7583 G.traps[sig] = xzalloc(1); /* == xstrdup(""); */
7584 }
7585 }
7586}
7587
7398/* Called a few times only (or even once if "sh -c") */ 7588/* Called a few times only (or even once if "sh -c") */
7399static void init_sigmasks(void) 7589static void install_special_sighandlers(void)
7400{ 7590{
7401 unsigned sig;
7402 unsigned mask; 7591 unsigned mask;
7403 sigset_t old_blocked_set;
7404
7405 if (!G.inherited_set_is_saved) {
7406 sigprocmask(SIG_SETMASK, NULL, &G.blocked_set);
7407 G.inherited_set = G.blocked_set;
7408 }
7409 old_blocked_set = G.blocked_set;
7410 7592
7411 mask = (1 << SIGQUIT); 7593 /* Which signals are shell-special? */
7594 mask = (1 << SIGQUIT) | (1 << SIGCHLD);
7412 if (G_interactive_fd) { 7595 if (G_interactive_fd) {
7413 mask = (1 << SIGQUIT) | SPECIAL_INTERACTIVE_SIGS; 7596 mask |= SPECIAL_INTERACTIVE_SIGS;
7414 if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ 7597 if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */
7415 mask |= SPECIAL_JOB_SIGS; 7598 mask |= SPECIAL_JOBSTOP_SIGS;
7416 } 7599 }
7417 G.non_DFL_mask = mask; 7600 /* Careful, do not re-install handlers we already installed */
7418 7601 if (G.special_sig_mask != mask) {
7419 sig = 0; 7602 unsigned diff = mask & ~G.special_sig_mask;
7420 while (mask) { 7603 G.special_sig_mask = mask;
7421 if (mask & 1) 7604 install_sighandlers(diff);
7422 sigaddset(&G.blocked_set, sig);
7423 mask >>= 1;
7424 sig++;
7425 } 7605 }
7426 sigdelset(&G.blocked_set, SIGCHLD);
7427
7428 if (memcmp(&old_blocked_set, &G.blocked_set, sizeof(old_blocked_set)) != 0)
7429 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
7430
7431 /* POSIX allows shell to re-enable SIGCHLD
7432 * even if it was SIG_IGN on entry */
7433#if ENABLE_HUSH_FAST
7434 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
7435 if (!G.inherited_set_is_saved)
7436 signal(SIGCHLD, SIGCHLD_handler);
7437#else
7438 if (!G.inherited_set_is_saved)
7439 signal(SIGCHLD, SIG_DFL);
7440#endif
7441
7442 G.inherited_set_is_saved = 1;
7443} 7606}
7444 7607
7445#if ENABLE_HUSH_JOB 7608#if ENABLE_HUSH_JOB
7446/* helper */ 7609/* helper */
7447static void maybe_set_to_sigexit(int sig)
7448{
7449 void (*handler)(int);
7450 /* non_DFL_mask'ed signals are, well, masked,
7451 * no need to set handler for them.
7452 */
7453 if (!((G.non_DFL_mask >> sig) & 1)) {
7454 handler = signal(sig, sigexit);
7455 if (handler == SIG_IGN) /* oops... restore back to IGN! */
7456 signal(sig, handler);
7457 }
7458}
7459/* Set handlers to restore tty pgrp and exit */ 7610/* Set handlers to restore tty pgrp and exit */
7460static void set_fatal_handlers(void) 7611static void install_fatal_sighandlers(void)
7461{ 7612{
7462 /* We _must_ restore tty pgrp on fatal signals */ 7613 unsigned mask;
7463 if (HUSH_DEBUG) { 7614
7464 maybe_set_to_sigexit(SIGILL ); 7615 /* We will restore tty pgrp on these signals */
7465 maybe_set_to_sigexit(SIGFPE ); 7616 mask = 0
7466 maybe_set_to_sigexit(SIGBUS ); 7617 + (1 << SIGILL ) * HUSH_DEBUG
7467 maybe_set_to_sigexit(SIGSEGV); 7618 + (1 << SIGFPE ) * HUSH_DEBUG
7468 maybe_set_to_sigexit(SIGTRAP); 7619 + (1 << SIGBUS ) * HUSH_DEBUG
7469 } /* else: hush is perfect. what SEGV? */ 7620 + (1 << SIGSEGV) * HUSH_DEBUG
7470 maybe_set_to_sigexit(SIGABRT); 7621 + (1 << SIGTRAP) * HUSH_DEBUG
7622 + (1 << SIGABRT)
7471 /* bash 3.2 seems to handle these just like 'fatal' ones */ 7623 /* bash 3.2 seems to handle these just like 'fatal' ones */
7472 maybe_set_to_sigexit(SIGPIPE); 7624 + (1 << SIGPIPE)
7473 maybe_set_to_sigexit(SIGALRM); 7625 + (1 << SIGALRM)
7474 /* if we are interactive, SIGHUP, SIGTERM and SIGINT are masked. 7626 /* if we are interactive, SIGHUP, SIGTERM and SIGINT are special sigs.
7475 * if we aren't interactive... but in this case 7627 * if we aren't interactive... but in this case
7476 * we never want to restore pgrp on exit, and this fn is not called */ 7628 * we never want to restore pgrp on exit, and this fn is not called
7477 /*maybe_set_to_sigexit(SIGHUP );*/ 7629 */
7478 /*maybe_set_to_sigexit(SIGTERM);*/ 7630 /*+ (1 << SIGHUP )*/
7479 /*maybe_set_to_sigexit(SIGINT );*/ 7631 /*+ (1 << SIGTERM)*/
7632 /*+ (1 << SIGINT )*/
7633 ;
7634 G_fatal_sig_mask = mask;
7635
7636 install_sighandlers(mask);
7480} 7637}
7481#endif 7638#endif
7482 7639
@@ -7522,6 +7679,10 @@ static int set_mode(int state, char mode, const char *o_opt)
7522int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 7679int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7523int hush_main(int argc, char **argv) 7680int hush_main(int argc, char **argv)
7524{ 7681{
7682 enum {
7683 OPT_login = (1 << 0),
7684 };
7685 unsigned flags;
7525 int opt; 7686 int opt;
7526 unsigned builtin_argc; 7687 unsigned builtin_argc;
7527 char **e; 7688 char **e;
@@ -7529,8 +7690,11 @@ int hush_main(int argc, char **argv)
7529 struct variable *shell_ver; 7690 struct variable *shell_ver;
7530 7691
7531 INIT_G(); 7692 INIT_G();
7532 if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */ 7693 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */
7533 G.last_exitcode = EXIT_SUCCESS; 7694 G.last_exitcode = EXIT_SUCCESS;
7695#if ENABLE_HUSH_FAST
7696 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
7697#endif
7534#if !BB_MMU 7698#if !BB_MMU
7535 G.argv0_for_re_execing = argv[0]; 7699 G.argv0_for_re_execing = argv[0];
7536#endif 7700#endif
@@ -7622,8 +7786,6 @@ int hush_main(int argc, char **argv)
7622# endif 7786# endif
7623#endif 7787#endif
7624 7788
7625 G.global_argc = argc;
7626 G.global_argv = argv;
7627 /* Initialize some more globals to non-zero values */ 7789 /* Initialize some more globals to non-zero values */
7628 cmdedit_update_prompt(); 7790 cmdedit_update_prompt();
7629 7791
@@ -7635,17 +7797,18 @@ int hush_main(int argc, char **argv)
7635 } 7797 }
7636 7798
7637 /* Shell is non-interactive at first. We need to call 7799 /* Shell is non-interactive at first. We need to call
7638 * init_sigmasks() if we are going to execute "sh <script>", 7800 * install_special_sighandlers() if we are going to execute "sh <script>",
7639 * "sh -c <cmds>" or login shell's /etc/profile and friends. 7801 * "sh -c <cmds>" or login shell's /etc/profile and friends.
7640 * If we later decide that we are interactive, we run init_sigmasks() 7802 * If we later decide that we are interactive, we run install_special_sighandlers()
7641 * in order to intercept (more) signals. 7803 * in order to intercept (more) signals.
7642 */ 7804 */
7643 7805
7644 /* Parse options */ 7806 /* Parse options */
7645 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ 7807 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */
7808 flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0;
7646 builtin_argc = 0; 7809 builtin_argc = 0;
7647 while (1) { 7810 while (1) {
7648 opt = getopt(argc, argv, "+c:xins" 7811 opt = getopt(argc, argv, "+c:xinsl"
7649#if !BB_MMU 7812#if !BB_MMU
7650 "<:$:R:V:" 7813 "<:$:R:V:"
7651# if ENABLE_HUSH_FUNCTIONS 7814# if ENABLE_HUSH_FUNCTIONS
@@ -7677,7 +7840,7 @@ int hush_main(int argc, char **argv)
7677 /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */ 7840 /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */
7678 const struct built_in_command *x; 7841 const struct built_in_command *x;
7679 7842
7680 init_sigmasks(); 7843 install_special_sighandlers();
7681 x = find_builtin(optarg); 7844 x = find_builtin(optarg);
7682 if (x) { /* paranoia */ 7845 if (x) { /* paranoia */
7683 G.global_argc -= builtin_argc; /* skip [BARGV...] "" */ 7846 G.global_argc -= builtin_argc; /* skip [BARGV...] "" */
@@ -7694,7 +7857,7 @@ int hush_main(int argc, char **argv)
7694 G.global_argv[0] = argv[0]; 7857 G.global_argv[0] = argv[0];
7695 G.global_argc++; 7858 G.global_argc++;
7696 } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */ 7859 } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */
7697 init_sigmasks(); 7860 install_special_sighandlers();
7698 parse_and_run_string(optarg); 7861 parse_and_run_string(optarg);
7699 goto final_return; 7862 goto final_return;
7700 case 'i': 7863 case 'i':
@@ -7706,6 +7869,9 @@ int hush_main(int argc, char **argv)
7706 /* "-s" means "read from stdin", but this is how we always 7869 /* "-s" means "read from stdin", but this is how we always
7707 * operate, so simply do nothing here. */ 7870 * operate, so simply do nothing here. */
7708 break; 7871 break;
7872 case 'l':
7873 flags |= OPT_login;
7874 break;
7709#if !BB_MMU 7875#if !BB_MMU
7710 case '<': /* "big heredoc" support */ 7876 case '<': /* "big heredoc" support */
7711 full_write1_str(optarg); 7877 full_write1_str(optarg);
@@ -7726,15 +7892,14 @@ int hush_main(int argc, char **argv)
7726 empty_trap_mask = bb_strtoull(optarg, &optarg, 16); 7892 empty_trap_mask = bb_strtoull(optarg, &optarg, 16);
7727 if (empty_trap_mask != 0) { 7893 if (empty_trap_mask != 0) {
7728 int sig; 7894 int sig;
7729 init_sigmasks(); 7895 install_special_sighandlers();
7730 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); 7896 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
7731 for (sig = 1; sig < NSIG; sig++) { 7897 for (sig = 1; sig < NSIG; sig++) {
7732 if (empty_trap_mask & (1LL << sig)) { 7898 if (empty_trap_mask & (1LL << sig)) {
7733 G.traps[sig] = xzalloc(1); /* == xstrdup(""); */ 7899 G.traps[sig] = xzalloc(1); /* == xstrdup(""); */
7734 sigaddset(&G.blocked_set, sig); 7900 install_sighandler(sig, SIG_IGN);
7735 } 7901 }
7736 } 7902 }
7737 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
7738 } 7903 }
7739# if ENABLE_HUSH_LOOPS 7904# if ENABLE_HUSH_LOOPS
7740 optarg++; 7905 optarg++;
@@ -7772,19 +7937,24 @@ int hush_main(int argc, char **argv)
7772 } 7937 }
7773 } /* option parsing loop */ 7938 } /* option parsing loop */
7774 7939
7940 /* Skip options. Try "hush -l": $1 should not be "-l"! */
7941 G.global_argc = argc - (optind - 1);
7942 G.global_argv = argv + (optind - 1);
7943 G.global_argv[0] = argv[0];
7944
7775 if (!G.root_pid) { 7945 if (!G.root_pid) {
7776 G.root_pid = getpid(); 7946 G.root_pid = getpid();
7777 G.root_ppid = getppid(); 7947 G.root_ppid = getppid();
7778 } 7948 }
7779 7949
7780 /* If we are login shell... */ 7950 /* If we are login shell... */
7781 if (argv[0] && argv[0][0] == '-') { 7951 if (flags & OPT_login) {
7782 FILE *input; 7952 FILE *input;
7783 debug_printf("sourcing /etc/profile\n"); 7953 debug_printf("sourcing /etc/profile\n");
7784 input = fopen_for_read("/etc/profile"); 7954 input = fopen_for_read("/etc/profile");
7785 if (input != NULL) { 7955 if (input != NULL) {
7786 close_on_exec_on(fileno(input)); 7956 close_on_exec_on(fileno(input));
7787 init_sigmasks(); 7957 install_special_sighandlers();
7788 parse_and_run_file(input); 7958 parse_and_run_file(input);
7789 fclose(input); 7959 fclose(input);
7790 } 7960 }
@@ -7797,19 +7967,19 @@ int hush_main(int argc, char **argv)
7797 */ 7967 */
7798 } 7968 }
7799 7969
7800 if (argv[optind]) { 7970 if (G.global_argv[1]) {
7801 FILE *input; 7971 FILE *input;
7802 /* 7972 /*
7803 * "bash <script>" (which is never interactive (unless -i?)) 7973 * "bash <script>" (which is never interactive (unless -i?))
7804 * sources $BASH_ENV here (without scanning $PATH). 7974 * sources $BASH_ENV here (without scanning $PATH).
7805 * If called as sh, does the same but with $ENV. 7975 * If called as sh, does the same but with $ENV.
7806 */ 7976 */
7807 debug_printf("running script '%s'\n", argv[optind]); 7977 G.global_argc--;
7808 G.global_argv = argv + optind; 7978 G.global_argv++;
7809 G.global_argc = argc - optind; 7979 debug_printf("running script '%s'\n", G.global_argv[0]);
7810 input = xfopen_for_read(argv[optind]); 7980 input = xfopen_for_read(G.global_argv[0]);
7811 close_on_exec_on(fileno(input)); 7981 close_on_exec_on(fileno(input));
7812 init_sigmasks(); 7982 install_special_sighandlers();
7813 parse_and_run_file(input); 7983 parse_and_run_file(input);
7814#if ENABLE_FEATURE_CLEAN_UP 7984#if ENABLE_FEATURE_CLEAN_UP
7815 fclose(input); 7985 fclose(input);
@@ -7818,7 +7988,7 @@ int hush_main(int argc, char **argv)
7818 } 7988 }
7819 7989
7820 /* Up to here, shell was non-interactive. Now it may become one. 7990 /* Up to here, shell was non-interactive. Now it may become one.
7821 * NB: don't forget to (re)run init_sigmasks() as needed. 7991 * NB: don't forget to (re)run install_special_sighandlers() as needed.
7822 */ 7992 */
7823 7993
7824 /* A shell is interactive if the '-i' flag was given, 7994 /* A shell is interactive if the '-i' flag was given,
@@ -7870,12 +8040,12 @@ int hush_main(int argc, char **argv)
7870 } 8040 }
7871 } 8041 }
7872 8042
7873 /* Block some signals */ 8043 /* Install more signal handlers */
7874 init_sigmasks(); 8044 install_special_sighandlers();
7875 8045
7876 if (G_saved_tty_pgrp) { 8046 if (G_saved_tty_pgrp) {
7877 /* Set other signals to restore saved_tty_pgrp */ 8047 /* Set other signals to restore saved_tty_pgrp */
7878 set_fatal_handlers(); 8048 install_fatal_sighandlers();
7879 /* Put ourselves in our own process group 8049 /* Put ourselves in our own process group
7880 * (bash, too, does this only if ctty is available) */ 8050 * (bash, too, does this only if ctty is available) */
7881 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ 8051 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
@@ -7886,7 +8056,7 @@ int hush_main(int argc, char **argv)
7886 * (we reset die_sleep = 0 whereever we [v]fork) */ 8056 * (we reset die_sleep = 0 whereever we [v]fork) */
7887 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */ 8057 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
7888 } else { 8058 } else {
7889 init_sigmasks(); 8059 install_special_sighandlers();
7890 } 8060 }
7891#elif ENABLE_HUSH_INTERACTIVE 8061#elif ENABLE_HUSH_INTERACTIVE
7892 /* No job control compiled in, only prompt/line editing */ 8062 /* No job control compiled in, only prompt/line editing */
@@ -7903,10 +8073,10 @@ int hush_main(int argc, char **argv)
7903 if (G_interactive_fd) { 8073 if (G_interactive_fd) {
7904 close_on_exec_on(G_interactive_fd); 8074 close_on_exec_on(G_interactive_fd);
7905 } 8075 }
7906 init_sigmasks(); 8076 install_special_sighandlers();
7907#else 8077#else
7908 /* We have interactiveness code disabled */ 8078 /* We have interactiveness code disabled */
7909 init_sigmasks(); 8079 install_special_sighandlers();
7910#endif 8080#endif
7911 /* bash: 8081 /* bash:
7912 * if interactive but not a login shell, sources ~/.bashrc 8082 * if interactive but not a login shell, sources ~/.bashrc
@@ -8040,7 +8210,7 @@ static int FAST_FUNC builtin_exec(char **argv)
8040 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp); 8210 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp);
8041 8211
8042 /* TODO: if exec fails, bash does NOT exit! We do. 8212 /* TODO: if exec fails, bash does NOT exit! We do.
8043 * We'll need to undo sigprocmask (it's inside execvp_or_die) 8213 * We'll need to undo trap cleanup (it's inside execvp_or_die)
8044 * and tcsetpgrp, and this is inherently racy. 8214 * and tcsetpgrp, and this is inherently racy.
8045 */ 8215 */
8046 execvp_or_die(argv); 8216 execvp_or_die(argv);
@@ -8237,6 +8407,8 @@ static int FAST_FUNC builtin_trap(char **argv)
8237 process_sig_list: 8407 process_sig_list:
8238 ret = EXIT_SUCCESS; 8408 ret = EXIT_SUCCESS;
8239 while (*argv) { 8409 while (*argv) {
8410 sighandler_t handler;
8411
8240 sig = get_signum(*argv++); 8412 sig = get_signum(*argv++);
8241 if (sig < 0 || sig >= NSIG) { 8413 if (sig < 0 || sig >= NSIG) {
8242 ret = EXIT_FAILURE; 8414 ret = EXIT_FAILURE;
@@ -8255,18 +8427,13 @@ static int FAST_FUNC builtin_trap(char **argv)
8255 if (sig == 0) 8427 if (sig == 0)
8256 continue; 8428 continue;
8257 8429
8258 if (new_cmd) { 8430 if (new_cmd)
8259 sigaddset(&G.blocked_set, sig); 8431 handler = (new_cmd[0] ? record_pending_signo : SIG_IGN);
8260 } else { 8432 else
8261 /* There was a trap handler, we are removing it 8433 /* We are removing trap handler */
8262 * (if sig has non-DFL handling, 8434 handler = pick_sighandler(sig);
8263 * we don't need to do anything) */ 8435 install_sighandler(sig, handler);
8264 if (sig < 32 && (G.non_DFL_mask & (1 << sig)))
8265 continue;
8266 sigdelset(&G.blocked_set, sig);
8267 }
8268 } 8436 }
8269 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
8270 return ret; 8437 return ret;
8271 } 8438 }
8272 8439
@@ -8467,6 +8634,27 @@ static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM)
8467 return EXIT_SUCCESS; 8634 return EXIT_SUCCESS;
8468} 8635}
8469 8636
8637/* Interruptibility of read builtin in bash
8638 * (tested on bash-4.2.8 by sending signals (not by ^C)):
8639 *
8640 * Empty trap makes read ignore corresponding signal, for any signal.
8641 *
8642 * SIGINT:
8643 * - terminates non-interactive shell;
8644 * - interrupts read in interactive shell;
8645 * if it has non-empty trap:
8646 * - executes trap and returns to command prompt in interactive shell;
8647 * - executes trap and returns to read in non-interactive shell;
8648 * SIGTERM:
8649 * - is ignored (does not interrupt) read in interactive shell;
8650 * - terminates non-interactive shell;
8651 * if it has non-empty trap:
8652 * - executes trap and returns to read;
8653 * SIGHUP:
8654 * - terminates shell (regardless of interactivity);
8655 * if it has non-empty trap:
8656 * - executes trap and returns to read;
8657 */
8470static int FAST_FUNC builtin_read(char **argv) 8658static int FAST_FUNC builtin_read(char **argv)
8471{ 8659{
8472 const char *r; 8660 const char *r;
@@ -8474,6 +8662,7 @@ static int FAST_FUNC builtin_read(char **argv)
8474 char *opt_p = NULL; 8662 char *opt_p = NULL;
8475 char *opt_t = NULL; 8663 char *opt_t = NULL;
8476 char *opt_u = NULL; 8664 char *opt_u = NULL;
8665 const char *ifs;
8477 int read_flags; 8666 int read_flags;
8478 8667
8479 /* "!": do not abort on errors. 8668 /* "!": do not abort on errors.
@@ -8483,10 +8672,12 @@ static int FAST_FUNC builtin_read(char **argv)
8483 if (read_flags == (uint32_t)-1) 8672 if (read_flags == (uint32_t)-1)
8484 return EXIT_FAILURE; 8673 return EXIT_FAILURE;
8485 argv += optind; 8674 argv += optind;
8675 ifs = get_local_var_value("IFS"); /* can be NULL */
8486 8676
8677 again:
8487 r = shell_builtin_read(set_local_var_from_halves, 8678 r = shell_builtin_read(set_local_var_from_halves,
8488 argv, 8679 argv,
8489 get_local_var_value("IFS"), /* can be NULL */ 8680 ifs,
8490 read_flags, 8681 read_flags,
8491 opt_n, 8682 opt_n,
8492 opt_p, 8683 opt_p,
@@ -8494,6 +8685,12 @@ static int FAST_FUNC builtin_read(char **argv)
8494 opt_u 8685 opt_u
8495 ); 8686 );
8496 8687
8688 if ((uintptr_t)r == 1 && errno == EINTR) {
8689 unsigned sig = check_and_run_traps();
8690 if (sig && sig != SIGINT)
8691 goto again;
8692 }
8693
8497 if ((uintptr_t)r > 1) { 8694 if ((uintptr_t)r > 1) {
8498 bb_error_msg("%s", r); 8695 bb_error_msg("%s", r);
8499 r = (char*)(uintptr_t)1; 8696 r = (char*)(uintptr_t)1;
@@ -8726,7 +8923,7 @@ static int FAST_FUNC builtin_unset(char **argv)
8726static int FAST_FUNC builtin_wait(char **argv) 8923static int FAST_FUNC builtin_wait(char **argv)
8727{ 8924{
8728 int ret = EXIT_SUCCESS; 8925 int ret = EXIT_SUCCESS;
8729 int status, sig; 8926 int status;
8730 8927
8731 argv = skip_dash_dash(argv); 8928 argv = skip_dash_dash(argv);
8732 if (argv[0] == NULL) { 8929 if (argv[0] == NULL) {
@@ -8746,25 +8943,53 @@ static int FAST_FUNC builtin_wait(char **argv)
8746 * ^C <-- after ~4 sec from keyboard 8943 * ^C <-- after ~4 sec from keyboard
8747 * $ 8944 * $
8748 */ 8945 */
8749 sigaddset(&G.blocked_set, SIGCHLD);
8750 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
8751 while (1) { 8946 while (1) {
8752 checkjobs(NULL); 8947 int sig;
8753 if (errno == ECHILD) 8948 sigset_t oldset, allsigs;
8949
8950 /* waitpid is not interruptible by SA_RESTARTed
8951 * signals which we use. Thus, this ugly dance:
8952 */
8953
8954 /* Make sure possible SIGCHLD is stored in kernel's
8955 * pending signal mask before we call waitpid.
8956 * Or else we may race with SIGCHLD, lose it,
8957 * and get stuck in sigwaitinfo...
8958 */
8959 sigfillset(&allsigs);
8960 sigprocmask(SIG_SETMASK, &allsigs, &oldset);
8961
8962 if (!sigisemptyset(&G.pending_set)) {
8963 /* Crap! we raced with some signal! */
8964 // sig = 0;
8965 goto restore;
8966 }
8967
8968 checkjobs(NULL); /* waitpid(WNOHANG) inside */
8969 if (errno == ECHILD) {
8970 sigprocmask(SIG_SETMASK, &oldset, NULL);
8971 break;
8972 }
8973
8974 /* Wait for SIGCHLD or any other signal */
8975 //sig = sigwaitinfo(&allsigs, NULL);
8976 /* It is vitally important for sigsuspend that SIGCHLD has non-DFL handler! */
8977 /* Note: sigsuspend invokes signal handler */
8978 sigsuspend(&oldset);
8979 restore:
8980 sigprocmask(SIG_SETMASK, &oldset, NULL);
8981
8982 /* So, did we get a signal? */
8983 //if (sig > 0)
8984 // raise(sig); /* run handler */
8985 sig = check_and_run_traps();
8986 if (sig /*&& sig != SIGCHLD - always true */) {
8987 /* see note 2 */
8988 ret = 128 + sig;
8754 break; 8989 break;
8755 /* Wait for SIGCHLD or any other signal of interest */
8756 /* sigtimedwait with infinite timeout: */
8757 sig = sigwaitinfo(&G.blocked_set, NULL);
8758 if (sig > 0) {
8759 sig = check_and_run_traps(sig);
8760 if (sig && sig != SIGCHLD) { /* see note 2 */
8761 ret = 128 + sig;
8762 break;
8763 }
8764 } 8990 }
8991 /* SIGCHLD, or no signal, or ignored one, such as SIGQUIT. Repeat */
8765 } 8992 }
8766 sigdelset(&G.blocked_set, SIGCHLD);
8767 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
8768 return ret; 8993 return ret;
8769 } 8994 }
8770 8995
diff --git a/shell/hush_test/hush-misc/assignment4.right b/shell/hush_test/hush-misc/assignment4.right
new file mode 100644
index 000000000..31c896f62
--- /dev/null
+++ b/shell/hush_test/hush-misc/assignment4.right
@@ -0,0 +1 @@
Done:0
diff --git a/shell/hush_test/hush-misc/assignment4.tests b/shell/hush_test/hush-misc/assignment4.tests
new file mode 100755
index 000000000..6f46d0a33
--- /dev/null
+++ b/shell/hush_test/hush-misc/assignment4.tests
@@ -0,0 +1,3 @@
1# There was a bug where we misinterpreted assignments after 'do':
2for i in 1; do eval b=; done
3echo Done:$?
diff --git a/shell/hush_test/hush-misc/while3.right b/shell/hush_test/hush-misc/while3.right
new file mode 100644
index 000000000..7c4d7beb0
--- /dev/null
+++ b/shell/hush_test/hush-misc/while3.right
@@ -0,0 +1 @@
OK:0
diff --git a/shell/hush_test/hush-misc/while3.tests b/shell/hush_test/hush-misc/while3.tests
new file mode 100755
index 000000000..9132b5f4d
--- /dev/null
+++ b/shell/hush_test/hush-misc/while3.tests
@@ -0,0 +1,4 @@
1while false; do
2 # bash will require at least ":" here...
3done
4echo OK:$?
diff --git a/shell/hush_test/hush-trap/signal_read1.right b/shell/hush_test/hush-trap/signal_read1.right
new file mode 100644
index 000000000..2870a8e70
--- /dev/null
+++ b/shell/hush_test/hush-trap/signal_read1.right
@@ -0,0 +1 @@
Got HUP:0
diff --git a/shell/hush_test/hush-trap/signal_read1.tests b/shell/hush_test/hush-trap/signal_read1.tests
new file mode 100755
index 000000000..1105479a3
--- /dev/null
+++ b/shell/hush_test/hush-trap/signal_read1.tests
@@ -0,0 +1,5 @@
1(sleep 1; kill -HUP $$) &
2trap 'echo "Got HUP:$?"; exit' HUP
3while true; do
4 read ignored
5done
diff --git a/shell/hush_test/hush-trap/signal_read2.right b/shell/hush_test/hush-trap/signal_read2.right
new file mode 100644
index 000000000..71a6bc16d
--- /dev/null
+++ b/shell/hush_test/hush-trap/signal_read2.right
@@ -0,0 +1,2 @@
1HUP
2Done:129
diff --git a/shell/hush_test/hush-trap/signal_read2.tests b/shell/hush_test/hush-trap/signal_read2.tests
new file mode 100755
index 000000000..eab5b9b5b
--- /dev/null
+++ b/shell/hush_test/hush-trap/signal_read2.tests
@@ -0,0 +1,7 @@
1$THIS_SH -c '
2(sleep 1; kill -HUP $$) &
3while true; do
4 read ignored
5done
6'
7echo "Done:$?"
diff --git a/shell/hush_test/run-all b/shell/hush_test/run-all
index 256f152dc..64a7abc47 100755
--- a/shell/hush_test/run-all
+++ b/shell/hush_test/run-all
@@ -48,8 +48,9 @@ do_test()
48 *.orig|*~) ;; 48 *.orig|*~) ;;
49 #*) echo $x ; sh $x ;; 49 #*) echo $x ; sh $x ;;
50 *) 50 *)
51 echo -n "$1/$x:"
51 sh "$x" >"../$1-$x.fail" 2>&1 && \ 52 sh "$x" >"../$1-$x.fail" 2>&1 && \
52 { echo "$1/$x: ok"; rm "../$1-$x.fail"; } || echo "$1/$x: fail"; 53 { { echo " ok"; rm "../$1-$x.fail"; } || echo " fail"; }
53 ;; 54 ;;
54 esac 55 esac
55 done 56 done
@@ -60,6 +61,7 @@ do_test()
60 name="${x%%.tests}" 61 name="${x%%.tests}"
61 test -f "$name.right" || continue 62 test -f "$name.right" || continue
62# echo Running test: "$x" 63# echo Running test: "$x"
64 echo -n "$1/$x:"
63 ( 65 (
64 "$THIS_SH" "./$x" >"$name.xx" 2>&1 66 "$THIS_SH" "./$x" >"$name.xx" 2>&1
65 # filter C library differences 67 # filter C library differences
@@ -70,9 +72,9 @@ do_test()
70 diff -u "$name.xx" "$name.right" >"../$1-$x.fail" && rm -f "$name.xx" "../$1-$x.fail" 72 diff -u "$name.xx" "$name.right" >"../$1-$x.fail" && rm -f "$name.xx" "../$1-$x.fail"
71 ) 73 )
72 case $? in 74 case $? in
73 0) echo "$1/$x: ok";; 75 0) echo " ok";;
74 77) echo "$1/$x: skip (feature disabled)";; 76 77) echo " skip (feature disabled)";;
75 *) echo "$1/$x: fail"; tret=1;; 77 *) echo " fail"; tret=1;;
76 esac 78 esac
77 done 79 done
78 exit ${tret} 80 exit ${tret}
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 75f4b3e54..4329ca05c 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -36,6 +36,10 @@ int FAST_FUNC is_well_formed_var_name(const char *s, char terminator)
36 36
37/* read builtin */ 37/* read builtin */
38 38
39/* Needs to be interruptible: shell mush handle traps and shell-special signals
40 * while inside read. To implement this, be sure to not loop on EINTR
41 * and return errno == EINTR reliably.
42 */
39//TODO: use more efficient setvar() which takes a pointer to malloced "VAR=VAL" 43//TODO: use more efficient setvar() which takes a pointer to malloced "VAR=VAL"
40//string. hush naturally has it, and ash has setvareq(). 44//string. hush naturally has it, and ash has setvareq().
41//Here we can simply store "VAR=" at buffer start and store read data directly 45//Here we can simply store "VAR=" at buffer start and store read data directly
@@ -51,6 +55,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
51 const char *opt_u 55 const char *opt_u
52) 56)
53{ 57{
58 unsigned err;
54 unsigned end_ms; /* -t TIMEOUT */ 59 unsigned end_ms; /* -t TIMEOUT */
55 int fd; /* -u FD */ 60 int fd; /* -u FD */
56 int nchars; /* -n NUM */ 61 int nchars; /* -n NUM */
@@ -62,6 +67,8 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
62 int startword; 67 int startword;
63 smallint backslash; 68 smallint backslash;
64 69
70 errno = err = 0;
71
65 pp = argv; 72 pp = argv;
66 while (*pp) { 73 while (*pp) {
67 if (!is_well_formed_var_name(*pp, '\0')) { 74 if (!is_well_formed_var_name(*pp, '\0')) {
@@ -152,28 +159,40 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
152 bufpos = 0; 159 bufpos = 0;
153 do { 160 do {
154 char c; 161 char c;
162 struct pollfd pfd[1];
163 int timeout;
155 164
156 if (end_ms) { 165 if ((bufpos & 0xff) == 0)
157 int timeout; 166 buffer = xrealloc(buffer, bufpos + 0x100);
158 struct pollfd pfd[1];
159 167
160 pfd[0].fd = fd; 168 timeout = -1;
161 pfd[0].events = POLLIN; 169 if (end_ms) {
162 timeout = end_ms - (unsigned)monotonic_ms(); 170 timeout = end_ms - (unsigned)monotonic_ms();
163 if (timeout <= 0 /* already late? */ 171 if (timeout <= 0) { /* already late? */
164 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
165 ) { /* timed out! */
166 retval = (const char *)(uintptr_t)1; 172 retval = (const char *)(uintptr_t)1;
167 goto ret; 173 goto ret;
168 } 174 }
169 } 175 }
170 176
171 if ((bufpos & 0xff) == 0) 177 /* We must poll even if timeout is -1:
172 buffer = xrealloc(buffer, bufpos + 0x100); 178 * we want to be interrupted if signal arrives,
173 if (nonblock_safe_read(fd, &buffer[bufpos], 1) != 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) {
191 err = errno;
174 retval = (const char *)(uintptr_t)1; 192 retval = (const char *)(uintptr_t)1;
175 break; 193 break;
176 } 194 }
195
177 c = buffer[bufpos]; 196 c = buffer[bufpos];
178 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) 197 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r'))
179 continue; 198 continue;
@@ -240,6 +259,8 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
240 free(buffer); 259 free(buffer);
241 if (read_flags & BUILTIN_READ_SILENT) 260 if (read_flags & BUILTIN_READ_SILENT)
242 tcsetattr(fd, TCSANOW, &old_tty); 261 tcsetattr(fd, TCSANOW, &old_tty);
262
263 errno = err;
243 return retval; 264 return retval;
244} 265}
245 266