Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/shell/hush.c
- Timestamp:
- Jan 1, 2014, 12:47:38 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3.2/mindi-busybox/shell/hush.c
r2859 r3232 82 82 * aaa 83 83 */ 84 #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 85 #include <malloc.h> /* for malloc_trim */ 84 #if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ 85 || defined(__APPLE__) \ 86 ) 87 # include <malloc.h> /* for malloc_trim */ 88 #endif 86 89 #include <glob.h> 87 90 /* #include <dmalloc.h> */ … … 90 93 #endif 91 94 95 #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 96 #include "unicode.h" 92 97 #include "shell_common.h" 93 98 #include "math.h" … … 101 106 # define PIPE_BUF 4096 /* amount of buffering in a pipe */ 102 107 #endif 103 104 //applet:IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_DROP))105 //applet:IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_DROP))106 //applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh))107 //applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash))108 109 //kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o110 //kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o111 108 112 109 //config:config HUSH … … 246 243 //config: 247 244 248 //usage:#define hush_trivial_usage NOUSAGE_STR 249 //usage:#define hush_full_usage "" 250 //usage:#define msh_trivial_usage NOUSAGE_STR 251 //usage:#define msh_full_usage "" 252 //usage:#define sh_trivial_usage NOUSAGE_STR 253 //usage:#define sh_full_usage "" 254 //usage:#define bash_trivial_usage NOUSAGE_STR 255 //usage:#define bash_full_usage "" 245 //applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP)) 246 //applet:IF_MSH(APPLET(msh, BB_DIR_BIN, BB_SUID_DROP)) 247 //applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, sh)) 248 //applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, bash)) 249 250 //kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o 251 //kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o 252 253 /* -i (interactive) and -s (read stdin) are also accepted, 254 * but currently do nothing, therefore aren't shown in help. 255 * NOMMU-specific options are not meant to be used by users, 256 * therefore we don't show them either. 257 */ 258 //usage:#define hush_trivial_usage 259 //usage: "[-nxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" 260 //usage:#define hush_full_usage "\n\n" 261 //usage: "Unix shell interpreter" 262 263 //usage:#define msh_trivial_usage hush_trivial_usage 264 //usage:#define msh_full_usage hush_full_usage 265 266 //usage:#if ENABLE_FEATURE_SH_IS_HUSH 267 //usage:# define sh_trivial_usage hush_trivial_usage 268 //usage:# define sh_full_usage hush_full_usage 269 //usage:#endif 270 //usage:#if ENABLE_FEATURE_BASH_IS_HUSH 271 //usage:# define bash_trivial_usage hush_trivial_usage 272 //usage:# define bash_full_usage hush_full_usage 273 //usage:#endif 256 274 257 275 … … 303 321 # undef ENABLE_FEATURE_EDITING_FANCY_PROMPT 304 322 # define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0 323 # undef ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 324 # define ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 0 305 325 #endif 306 326 … … 437 457 #endif 438 458 439 /* I can almost use ordinary FILE*. Is open_memstream() universally440 * available? Where is it documented? */441 459 typedef struct in_str { 442 460 const char *p; … … 445 463 char peek_buf[2]; 446 464 #if ENABLE_HUSH_INTERACTIVE 447 smallint promptme;448 465 smallint promptmode; /* 0: PS1, 1: PS2 */ 449 466 #endif 467 int last_char; 450 468 FILE *file; 451 469 int (*get) (struct in_str *) FAST_FUNC; … … 505 523 pid_t pid; /* 0 if exited */ 506 524 int assignment_cnt; /* how many argv[i] are assignments? */ 507 smallint is_stopped; /* is the command currently running? */508 525 smallint cmd_type; /* CMD_xxx */ 509 526 #define CMD_NORMAL 0 … … 677 694 * xtrace off 678 695 */ 679 static const char o_opt_strings[] ALIGN1 = "pipefail\0"; 696 static const char o_opt_strings[] ALIGN1 = 697 "pipefail\0" 698 "noexec\0" 699 #if ENABLE_HUSH_MODE_X 700 "xtrace\0" 701 #endif 702 ; 680 703 enum { 681 704 OPT_O_PIPEFAIL, 705 OPT_O_NOEXEC, 706 #if ENABLE_HUSH_MODE_X 707 OPT_O_XTRACE, 708 #endif 682 709 NUM_OPT_O 683 710 }; … … 727 754 #endif 728 755 char o_opt[NUM_OPT_O]; 756 #if ENABLE_HUSH_MODE_X 757 # define G_x_mode (G.o_opt[OPT_O_XTRACE]) 758 #else 759 # define G_x_mode 0 760 #endif 729 761 smallint flag_SIGINT; 730 762 #if ENABLE_HUSH_LOOPS … … 738 770 smallint flag_return_in_progress; 739 771 #endif 740 smallint n_mode;741 #if ENABLE_HUSH_MODE_X742 smallint x_mode;743 # define G_x_mode (G.x_mode)744 #else745 # define G_x_mode 0746 #endif747 772 smallint exiting; /* used to prevent EXIT trap recursion */ 748 773 /* These four support $?, $#, and $1 */ … … 750 775 /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */ 751 776 smalluint global_args_malloced; 752 smalluint inherited_set_is_saved;753 777 /* how many non-NULL argv's we have. NB: $# + 1 */ 754 778 int global_argc; … … 778 802 smallint we_have_children; 779 803 #endif 780 /* which signals have non-DFL handler (even with no traps set)? */ 781 unsigned non_DFL_mask; 804 /* Which signals have non-DFL handler (even with no traps set)? 805 * Set at the start to: 806 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS) 807 * SPECIAL_INTERACTIVE_SIGS are cleared after fork. 808 * The rest is cleared right before execv syscalls. 809 * Other than these two times, never modified. 810 */ 811 unsigned special_sig_mask; 812 #if ENABLE_HUSH_JOB 813 unsigned fatal_sig_mask; 814 # define G_fatal_sig_mask G.fatal_sig_mask 815 #else 816 # define G_fatal_sig_mask 0 817 #endif 782 818 char **traps; /* char *traps[NSIG] */ 783 sigset_t blocked_set; 784 sigset_t inherited_set; 819 sigset_t pending_set; 785 820 #if HUSH_DEBUG 786 821 unsigned long memleak_value; 787 822 int debug_indent; 788 823 #endif 824 struct sigaction sa; 789 825 char user_input_buf[ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 2]; 790 826 }; … … 795 831 #define INIT_G() do { \ 796 832 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 833 /* memset(&G.sa, 0, sizeof(G.sa)); */ \ 834 sigfillset(&G.sa.sa_mask); \ 835 G.sa.sa_flags = SA_RESTART; \ 797 836 } while (0) 798 837 … … 1062 1101 } 1063 1102 1064 static void syntax_error(unsigned lineno , const char *msg)1103 static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) 1065 1104 { 1066 1105 if (msg) 1067 die_if_script(lineno,"syntax error: %s", msg);1106 bb_error_msg("syntax error: %s", msg); 1068 1107 else 1069 die_if_script(lineno, "syntax error", NULL); 1070 } 1071 1072 static void syntax_error_at(unsigned lineno, const char *msg) 1073 { 1074 die_if_script(lineno, "syntax error at '%s'", msg); 1075 } 1076 1077 static void syntax_error_unterm_str(unsigned lineno, const char *s) 1078 { 1079 die_if_script(lineno, "syntax error: unterminated %s", s); 1080 } 1081 1082 /* It so happens that all such cases are totally fatal 1083 * even if shell is interactive: EOF while looking for closing 1084 * delimiter. There is nowhere to read stuff from after that, 1085 * it's EOF! The only choice is to terminate. 1086 */ 1087 static void syntax_error_unterm_ch(unsigned lineno, char ch) NORETURN; 1108 bb_error_msg("syntax error"); 1109 } 1110 1111 static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg) 1112 { 1113 bb_error_msg("syntax error at '%s'", msg); 1114 } 1115 1116 static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) 1117 { 1118 bb_error_msg("syntax error: unterminated %s", s); 1119 } 1120 1088 1121 static void syntax_error_unterm_ch(unsigned lineno, char ch) 1089 1122 { 1090 1123 char msg[2] = { ch, '\0' }; 1091 1124 syntax_error_unterm_str(lineno, msg); 1092 xfunc_die(); 1093 } 1094 1095 static void syntax_error_unexpected_ch(unsigned lineno, int ch) 1125 } 1126 1127 static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch) 1096 1128 { 1097 1129 char msg[2]; 1098 1130 msg[0] = ch; 1099 1131 msg[1] = '\0'; 1100 die_if_script(lineno,"syntax error: unexpected %s", ch == EOF ? "EOF" : msg);1132 bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); 1101 1133 } 1102 1134 … … 1312 1344 * Example 3: this does not wait 5 sec, but executes ls: 1313 1345 * "sleep 5; ls -l" + press ^C 1346 * Example 4: this does not wait and does not execute ls: 1347 * "sleep 5 & wait; ls -l" + press ^C 1314 1348 * 1315 1349 * (What happens to signals which are IGN on shell start?) 1316 1350 * (What happens with signal mask on shell start?) 1317 1351 * 1318 * Implementation in hush1319 * ================== ====1352 * Old implementation 1353 * ================== 1320 1354 * We use in-kernel pending signal mask to determine which signals were sent. 1321 1355 * We block all signals which we don't want to take action immediately, … … 1325 1359 * and act on them. 1326 1360 * 1327 * unsigned non_DFL_mask: a mask of such "special" signals1361 * unsigned special_sig_mask: a mask of such "special" signals 1328 1362 * sigset_t blocked_set: current blocked signal set 1329 1363 * 1330 1364 * "trap - SIGxxx": 1331 * clear bit in blocked_set unless it is also in non_DFL_mask1365 * clear bit in blocked_set unless it is also in special_sig_mask 1332 1366 * "trap 'cmd' SIGxxx": 1333 1367 * set bit in blocked_set (even if 'cmd' is '') … … 1348 1382 * are set to the default actions". bash interprets it so that traps which 1349 1383 * are set to '' (ignore) are NOT reset to defaults. We do the same. 1384 * 1385 * Problem: the above approach makes it unwieldy to catch signals while 1386 * we are in read builtin, of while we read commands from stdin: 1387 * masked signals are not visible! 1388 * 1389 * New implementation 1390 * ================== 1391 * We record each signal we are interested in by installing signal handler 1392 * for them - a bit like emulating kernel pending signal mask in userspace. 1393 * We are interested in: signals which need to have special handling 1394 * as described above, and all signals which have traps set. 1395 * Signals are rocorded in pending_set. 1396 * After each pipe execution, we extract any pending signals 1397 * and act on them. 1398 * 1399 * unsigned special_sig_mask: a mask of shell-special signals. 1400 * unsigned fatal_sig_mask: a mask of signals on which we restore tty pgrp. 1401 * char *traps[sig] if trap for sig is set (even if it's ''). 1402 * sigset_t pending_set: set of sigs we received. 1403 * 1404 * "trap - SIGxxx": 1405 * if sig is in special_sig_mask, set handler back to: 1406 * record_pending_signo, or to IGN if it's a tty stop signal 1407 * if sig is in fatal_sig_mask, set handler back to sigexit. 1408 * else: set handler back to SIG_DFL 1409 * "trap 'cmd' SIGxxx": 1410 * set handler to record_pending_signo. 1411 * "trap '' SIGxxx": 1412 * set handler to SIG_IGN. 1413 * after [v]fork, if we plan to be a shell: 1414 * set signals with special interactive handling to SIG_DFL 1415 * (because child shell is not interactive), 1416 * unset all traps except '' (note: regardless of child shell's type - {}, (), etc) 1417 * after [v]fork, if we plan to exec: 1418 * POSIX says fork clears pending signal mask in child - no need to clear it. 1419 * 1420 * To make wait builtin interruptible, we handle SIGCHLD as special signal, 1421 * otherwise (if we leave it SIG_DFL) sigsuspend in wait builtin will not wake up on it. 1422 * 1423 * Note (compat): 1424 * Standard says "When a subshell is entered, traps that are not being ignored 1425 * are set to the default actions". bash interprets it so that traps which 1426 * are set to '' (ignore) are NOT reset to defaults. We do the same. 1350 1427 */ 1351 1428 enum { … … 1355 1432 | (1 << SIGHUP) 1356 1433 , 1357 SPECIAL_JOB _SIGS = 01434 SPECIAL_JOBSTOP_SIGS = 0 1358 1435 #if ENABLE_HUSH_JOB 1359 1436 | (1 << SIGTTIN) … … 1361 1438 | (1 << SIGTSTP) 1362 1439 #endif 1440 , 1363 1441 }; 1364 1442 1443 static void record_pending_signo(int sig) 1444 { 1445 sigaddset(&G.pending_set, sig); 1365 1446 #if ENABLE_HUSH_FAST 1366 static void SIGCHLD_handler(int sig UNUSED_PARAM) 1367 { 1368 G.count_SIGCHLD++; 1447 if (sig == SIGCHLD) { 1448 G.count_SIGCHLD++; 1369 1449 //bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 1370 } 1371 #endif 1450 } 1451 #endif 1452 } 1453 1454 static sighandler_t install_sighandler(int sig, sighandler_t handler) 1455 { 1456 struct sigaction old_sa; 1457 1458 /* We could use signal() to install handlers... almost: 1459 * except that we need to mask ALL signals while handlers run. 1460 * I saw signal nesting in strace, race window isn't small. 1461 * SA_RESTART is also needed, but in Linux, signal() 1462 * sets SA_RESTART too. 1463 */ 1464 /* memset(&G.sa, 0, sizeof(G.sa)); - already done */ 1465 /* sigfillset(&G.sa.sa_mask); - already done */ 1466 /* G.sa.sa_flags = SA_RESTART; - already done */ 1467 G.sa.sa_handler = handler; 1468 sigaction(sig, &G.sa, &old_sa); 1469 return old_sa.sa_handler; 1470 } 1372 1471 1373 1472 #if ENABLE_HUSH_JOB … … 1386 1485 static void sigexit(int sig) 1387 1486 { 1388 /* Disable all signals: job control, SIGPIPE, etc. */1389 sigprocmask_allsigs(SIG_BLOCK);1390 1391 1487 /* Careful: we can end up here after [v]fork. Do not restore 1392 1488 * tty pgrp then, only top-level shell process does that */ 1393 if (G_saved_tty_pgrp && getpid() == G.root_pid) 1489 if (G_saved_tty_pgrp && getpid() == G.root_pid) { 1490 /* Disable all signals: job control, SIGPIPE, etc. 1491 * Mostly paranoid measure, to prevent infinite SIGTTOU. 1492 */ 1493 sigprocmask_allsigs(SIG_BLOCK); 1394 1494 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp); 1495 } 1395 1496 1396 1497 /* Not a signal, just exit */ … … 1407 1508 #endif 1408 1509 1510 static sighandler_t pick_sighandler(unsigned sig) 1511 { 1512 sighandler_t handler = SIG_DFL; 1513 if (sig < sizeof(unsigned)*8) { 1514 unsigned sigmask = (1 << sig); 1515 1516 #if ENABLE_HUSH_JOB 1517 /* is sig fatal? */ 1518 if (G_fatal_sig_mask & sigmask) 1519 handler = sigexit; 1520 else 1521 #endif 1522 /* sig has special handling? */ 1523 if (G.special_sig_mask & sigmask) { 1524 handler = record_pending_signo; 1525 /* TTIN/TTOU/TSTP can't be set to record_pending_signo 1526 * in order to ignore them: they will be raised 1527 * in an endless loop when we try to do some 1528 * terminal ioctls! We do have to _ignore_ these. 1529 */ 1530 if (SPECIAL_JOBSTOP_SIGS & sigmask) 1531 handler = SIG_IGN; 1532 } 1533 } 1534 return handler; 1535 } 1536 1409 1537 /* Restores tty foreground process group, and exits. */ 1410 1538 static void hush_exit(int exitcode) NORETURN; 1411 1539 static void hush_exit(int exitcode) 1412 1540 { 1541 #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 1542 save_history(G.line_input_state); 1543 #endif 1544 1545 fflush_all(); 1413 1546 if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { 1414 /* Prevent recursion:1415 * trap "echo Hi; exit" EXIT; exit1416 */1417 1547 char *argv[3]; 1418 1548 /* argv[0] is unused */ … … 1451 1581 1452 1582 1453 static int check_and_run_traps(int sig) 1454 { 1455 /* I want it in rodata, not in bss. 1456 * gcc 4.2.1 puts it in rodata only if it has { 0, 0 } 1457 * initializer. But other compilers may still use bss. 1458 * TODO: find more portable solution. 1459 */ 1460 static const struct timespec zero_timespec = { 0, 0 }; 1461 smalluint save_rcode; 1583 //TODO: return a mask of ALL handled sigs? 1584 static int check_and_run_traps(void) 1585 { 1462 1586 int last_sig = 0; 1463 1587 1464 if (sig)1465 goto jump_in;1466 1588 while (1) { 1467 sig = sigtimedwait(&G.blocked_set, NULL, &zero_timespec); 1468 if (sig <= 0) 1589 int sig; 1590 1591 if (sigisemptyset(&G.pending_set)) 1469 1592 break; 1470 jump_in: 1471 last_sig = sig; 1593 sig = 0; 1594 do { 1595 sig++; 1596 if (sigismember(&G.pending_set, sig)) { 1597 sigdelset(&G.pending_set, sig); 1598 goto got_sig; 1599 } 1600 } while (sig < NSIG); 1601 break; 1602 got_sig: 1472 1603 if (G.traps && G.traps[sig]) { 1473 1604 if (G.traps[sig][0]) { 1474 1605 /* We have user-defined handler */ 1606 smalluint save_rcode; 1475 1607 char *argv[3]; 1476 1608 /* argv[0] is unused */ … … 1480 1612 builtin_eval(argv); 1481 1613 G.last_exitcode = save_rcode; 1614 last_sig = sig; 1482 1615 } /* else: "" trap, ignoring signal */ 1483 1616 continue; … … 1485 1618 /* not a trap: special action */ 1486 1619 switch (sig) { 1487 #if ENABLE_HUSH_FAST1488 case SIGCHLD:1489 G.count_SIGCHLD++;1490 //bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);1491 break;1492 #endif1493 1620 case SIGINT: 1494 1621 /* Builtin was ^C'ed, make it look prettier: */ 1495 1622 bb_putchar('\n'); 1496 1623 G.flag_SIGINT = 1; 1624 last_sig = sig; 1497 1625 break; 1498 1626 #if ENABLE_HUSH_JOB … … 1511 1639 } 1512 1640 #endif 1641 #if ENABLE_HUSH_FAST 1642 case SIGCHLD: 1643 G.count_SIGCHLD++; 1644 //bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); 1645 /* Note: 1646 * We dont do 'last_sig = sig' here -> NOT returning this sig. 1647 * This simplifies wait builtin a bit. 1648 */ 1649 break; 1650 #endif 1513 1651 default: /* ignored: */ 1514 1652 /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */ 1653 /* Note: 1654 * We dont do 'last_sig = sig' here -> NOT returning this sig. 1655 * Example: wait is not interrupted by TERM 1656 * in interactive shell, because TERM is ignored. 1657 */ 1515 1658 break; 1516 1659 } … … 1834 1977 if (ch != '\0') { 1835 1978 i->p++; 1979 i->last_char = ch; 1836 1980 return ch; 1837 1981 } … … 1891 2035 * is actually being read */ 1892 2036 do { 2037 /* Unicode support should be activated even if LANG is set 2038 * _during_ shell execution, not only if it was set when 2039 * shell was started. Therefore, re-check LANG every time: 2040 */ 2041 reinit_unicode(get_local_var_value("LANG")); 2042 1893 2043 G.flag_SIGINT = 0; 1894 2044 /* buglet: SIGINT will not make new prompt to appear _at once_, 1895 2045 * only after <Enter>. (^C will work) */ 1896 r = read_line_input( prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, G.line_input_state);2046 r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1); 1897 2047 /* catch *SIGINT* etc (^C is handled by read_line_input) */ 1898 check_and_run_traps( 0);2048 check_and_run_traps(); 1899 2049 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ 1900 2050 i->eof_flag = (r < 0); … … 1906 2056 do { 1907 2057 G.flag_SIGINT = 0; 1908 fputs(prompt_str, stdout); 2058 if (i->last_char == '\0' || i->last_char == '\n') { 2059 /* Why check_and_run_traps here? Try this interactively: 2060 * $ trap 'echo INT' INT; (sleep 2; kill -INT $$) & 2061 * $ <[enter], repeatedly...> 2062 * Without check_and_run_traps, handler never runs. 2063 */ 2064 check_and_run_traps(); 2065 fputs(prompt_str, stdout); 2066 } 1909 2067 fflush_all(); 1910 2068 G.user_input_buf[0] = r = fgetc(i->file); 1911 2069 /*G.user_input_buf[1] = '\0'; - already is and never changed */ 1912 //do we need check_and_run_traps(0)? (maybe only if stdin)1913 2070 } while (G.flag_SIGINT); 1914 2071 i->eof_flag = (r == EOF); … … 1938 2095 * more complicated by now, like sourcing or substituting. */ 1939 2096 #if ENABLE_HUSH_INTERACTIVE 1940 if (G_interactive_fd && i-> promptme && i->file == stdin) {2097 if (G_interactive_fd && i->file == stdin) { 1941 2098 do { 1942 2099 get_user_input(i); 1943 2100 } while (!*i->p); /* need non-empty line */ 1944 2101 i->promptmode = 1; /* PS2 */ 1945 i->promptme = 0;1946 2102 goto take_cached; 1947 2103 } … … 1950 2106 } 1951 2107 debug_printf("file_get: got '%c' %d\n", ch, ch); 1952 #if ENABLE_HUSH_INTERACTIVE 1953 if (ch == '\n') 1954 i->promptme = 1; 1955 #endif 2108 i->last_char = ch; 1956 2109 return ch; 1957 2110 } … … 1980 2133 static void setup_file_in_str(struct in_str *i, FILE *f) 1981 2134 { 2135 memset(i, 0, sizeof(*i)); 1982 2136 i->peek = file_peek; 1983 2137 i->get = file_get; 1984 #if ENABLE_HUSH_INTERACTIVE 1985 i->promptme = 1; 1986 i->promptmode = 0; /* PS1 */ 1987 #endif 2138 /* i->promptmode = 0; - PS1 (memset did it) */ 1988 2139 i->file = f; 1989 i->p = NULL;2140 /* i->p = NULL; */ 1990 2141 } 1991 2142 1992 2143 static void setup_string_in_str(struct in_str *i, const char *s) 1993 2144 { 2145 memset(i, 0, sizeof(*i)); 1994 2146 i->peek = static_peek; 1995 2147 i->get = static_get; 1996 #if ENABLE_HUSH_INTERACTIVE 1997 i->promptme = 1; 1998 i->promptmode = 0; /* PS1 */ 1999 #endif 2148 /* i->promptmode = 0; - PS1 (memset did it) */ 2000 2149 i->p = s; 2001 i->eof_flag = 0;2150 /* i->eof_flag = 0; */ 2002 2151 } 2003 2152 … … 2134 2283 o_addblock(o, str, ordinary_cnt); 2135 2284 if (ordinary_cnt == len) 2136 return; 2285 return; /* NUL is already added by o_addblock */ 2137 2286 str += ordinary_cnt; 2138 2287 len -= ordinary_cnt + 1; /* we are processing + 1 char below */ … … 2148 2297 o->data[o->length] = ch; 2149 2298 o->length++; 2150 o->data[o->length] = '\0';2151 }2299 } 2300 o->data[o->length] = '\0'; 2152 2301 } 2153 2302 … … 2238 2387 o->has_empty_slot = 0; 2239 2388 } 2389 o->has_quoted_part = 0; 2240 2390 list[n] = (char*)(uintptr_t)string_len; 2241 2391 return n + 1; … … 3117 3267 p += 3; 3118 3268 } 3119 if (p == word->data || p[0] != '\0') {3120 /* saw no "$@", or not only "$@" but some3121 * real text is there too */3122 /* insert "empty variable" reference, this makes3123 * e.g. "", $empty"" etc to not disappear */3124 o_addchr(word, SPECIAL_VAR_SYMBOL);3125 o_addchr(word, SPECIAL_VAR_SYMBOL);3126 }3127 3269 } 3128 3270 command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); … … 3322 3464 3323 3465 goto jump_in; 3466 3324 3467 while (1) { 3325 3468 ch = i_getch(input); … … 3533 3676 #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS 3534 3677 /* Subroutines for copying $(...) and `...` things */ 3535 static voidadd_till_backquote(o_string *dest, struct in_str *input, int in_dquote);3678 static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); 3536 3679 /* '...' */ 3537 static voidadd_till_single_quote(o_string *dest, struct in_str *input)3680 static int add_till_single_quote(o_string *dest, struct in_str *input) 3538 3681 { 3539 3682 while (1) { … … 3541 3684 if (ch == EOF) { 3542 3685 syntax_error_unterm_ch('\''); 3543 /*xfunc_die(); - redundant */3686 return 0; 3544 3687 } 3545 3688 if (ch == '\'') 3546 return ;3689 return 1; 3547 3690 o_addchr(dest, ch); 3548 3691 } 3549 3692 } 3550 3693 /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ 3551 static voidadd_till_double_quote(o_string *dest, struct in_str *input)3694 static int add_till_double_quote(o_string *dest, struct in_str *input) 3552 3695 { 3553 3696 while (1) { … … 3555 3698 if (ch == EOF) { 3556 3699 syntax_error_unterm_ch('"'); 3557 /*xfunc_die(); - redundant */3700 return 0; 3558 3701 } 3559 3702 if (ch == '"') 3560 return ;3703 return 1; 3561 3704 if (ch == '\\') { /* \x. Copy both chars. */ 3562 3705 o_addchr(dest, ch); … … 3565 3708 o_addchr(dest, ch); 3566 3709 if (ch == '`') { 3567 add_till_backquote(dest, input, /*in_dquote:*/ 1); 3710 if (!add_till_backquote(dest, input, /*in_dquote:*/ 1)) 3711 return 0; 3568 3712 o_addchr(dest, ch); 3569 3713 continue; … … 3586 3730 * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST 3587 3731 */ 3588 static voidadd_till_backquote(o_string *dest, struct in_str *input, int in_dquote)3732 static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote) 3589 3733 { 3590 3734 while (1) { 3591 3735 int ch = i_getch(input); 3592 3736 if (ch == '`') 3593 return ;3737 return 1; 3594 3738 if (ch == '\\') { 3595 3739 /* \x. Copy both unless it is \`, \$, \\ and maybe \" */ … … 3605 3749 if (ch == EOF) { 3606 3750 syntax_error_unterm_ch('`'); 3607 /*xfunc_die(); - redundant */3751 return 0; 3608 3752 } 3609 3753 o_addchr(dest, ch); … … 3641 3785 if (ch == EOF) { 3642 3786 syntax_error_unterm_ch(end_ch); 3643 /*xfunc_die(); - redundant */3787 return 0; 3644 3788 } 3645 3789 if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) { … … 3655 3799 if (ch == '(' || ch == '{') { 3656 3800 ch = (ch == '(' ? ')' : '}'); 3657 add_till_closing_bracket(dest, input, ch); 3801 if (!add_till_closing_bracket(dest, input, ch)) 3802 return 0; 3658 3803 o_addchr(dest, ch); 3659 3804 continue; 3660 3805 } 3661 3806 if (ch == '\'') { 3662 add_till_single_quote(dest, input); 3807 if (!add_till_single_quote(dest, input)) 3808 return 0; 3663 3809 o_addchr(dest, ch); 3664 3810 continue; 3665 3811 } 3666 3812 if (ch == '"') { 3667 add_till_double_quote(dest, input); 3813 if (!add_till_double_quote(dest, input)) 3814 return 0; 3668 3815 o_addchr(dest, ch); 3669 3816 continue; 3670 3817 } 3671 3818 if (ch == '`') { 3672 add_till_backquote(dest, input, /*in_dquote:*/ 0); 3819 if (!add_till_backquote(dest, input, /*in_dquote:*/ 0)) 3820 return 0; 3673 3821 o_addchr(dest, ch); 3674 3822 continue; … … 3679 3827 if (ch == EOF) { 3680 3828 syntax_error_unterm_ch(')'); 3681 /*xfunc_die(); - redundant */3829 return 0; 3682 3830 } 3683 3831 o_addchr(dest, ch); … … 3750 3898 bad_dollar_syntax: 3751 3899 syntax_error_unterm_str("${name}"); 3752 debug_printf_parse("parse_dollar return 1: unterminated ${name}\n");3753 return 1;3900 debug_printf_parse("parse_dollar return 0: unterminated ${name}\n"); 3901 return 0; 3754 3902 } 3755 3903 nommu_addchr(as_string, ch); … … 3807 3955 #if ENABLE_HUSH_DOLLAR_OPS 3808 3956 last_ch = add_till_closing_bracket(dest, input, end_ch); 3957 if (last_ch == 0) /* error? */ 3958 return 0; 3809 3959 #else 3810 3960 #error Simple code to only allow ${var} is not implemented … … 3851 4001 if (!BB_MMU) 3852 4002 pos = dest->length; 3853 add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG); 4003 if (!add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG)) 4004 return 0; /* error */ 3854 4005 if (as_string) { 3855 4006 o_addstr(as_string, dest->data + pos); … … 3866 4017 if (!BB_MMU) 3867 4018 pos = dest->length; 3868 add_till_closing_bracket(dest, input, ')'); 4019 if (!add_till_closing_bracket(dest, input, ')')) 4020 return 0; /* error */ 3869 4021 if (as_string) { 3870 4022 o_addstr(as_string, dest->data + pos); … … 3893 4045 o_addQchr(dest, '$'); 3894 4046 } 3895 debug_printf_parse("parse_dollar return 0\n");3896 return 0;4047 debug_printf_parse("parse_dollar return 1 (ok)\n"); 4048 return 1; 3897 4049 #undef as_string 3898 4050 } … … 3935 4087 nommu_addchr(as_string, ch); 3936 4088 if (ch == dquote_end) { /* may be only '"' or EOF */ 3937 debug_printf_parse("encode_string return 0\n");3938 return 0;4089 debug_printf_parse("encode_string return 1 (ok)\n"); 4090 return 1; 3939 4091 } 3940 4092 /* note: can't move it above ch == dquote_end check! */ 3941 4093 if (ch == EOF) { 3942 4094 syntax_error_unterm_ch('"'); 3943 /*xfunc_die(); - redundant*/4095 return 0; /* error */ 3944 4096 } 3945 4097 next = '\0'; … … 3972 4124 } 3973 4125 if (ch == '$') { 3974 if ( parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80) != 0) {3975 debug_printf_parse("encode_string return 1: "3976 "parse_dollar returned non-0\n");3977 return 1;4126 if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) { 4127 debug_printf_parse("encode_string return 0: " 4128 "parse_dollar returned 0 (error)\n"); 4129 return 0; 3978 4130 } 3979 4131 goto again; … … 3984 4136 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3985 4137 o_addchr(dest, 0x80 | '`'); 3986 add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"'); 4138 if (!add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"')) 4139 return 0; /* error */ 3987 4140 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3988 4141 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); … … 3999 4152 * Return a list of pipes to execute, or NULL on EOF 4000 4153 * or if end_trigger character is met. 4001 * On syntax error, exit i sshell is not interactive,4154 * On syntax error, exit if shell is not interactive, 4002 4155 * reset parsing machinery and start parsing anew, 4003 4156 * or return ERR_PTR. … … 4028 4181 */ 4029 4182 4030 reset: /* we come back here only on syntax errors in interactive shell */4031 4032 #if ENABLE_HUSH_INTERACTIVE4033 input->promptmode = 0; /* PS1 */4034 #endif4035 4183 if (MAYBE_ASSIGNMENT != 0) 4036 4184 dest.o_assignment = MAYBE_ASSIGNMENT; … … 4058 4206 * checking only ')' */ 4059 4207 if (end_trigger == ')') { 4060 syntax_error_unterm_ch('('); /* exits */4061 /* goto parse_error; */4208 syntax_error_unterm_ch('('); 4209 goto parse_error; 4062 4210 } 4063 4211 … … 4072 4220 * bash says: "syntax error near unexpected token '&'") */ 4073 4221 if (pi->num_cmds == 0 4074 IF_HAS_KEYWORDS(&& pi->res_word == RES_NONE)4222 IF_HAS_KEYWORDS(&& pi->res_word == RES_NONE) 4075 4223 ) { 4076 4224 free_pipe_list(pi); … … 4225 4373 /* Do we sit outside of any if's, loops or case's? */ 4226 4374 if (!HAS_KEYWORDS 4227 4375 IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) 4228 4376 ) { 4229 4377 o_free(&dest); … … 4354 4502 break; 4355 4503 case '$': 4356 if ( parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) {4504 if (!parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0)) { 4357 4505 debug_printf_parse("parse_stream parse error: " 4358 "parse_dollar returned non-0\n");4506 "parse_dollar returned 0 (error)\n"); 4359 4507 goto parse_error; 4360 4508 } … … 4362 4510 case '\'': 4363 4511 dest.has_quoted_part = 1; 4364 while (1) { 4365 ch = i_getch(input); 4366 if (ch == EOF) { 4367 syntax_error_unterm_ch('\''); 4368 /*xfunc_die(); - redundant */ 4512 if (next == '\'' && !ctx.pending_redirect) { 4513 insert_empty_quoted_str_marker: 4514 nommu_addchr(&ctx.as_string, next); 4515 i_getch(input); /* eat second ' */ 4516 o_addchr(&dest, SPECIAL_VAR_SYMBOL); 4517 o_addchr(&dest, SPECIAL_VAR_SYMBOL); 4518 } else { 4519 while (1) { 4520 ch = i_getch(input); 4521 if (ch == EOF) { 4522 syntax_error_unterm_ch('\''); 4523 goto parse_error; 4524 } 4525 nommu_addchr(&ctx.as_string, ch); 4526 if (ch == '\'') 4527 break; 4528 o_addqchr(&dest, ch); 4369 4529 } 4370 nommu_addchr(&ctx.as_string, ch);4371 if (ch == '\'')4372 break;4373 o_addqchr(&dest, ch);4374 4530 } 4375 4531 break; 4376 4532 case '"': 4377 4533 dest.has_quoted_part = 1; 4534 if (next == '"' && !ctx.pending_redirect) 4535 goto insert_empty_quoted_str_marker; 4378 4536 if (dest.o_assignment == NOT_ASSIGNMENT) 4379 4537 dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; 4380 if ( encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1))4538 if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) 4381 4539 goto parse_error; 4382 4540 dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; … … 4384 4542 #if ENABLE_HUSH_TICK 4385 4543 case '`': { 4386 unsigned pos;4544 USE_FOR_NOMMU(unsigned pos;) 4387 4545 4388 4546 o_addchr(&dest, SPECIAL_VAR_SYMBOL); 4389 4547 o_addchr(&dest, '`'); 4390 pos = dest.length; 4391 add_till_backquote(&dest, input, /*in_dquote:*/ 0); 4548 USE_FOR_NOMMU(pos = dest.length;) 4549 if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0)) 4550 goto parse_error; 4392 4551 # if !BB_MMU 4393 4552 o_addstr(&ctx.as_string, dest.data + pos); … … 4528 4687 IF_HAS_KEYWORDS(pctx = p2;) 4529 4688 } while (HAS_KEYWORDS && pctx); 4530 /* Free text, clear all dest fields */ 4689 4531 4690 o_free(&dest); 4532 /* If we are not in top-level parse, we return, 4533 * our caller will propagate error. 4534 */ 4535 if (end_trigger != ';') { 4691 G.last_exitcode = 1; 4536 4692 #if !BB_MMU 4537 if (pstring) 4538 *pstring = NULL; 4539 #endif 4540 debug_leave(); 4541 return ERR_PTR; 4542 } 4543 /* Discard cached input, force prompt */ 4544 input->p = NULL; 4545 IF_HUSH_INTERACTIVE(input->promptme = 1;) 4546 goto reset; 4693 if (pstring) 4694 *pstring = NULL; 4695 #endif 4696 debug_leave(); 4697 return ERR_PTR; 4547 4698 } 4548 4699 } … … 4604 4755 /* Store given string, finalizing the word and starting new one whenever 4605 4756 * we encounter IFS char(s). This is used for expanding variable values. 4606 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ 4607 static int expand_on_ifs(o_string *output, int n, const char *str) 4608 { 4757 * End-of-string does NOT finalize word: think about 'echo -$VAR-'. 4758 * Return in *ended_with_ifs: 4759 * 1 - ended with IFS char, else 0 (this includes case of empty str). 4760 */ 4761 static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const char *str) 4762 { 4763 int last_is_ifs = 0; 4764 4609 4765 while (1) { 4610 int word_len = strcspn(str, G.ifs); 4766 int word_len; 4767 4768 if (!*str) /* EOL - do not finalize word */ 4769 break; 4770 word_len = strcspn(str, G.ifs); 4611 4771 if (word_len) { 4772 /* We have WORD_LEN leading non-IFS chars */ 4612 4773 if (!(output->o_expflags & EXP_FLAG_GLOB)) { 4613 4774 o_addblock(output, str, word_len); … … 4622 4783 /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ 4623 4784 } 4785 last_is_ifs = 0; 4624 4786 str += word_len; 4625 } 4787 if (!*str) /* EOL - do not finalize word */ 4788 break; 4789 } 4790 4791 /* We know str here points to at least one IFS char */ 4792 last_is_ifs = 1; 4793 str += strspn(str, G.ifs); /* skip IFS chars */ 4626 4794 if (!*str) /* EOL - do not finalize word */ 4627 4795 break; 4628 o_addchr(output, '\0'); 4629 debug_print_list("expand_on_ifs", output, n); 4630 n = o_save_ptr(output, n); 4631 str += strspn(str, G.ifs); /* skip ifs chars */ 4632 } 4796 4797 /* Start new word... but not always! */ 4798 /* Case "v=' a'; echo ''$v": we do need to finalize empty word: */ 4799 if (output->has_quoted_part 4800 /* Case "v=' a'; echo $v": 4801 * here nothing precedes the space in $v expansion, 4802 * therefore we should not finish the word 4803 * (IOW: if there *is* word to finalize, only then do it): 4804 */ 4805 || (n > 0 && output->data[output->length - 1]) 4806 ) { 4807 o_addchr(output, '\0'); 4808 debug_print_list("expand_on_ifs", output, n); 4809 n = o_save_ptr(output, n); 4810 } 4811 } 4812 4813 if (ended_with_ifs) 4814 *ended_with_ifs = last_is_ifs; 4633 4815 debug_print_list("expand_on_ifs[1]", output, n); 4634 4816 return n; … … 4667 4849 setup_string_in_str(&input, str); 4668 4850 encode_string(NULL, &dest, &input, EOF, process_bkslash); 4851 //TODO: error check (encode_string returns 0 on error)? 4669 4852 //bb_error_msg("'%s' -> '%s'", str, dest.data); 4670 4853 exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash); … … 5044 5227 */ 5045 5228 char cant_be_null = 0; /* only bit 0x80 matters */ 5229 int ended_in_ifs = 0; /* did last unquoted expansion end with IFS chars? */ 5046 5230 char *p; 5047 5231 … … 5062 5246 char arith_buf[sizeof(arith_t)*3 + 2]; 5063 5247 #endif 5248 5249 if (ended_in_ifs) { 5250 o_addchr(output, '\0'); 5251 n = o_save_ptr(output, n); 5252 ended_in_ifs = 0; 5253 } 5254 5064 5255 o_addblock(output, arg, p - arg); 5065 5256 debug_print_list("expand_vars_to_list[1]", output, n); … … 5090 5281 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ 5091 5282 while (G.global_argv[i]) { 5092 n = expand_on_ifs( output, n, G.global_argv[i]);5283 n = expand_on_ifs(NULL, output, n, G.global_argv[i]); 5093 5284 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); 5094 5285 if (G.global_argv[i++][0] && G.global_argv[i]) { … … 5123 5314 o_addchr(output, G.ifs[0]); 5124 5315 } 5316 output->has_quoted_part = 1; 5125 5317 } 5126 5318 break; … … 5128 5320 case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ 5129 5321 /* "Empty variable", used to make "" etc to not disappear */ 5322 output->has_quoted_part = 1; 5130 5323 arg++; 5131 5324 cant_be_null = 0x80; … … 5165 5358 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); 5166 5359 if (val && val[0]) { 5167 n = expand_on_ifs( output, n, val);5360 n = expand_on_ifs(&ended_in_ifs, output, n, val); 5168 5361 val = NULL; 5169 5362 } 5170 5363 } else { /* quoted $VAR, val will be appended below */ 5364 output->has_quoted_part = 1; 5171 5365 debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, 5172 5366 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); … … 5193 5387 5194 5388 if (arg[0]) { 5389 if (ended_in_ifs) { 5390 o_addchr(output, '\0'); 5391 n = o_save_ptr(output, n); 5392 } 5195 5393 debug_print_list("expand_vars_to_list[a]", output, n); 5196 5394 /* this part is literal, and it was already pre-quoted … … 5323 5521 5324 5522 5523 static void switch_off_special_sigs(unsigned mask) 5524 { 5525 unsigned sig = 0; 5526 while ((mask >>= 1) != 0) { 5527 sig++; 5528 if (!(mask & 1)) 5529 continue; 5530 if (G.traps) { 5531 if (G.traps[sig] && !G.traps[sig][0]) 5532 /* trap is '', has to remain SIG_IGN */ 5533 continue; 5534 free(G.traps[sig]); 5535 G.traps[sig] = NULL; 5536 } 5537 /* We are here only if no trap or trap was not '' */ 5538 install_sighandler(sig, SIG_DFL); 5539 } 5540 } 5541 5325 5542 #if BB_MMU 5326 5543 /* never called */ … … 5342 5559 * Same goes for SIGTERM, SIGHUP, SIGINT. 5343 5560 */ 5344 if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS)) 5345 return; /* already no traps and no SPECIAL_INTERACTIVE_SIGS */ 5346 5347 /* Switching off SPECIAL_INTERACTIVE_SIGS. 5348 * Stupid. It can be done with *single* &= op, but we can't use 5349 * the fact that G.blocked_set is implemented as a bitmask 5350 * in libc... */ 5351 mask = (SPECIAL_INTERACTIVE_SIGS >> 1); 5352 sig = 1; 5353 while (1) { 5354 if (mask & 1) { 5355 /* Careful. Only if no trap or trap is not "" */ 5356 if (!G.traps || !G.traps[sig] || G.traps[sig][0]) 5357 sigdelset(&G.blocked_set, sig); 5358 } 5359 mask >>= 1; 5360 if (!mask) 5361 break; 5362 sig++; 5363 } 5364 /* Our homegrown sig mask is saner to work with :) */ 5365 G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS; 5366 5367 /* Resetting all traps to default except empty ones */ 5368 mask = G.non_DFL_mask; 5369 if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) { 5370 if (!G.traps[sig] || !G.traps[sig][0]) 5371 continue; 5561 mask = (G.special_sig_mask & SPECIAL_INTERACTIVE_SIGS) | G_fatal_sig_mask; 5562 if (!G.traps && !mask) 5563 return; /* already no traps and no special sigs */ 5564 5565 /* Switch off special sigs */ 5566 switch_off_special_sigs(mask); 5567 #if ENABLE_HUSH_JOB 5568 G_fatal_sig_mask = 0; 5569 #endif 5570 G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS; 5571 /* SIGQUIT,SIGCHLD and maybe SPECIAL_JOBSTOP_SIGS 5572 * remain set in G.special_sig_mask */ 5573 5574 if (!G.traps) 5575 return; 5576 5577 /* Reset all sigs to default except ones with empty traps */ 5578 for (sig = 0; sig < NSIG; sig++) { 5579 if (!G.traps[sig]) 5580 continue; /* no trap: nothing to do */ 5581 if (!G.traps[sig][0]) 5582 continue; /* empty trap: has to remain SIG_IGN */ 5583 /* sig has non-empty trap, reset it: */ 5372 5584 free(G.traps[sig]); 5373 5585 G.traps[sig] = NULL; 5374 /* There is no signal for 0 (EXIT) */5586 /* There is no signal for trap 0 (EXIT) */ 5375 5587 if (sig == 0) 5376 5588 continue; 5377 /* There was a trap handler, we just removed it. 5378 * But if sig still has non-DFL handling, 5379 * we should not unblock the sig. */ 5380 if (mask & 1) 5381 continue; 5382 sigdelset(&G.blocked_set, sig); 5383 } 5384 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 5589 install_sighandler(sig, pick_sighandler(sig)); 5590 } 5385 5591 } 5386 5592 … … 5493 5699 * 5494 5700 * I conclude it means we don't need to pass active traps here. 5495 * Even if we would use signal handlers instead of signal masking5496 * in order to implement trap handling,5497 * exec syscall below resets signals to SIG_DFL for us.5498 5701 */ 5499 5702 *pp++ = (char *) "-c"; … … 5512 5715 do_exec: 5513 5716 debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); 5514 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 5717 /* Don't propagate SIG_IGN to the child */ 5718 if (SPECIAL_JOBSTOP_SIGS != 0) 5719 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); 5515 5720 execve(bb_busybox_exec_path, argv, pp); 5516 5721 /* Fallback. Useful for init=/bin/hush usage etc */ … … 5543 5748 struct pipe *pipe_list; 5544 5749 5750 #if ENABLE_HUSH_INTERACTIVE 5751 if (end_trigger == ';') 5752 inp->promptmode = 0; /* PS1 */ 5753 #endif 5545 5754 pipe_list = parse_stream(NULL, inp, end_trigger); 5546 if (!pipe_list) { /* EOF */ 5547 if (empty) 5755 if (!pipe_list || pipe_list == ERR_PTR) { /* EOF/error */ 5756 /* If we are in "big" script 5757 * (not in `cmd` or something similar)... 5758 */ 5759 if (pipe_list == ERR_PTR && end_trigger == ';') { 5760 /* Discard cached input (rest of line) */ 5761 int ch = inp->last_char; 5762 while (ch != EOF && ch != '\n') { 5763 //bb_error_msg("Discarded:'%c'", ch); 5764 ch = i_getch(inp); 5765 } 5766 /* Force prompt */ 5767 inp->p = NULL; 5768 /* This stream isn't empty */ 5769 empty = 0; 5770 continue; 5771 } 5772 if (!pipe_list && empty) 5548 5773 G.last_exitcode = 0; 5549 5774 break; … … 5553 5778 run_and_free_list(pipe_list); 5554 5779 empty = 0; 5780 #if ENABLE_HUSH_FUNCTIONS 5781 if (G.flag_return_in_progress == 1) 5782 break; 5783 #endif 5555 5784 } 5556 5785 } … … 6119 6348 { 6120 6349 #if BB_MMU 6121 int rcode = x->b_function(argv); 6350 int rcode; 6351 fflush_all(); 6352 rcode = x->b_function(argv); 6122 6353 fflush_all(); 6123 6354 _exit(rcode); 6124 6355 #else 6356 fflush_all(); 6125 6357 /* On NOMMU, we must never block! 6126 6358 * Example: { sleep 99 | read line; } & echo Ok … … 6139 6371 { 6140 6372 debug_printf_exec("execing '%s'\n", argv[0]); 6141 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 6373 /* Don't propagate SIG_IGN to the child */ 6374 if (SPECIAL_JOBSTOP_SIGS != 0) 6375 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); 6142 6376 execvp(argv[0], argv); 6143 6377 bb_perror_msg("can't execute '%s'", argv[0]); … … 6271 6505 /* Re-exec ourselves */ 6272 6506 debug_printf_exec("re-execing applet '%s'\n", argv[0]); 6273 sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); 6507 /* Don't propagate SIG_IGN to the child */ 6508 if (SPECIAL_JOBSTOP_SIGS != 0) 6509 switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); 6274 6510 execv(bb_busybox_exec_path, argv); 6275 6511 /* If they called chroot or otherwise made the binary no longer … … 6514 6750 ex = WEXITSTATUS(status); 6515 6751 /* bash prints killer signal's name for *last* 6516 * process in pipe (prints just newline for SIGINT ).6752 * process in pipe (prints just newline for SIGINT/SIGPIPE). 6517 6753 * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) 6518 6754 */ … … 6520 6756 int sig = WTERMSIG(status); 6521 6757 if (i == fg_pipe->num_cmds-1) 6522 printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); 6758 /* TODO: use strsignal() instead for bash compat? but that's bloat... */ 6759 printf("%s\n", sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); 6760 /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ 6523 6761 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? 6524 6762 * Maybe we need to use sig | 128? */ … … 6527 6765 fg_pipe->cmds[i].cmd_exitcode = ex; 6528 6766 } else { 6529 fg_pipe->cmds[i].is_stopped = 1;6530 6767 fg_pipe->stopped_cmds++; 6531 6768 } … … 6588 6825 } else { 6589 6826 /* child stopped */ 6590 pi->cmds[i].is_stopped = 1;6591 6827 pi->stopped_cmds++; 6592 6828 } … … 6629 6865 * cmd && ... { list } && ... 6630 6866 * cmd || ... { list } || ... 6631 * If it is, then we can run cmd as a builtin, NOFORK [do we do this?],6867 * If it is, then we can run cmd as a builtin, NOFORK, 6632 6868 * or (if SH_STANDALONE) an applet, and we can run the { list } 6633 6869 * with run_list. If it isn't one of these, we fork and exec cmd. … … 6811 7047 6812 7048 /* Expand the rest into (possibly) many strings each */ 6813 if (0) {}6814 7049 #if ENABLE_HUSH_BASH_COMPAT 6815 elseif (command->cmd_type == CMD_SINGLEWORD_NOGLOB) {7050 if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) { 6816 7051 argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); 6817 } 6818 #endif 6819 else{7052 } else 7053 #endif 7054 { 6820 7055 argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); 6821 7056 } … … 6847 7082 debug_printf_exec(": builtin '%s' '%s'...\n", 6848 7083 x->b_cmd, argv_expanded[1]); 7084 fflush_all(); 6849 7085 rcode = x->b_function(argv_expanded) & 0xff; 6850 7086 fflush_all(); … … 6879 7115 } 6880 7116 6881 if (ENABLE_FEATURE_SH_ STANDALONE) {7117 if (ENABLE_FEATURE_SH_NOFORK) { 6882 7118 int n = find_applet_by_name(argv_expanded[0]); 6883 7119 if (n >= 0 && APPLET_IS_NOFORK(n)) { … … 6968 7204 _exit(1); 6969 7205 6970 /* Restore default handlers just prior to exec */6971 /*signal(SIGCHLD, SIG_DFL); - so far we don't have any handlers */6972 6973 7206 /* Stores to nommu_save list of env vars putenv'ed 6974 7207 * (NOMMU, on MMU we don't need that) */ … … 7248 7481 G.last_exitcode = rcode; 7249 7482 debug_printf_exec(": builtin/func exitcode %d\n", rcode); 7250 check_and_run_traps( 0);7483 check_and_run_traps(); 7251 7484 #if ENABLE_HUSH_LOOPS 7252 7485 /* Was it "break" or "continue"? */ … … 7280 7513 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". 7281 7514 * I'm NOT treating inner &'s as jobs */ 7282 check_and_run_traps( 0);7515 check_and_run_traps(); 7283 7516 #if ENABLE_HUSH_JOB 7284 7517 if (G.run_list_level == 1) … … 7295 7528 rcode = checkjobs_and_fg_shell(pi); 7296 7529 debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode); 7297 check_and_run_traps( 0);7530 check_and_run_traps(); 7298 7531 } else 7299 7532 #endif … … 7301 7534 rcode = checkjobs(pi); 7302 7535 debug_printf_exec(": checkjobs exitcode %d\n", rcode); 7303 check_and_run_traps( 0);7536 check_and_run_traps(); 7304 7537 } 7305 7538 G.last_exitcode = rcode; … … 7316 7549 if (pi->next 7317 7550 && (pi->next->res_word == RES_DO || pi->next->res_word == RES_DONE) 7318 /* (the second check above is needed for "while ...; do \n done" case)*/7551 /* check for RES_DONE is needed for "while ...; do \n done" case */ 7319 7552 ) { 7320 7553 if (rword == RES_WHILE) { … … 7362 7595 int rcode = 0; 7363 7596 debug_printf_exec("run_and_free_list entered\n"); 7364 if (!G. n_mode) {7597 if (!G.o_opt[OPT_O_NOEXEC]) { 7365 7598 debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); 7366 7599 rcode = run_list(pi); … … 7375 7608 7376 7609 7610 static void install_sighandlers(unsigned mask) 7611 { 7612 sighandler_t old_handler; 7613 unsigned sig = 0; 7614 while ((mask >>= 1) != 0) { 7615 sig++; 7616 if (!(mask & 1)) 7617 continue; 7618 old_handler = install_sighandler(sig, pick_sighandler(sig)); 7619 /* POSIX allows shell to re-enable SIGCHLD 7620 * even if it was SIG_IGN on entry. 7621 * Therefore we skip IGN check for it: 7622 */ 7623 if (sig == SIGCHLD) 7624 continue; 7625 if (old_handler == SIG_IGN) { 7626 /* oops... restore back to IGN, and record this fact */ 7627 install_sighandler(sig, old_handler); 7628 if (!G.traps) 7629 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); 7630 free(G.traps[sig]); 7631 G.traps[sig] = xzalloc(1); /* == xstrdup(""); */ 7632 } 7633 } 7634 } 7635 7377 7636 /* Called a few times only (or even once if "sh -c") */ 7378 static void init_sigmasks(void) 7379 { 7380 unsigned sig; 7637 static void install_special_sighandlers(void) 7638 { 7381 7639 unsigned mask; 7382 sigset_t old_blocked_set; 7383 7384 if (!G.inherited_set_is_saved) { 7385 sigprocmask(SIG_SETMASK, NULL, &G.blocked_set); 7386 G.inherited_set = G.blocked_set; 7387 } 7388 old_blocked_set = G.blocked_set; 7389 7390 mask = (1 << SIGQUIT); 7640 7641 /* Which signals are shell-special? */ 7642 mask = (1 << SIGQUIT) | (1 << SIGCHLD); 7391 7643 if (G_interactive_fd) { 7392 mask = (1 << SIGQUIT) |SPECIAL_INTERACTIVE_SIGS;7644 mask |= SPECIAL_INTERACTIVE_SIGS; 7393 7645 if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ 7394 mask |= SPECIAL_JOB_SIGS; 7395 } 7396 G.non_DFL_mask = mask; 7397 7398 sig = 0; 7399 while (mask) { 7400 if (mask & 1) 7401 sigaddset(&G.blocked_set, sig); 7402 mask >>= 1; 7403 sig++; 7404 } 7405 sigdelset(&G.blocked_set, SIGCHLD); 7406 7407 if (memcmp(&old_blocked_set, &G.blocked_set, sizeof(old_blocked_set)) != 0) 7408 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 7409 7410 /* POSIX allows shell to re-enable SIGCHLD 7411 * even if it was SIG_IGN on entry */ 7412 #if ENABLE_HUSH_FAST 7413 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ 7414 if (!G.inherited_set_is_saved) 7415 signal(SIGCHLD, SIGCHLD_handler); 7416 #else 7417 if (!G.inherited_set_is_saved) 7418 signal(SIGCHLD, SIG_DFL); 7419 #endif 7420 7421 G.inherited_set_is_saved = 1; 7646 mask |= SPECIAL_JOBSTOP_SIGS; 7647 } 7648 /* Careful, do not re-install handlers we already installed */ 7649 if (G.special_sig_mask != mask) { 7650 unsigned diff = mask & ~G.special_sig_mask; 7651 G.special_sig_mask = mask; 7652 install_sighandlers(diff); 7653 } 7422 7654 } 7423 7655 7424 7656 #if ENABLE_HUSH_JOB 7425 7657 /* helper */ 7426 static void maybe_set_to_sigexit(int sig) 7427 { 7428 void (*handler)(int); 7429 /* non_DFL_mask'ed signals are, well, masked, 7430 * no need to set handler for them. 7658 /* Set handlers to restore tty pgrp and exit */ 7659 static void install_fatal_sighandlers(void) 7660 { 7661 unsigned mask; 7662 7663 /* We will restore tty pgrp on these signals */ 7664 mask = 0 7665 + (1 << SIGILL ) * HUSH_DEBUG 7666 + (1 << SIGFPE ) * HUSH_DEBUG 7667 + (1 << SIGBUS ) * HUSH_DEBUG 7668 + (1 << SIGSEGV) * HUSH_DEBUG 7669 + (1 << SIGTRAP) * HUSH_DEBUG 7670 + (1 << SIGABRT) 7671 /* bash 3.2 seems to handle these just like 'fatal' ones */ 7672 + (1 << SIGPIPE) 7673 + (1 << SIGALRM) 7674 /* if we are interactive, SIGHUP, SIGTERM and SIGINT are special sigs. 7675 * if we aren't interactive... but in this case 7676 * we never want to restore pgrp on exit, and this fn is not called 7431 7677 */ 7432 if (!((G.non_DFL_mask >> sig) & 1)) { 7433 handler = signal(sig, sigexit); 7434 if (handler == SIG_IGN) /* oops... restore back to IGN! */ 7435 signal(sig, handler); 7436 } 7437 } 7438 /* Set handlers to restore tty pgrp and exit */ 7439 static void set_fatal_handlers(void) 7440 { 7441 /* We _must_ restore tty pgrp on fatal signals */ 7442 if (HUSH_DEBUG) { 7443 maybe_set_to_sigexit(SIGILL ); 7444 maybe_set_to_sigexit(SIGFPE ); 7445 maybe_set_to_sigexit(SIGBUS ); 7446 maybe_set_to_sigexit(SIGSEGV); 7447 maybe_set_to_sigexit(SIGTRAP); 7448 } /* else: hush is perfect. what SEGV? */ 7449 maybe_set_to_sigexit(SIGABRT); 7450 /* bash 3.2 seems to handle these just like 'fatal' ones */ 7451 maybe_set_to_sigexit(SIGPIPE); 7452 maybe_set_to_sigexit(SIGALRM); 7453 /* if we are interactive, SIGHUP, SIGTERM and SIGINT are masked. 7454 * if we aren't interactive... but in this case 7455 * we never want to restore pgrp on exit, and this fn is not called */ 7456 /*maybe_set_to_sigexit(SIGHUP );*/ 7457 /*maybe_set_to_sigexit(SIGTERM);*/ 7458 /*maybe_set_to_sigexit(SIGINT );*/ 7678 /*+ (1 << SIGHUP )*/ 7679 /*+ (1 << SIGTERM)*/ 7680 /*+ (1 << SIGINT )*/ 7681 ; 7682 G_fatal_sig_mask = mask; 7683 7684 install_sighandlers(mask); 7459 7685 } 7460 7686 #endif … … 7465 7691 switch (mode) { 7466 7692 case 'n': 7467 G. n_mode= state;7693 G.o_opt[OPT_O_NOEXEC] = state; 7468 7694 break; 7469 7695 case 'x': … … 7502 7728 int hush_main(int argc, char **argv) 7503 7729 { 7730 enum { 7731 OPT_login = (1 << 0), 7732 }; 7733 unsigned flags; 7504 7734 int opt; 7505 7735 unsigned builtin_argc; … … 7509 7739 7510 7740 INIT_G(); 7511 if (EXIT_SUCCESS ) /* if EXIT_SUCCESS == 0, it is already done */7741 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ 7512 7742 G.last_exitcode = EXIT_SUCCESS; 7743 #if ENABLE_HUSH_FAST 7744 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ 7745 #endif 7513 7746 #if !BB_MMU 7514 7747 G.argv0_for_re_execing = argv[0]; … … 7584 7817 #if ENABLE_FEATURE_EDITING 7585 7818 G.line_input_state = new_line_input_t(FOR_SHELL); 7586 # if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_HUSH_SAVEHISTORY 7587 { 7588 const char *hp = get_local_var_value("HISTFILE"); 7589 if (!hp) { 7590 hp = get_local_var_value("HOME"); 7591 if (hp) { 7592 G.line_input_state->hist_file = concat_path_file(hp, ".hush_history"); 7593 //set_local_var(xasprintf("HISTFILE=%s", ...)); 7594 } 7595 } 7596 } 7597 # endif 7598 #endif 7599 7600 G.global_argc = argc; 7601 G.global_argv = argv; 7819 #endif 7820 7602 7821 /* Initialize some more globals to non-zero values */ 7603 7822 cmdedit_update_prompt(); … … 7611 7830 7612 7831 /* Shell is non-interactive at first. We need to call 7613 * in it_sigmasks() if we are going to execute "sh <script>",7832 * install_special_sighandlers() if we are going to execute "sh <script>", 7614 7833 * "sh -c <cmds>" or login shell's /etc/profile and friends. 7615 * If we later decide that we are interactive, we run in it_sigmasks()7834 * If we later decide that we are interactive, we run install_special_sighandlers() 7616 7835 * in order to intercept (more) signals. 7617 7836 */ … … 7619 7838 /* Parse options */ 7620 7839 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ 7840 flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; 7621 7841 builtin_argc = 0; 7622 7842 while (1) { 7623 opt = getopt(argc, argv, "+c:xins "7843 opt = getopt(argc, argv, "+c:xinsl" 7624 7844 #if !BB_MMU 7625 7845 "<:$:R:V:" … … 7653 7873 const struct built_in_command *x; 7654 7874 7655 in it_sigmasks();7875 install_special_sighandlers(); 7656 7876 x = find_builtin(optarg); 7657 7877 if (x) { /* paranoia */ … … 7659 7879 G.global_argv += builtin_argc; 7660 7880 G.global_argv[-1] = NULL; /* replace "" */ 7881 fflush_all(); 7661 7882 G.last_exitcode = x->b_function(argv + optind - 1); 7662 7883 } … … 7669 7890 G.global_argc++; 7670 7891 } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */ 7671 in it_sigmasks();7892 install_special_sighandlers(); 7672 7893 parse_and_run_string(optarg); 7673 7894 goto final_return; … … 7680 7901 /* "-s" means "read from stdin", but this is how we always 7681 7902 * operate, so simply do nothing here. */ 7903 break; 7904 case 'l': 7905 flags |= OPT_login; 7682 7906 break; 7683 7907 #if !BB_MMU … … 7701 7925 if (empty_trap_mask != 0) { 7702 7926 int sig; 7703 in it_sigmasks();7927 install_special_sighandlers(); 7704 7928 G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); 7705 7929 for (sig = 1; sig < NSIG; sig++) { 7706 7930 if (empty_trap_mask & (1LL << sig)) { 7707 7931 G.traps[sig] = xzalloc(1); /* == xstrdup(""); */ 7708 sigaddset(&G.blocked_set, sig);7932 install_sighandler(sig, SIG_IGN); 7709 7933 } 7710 7934 } 7711 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);7712 7935 } 7713 7936 # if ENABLE_HUSH_LOOPS … … 7747 7970 } /* option parsing loop */ 7748 7971 7972 /* Skip options. Try "hush -l": $1 should not be "-l"! */ 7973 G.global_argc = argc - (optind - 1); 7974 G.global_argv = argv + (optind - 1); 7975 G.global_argv[0] = argv[0]; 7976 7749 7977 if (!G.root_pid) { 7750 7978 G.root_pid = getpid(); … … 7753 7981 7754 7982 /* If we are login shell... */ 7755 if ( argv[0] && argv[0][0] == '-') {7983 if (flags & OPT_login) { 7756 7984 FILE *input; 7757 7985 debug_printf("sourcing /etc/profile\n"); … … 7759 7987 if (input != NULL) { 7760 7988 close_on_exec_on(fileno(input)); 7761 in it_sigmasks();7989 install_special_sighandlers(); 7762 7990 parse_and_run_file(input); 7763 7991 fclose(input); … … 7772 8000 } 7773 8001 7774 if ( argv[optind]) {8002 if (G.global_argv[1]) { 7775 8003 FILE *input; 7776 8004 /* … … 7779 8007 * If called as sh, does the same but with $ENV. 7780 8008 */ 7781 debug_printf("running script '%s'\n", argv[optind]);7782 G.global_argv = argv + optind;7783 G.global_argc = argc - optind;7784 input = xfopen_for_read( argv[optind]);8009 G.global_argc--; 8010 G.global_argv++; 8011 debug_printf("running script '%s'\n", G.global_argv[0]); 8012 input = xfopen_for_read(G.global_argv[0]); 7785 8013 close_on_exec_on(fileno(input)); 7786 in it_sigmasks();8014 install_special_sighandlers(); 7787 8015 parse_and_run_file(input); 7788 8016 #if ENABLE_FEATURE_CLEAN_UP … … 7793 8021 7794 8022 /* Up to here, shell was non-interactive. Now it may become one. 7795 * NB: don't forget to (re)run in it_sigmasks() as needed.8023 * NB: don't forget to (re)run install_special_sighandlers() as needed. 7796 8024 */ 7797 8025 … … 7845 8073 } 7846 8074 7847 /* Block some signals */7848 in it_sigmasks();8075 /* Install more signal handlers */ 8076 install_special_sighandlers(); 7849 8077 7850 8078 if (G_saved_tty_pgrp) { 7851 8079 /* Set other signals to restore saved_tty_pgrp */ 7852 set_fatal_handlers();8080 install_fatal_sighandlers(); 7853 8081 /* Put ourselves in our own process group 7854 8082 * (bash, too, does this only if ctty is available) */ … … 7860 8088 * (we reset die_sleep = 0 whereever we [v]fork) */ 7861 8089 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */ 8090 8091 # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 8092 { 8093 const char *hp = get_local_var_value("HISTFILE"); 8094 if (!hp) { 8095 hp = get_local_var_value("HOME"); 8096 if (hp) 8097 hp = concat_path_file(hp, ".hush_history"); 8098 } else { 8099 hp = xstrdup(hp); 8100 } 8101 if (hp) { 8102 G.line_input_state->hist_file = hp; 8103 //set_local_var(xasprintf("HISTFILE=%s", ...)); 8104 } 8105 # if ENABLE_FEATURE_SH_HISTFILESIZE 8106 hp = get_local_var_value("HISTFILESIZE"); 8107 G.line_input_state->max_history = size_from_HISTFILESIZE(hp); 8108 # endif 8109 } 8110 # endif 7862 8111 } else { 7863 in it_sigmasks();8112 install_special_sighandlers(); 7864 8113 } 7865 8114 #elif ENABLE_HUSH_INTERACTIVE … … 7878 8127 close_on_exec_on(G_interactive_fd); 7879 8128 } 7880 in it_sigmasks();8129 install_special_sighandlers(); 7881 8130 #else 7882 8131 /* We have interactiveness code disabled */ 7883 in it_sigmasks();8132 install_special_sighandlers(); 7884 8133 #endif 7885 8134 /* bash: … … 8015 8264 8016 8265 /* TODO: if exec fails, bash does NOT exit! We do. 8017 * We'll need to undo sigprocmask(it's inside execvp_or_die)8266 * We'll need to undo trap cleanup (it's inside execvp_or_die) 8018 8267 * and tcsetpgrp, and this is inherently racy. 8019 8268 */ … … 8033 8282 * # exit 8034 8283 * exit 8035 #EEE (then bash exits)8284 * EEE (then bash exits) 8036 8285 * 8037 8286 * TODO: we can use G.exiting = -1 as indicator "last cmd was exit" … … 8212 8461 ret = EXIT_SUCCESS; 8213 8462 while (*argv) { 8463 sighandler_t handler; 8464 8214 8465 sig = get_signum(*argv++); 8215 8466 if (sig < 0 || sig >= NSIG) { … … 8230 8481 continue; 8231 8482 8232 if (new_cmd) { 8233 sigaddset(&G.blocked_set, sig); 8234 } else { 8235 /* There was a trap handler, we are removing it 8236 * (if sig has non-DFL handling, 8237 * we don't need to do anything) */ 8238 if (sig < 32 && (G.non_DFL_mask & (1 << sig))) 8239 continue; 8240 sigdelset(&G.blocked_set, sig); 8241 } 8242 } 8243 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 8483 if (new_cmd) 8484 handler = (new_cmd[0] ? record_pending_signo : SIG_IGN); 8485 else 8486 /* We are removing trap handler */ 8487 handler = pick_sighandler(sig); 8488 install_sighandler(sig, handler); 8489 } 8244 8490 return ret; 8245 8491 } … … 8346 8592 for (i = 0; i < pi->num_cmds; i++) { 8347 8593 debug_printf_jobs("reviving pid %d\n", pi->cmds[i].pid); 8348 pi->cmds[i].is_stopped = 0;8349 8594 } 8350 8595 pi->stopped_cmds = 0; … … 8442 8687 } 8443 8688 8689 /* Interruptibility of read builtin in bash 8690 * (tested on bash-4.2.8 by sending signals (not by ^C)): 8691 * 8692 * Empty trap makes read ignore corresponding signal, for any signal. 8693 * 8694 * SIGINT: 8695 * - terminates non-interactive shell; 8696 * - interrupts read in interactive shell; 8697 * if it has non-empty trap: 8698 * - executes trap and returns to command prompt in interactive shell; 8699 * - executes trap and returns to read in non-interactive shell; 8700 * SIGTERM: 8701 * - is ignored (does not interrupt) read in interactive shell; 8702 * - terminates non-interactive shell; 8703 * if it has non-empty trap: 8704 * - executes trap and returns to read; 8705 * SIGHUP: 8706 * - terminates shell (regardless of interactivity); 8707 * if it has non-empty trap: 8708 * - executes trap and returns to read; 8709 */ 8444 8710 static int FAST_FUNC builtin_read(char **argv) 8445 8711 { … … 8449 8715 char *opt_t = NULL; 8450 8716 char *opt_u = NULL; 8717 const char *ifs; 8451 8718 int read_flags; 8452 8719 … … 8458 8725 return EXIT_FAILURE; 8459 8726 argv += optind; 8460 8727 ifs = get_local_var_value("IFS"); /* can be NULL */ 8728 8729 again: 8461 8730 r = shell_builtin_read(set_local_var_from_halves, 8462 8731 argv, 8463 get_local_var_value("IFS"), /* can be NULL */8732 ifs, 8464 8733 read_flags, 8465 8734 opt_n, … … 8468 8737 opt_u 8469 8738 ); 8739 8740 if ((uintptr_t)r == 1 && errno == EINTR) { 8741 unsigned sig = check_and_run_traps(); 8742 if (sig && sig != SIGINT) 8743 goto again; 8744 } 8470 8745 8471 8746 if ((uintptr_t)r > 1) { … … 8701 8976 { 8702 8977 int ret = EXIT_SUCCESS; 8703 int status , sig;8978 int status; 8704 8979 8705 8980 argv = skip_dash_dash(argv); … … 8721 8996 * $ 8722 8997 */ 8723 sigaddset(&G.blocked_set, SIGCHLD);8724 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);8725 8998 while (1) { 8726 checkjobs(NULL); 8727 if (errno == ECHILD) 8999 int sig; 9000 sigset_t oldset, allsigs; 9001 9002 /* waitpid is not interruptible by SA_RESTARTed 9003 * signals which we use. Thus, this ugly dance: 9004 */ 9005 9006 /* Make sure possible SIGCHLD is stored in kernel's 9007 * pending signal mask before we call waitpid. 9008 * Or else we may race with SIGCHLD, lose it, 9009 * and get stuck in sigwaitinfo... 9010 */ 9011 sigfillset(&allsigs); 9012 sigprocmask(SIG_SETMASK, &allsigs, &oldset); 9013 9014 if (!sigisemptyset(&G.pending_set)) { 9015 /* Crap! we raced with some signal! */ 9016 // sig = 0; 9017 goto restore; 9018 } 9019 9020 checkjobs(NULL); /* waitpid(WNOHANG) inside */ 9021 if (errno == ECHILD) { 9022 sigprocmask(SIG_SETMASK, &oldset, NULL); 8728 9023 break; 8729 /* Wait for SIGCHLD or any other signal of interest */ 8730 /* sigtimedwait with infinite timeout: */ 8731 sig = sigwaitinfo(&G.blocked_set, NULL); 8732 if (sig > 0) { 8733 sig = check_and_run_traps(sig); 8734 if (sig && sig != SIGCHLD) { /* see note 2 */ 8735 ret = 128 + sig; 8736 break; 8737 } 8738 } 8739 } 8740 sigdelset(&G.blocked_set, SIGCHLD); 8741 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); 9024 } 9025 9026 /* Wait for SIGCHLD or any other signal */ 9027 //sig = sigwaitinfo(&allsigs, NULL); 9028 /* It is vitally important for sigsuspend that SIGCHLD has non-DFL handler! */ 9029 /* Note: sigsuspend invokes signal handler */ 9030 sigsuspend(&oldset); 9031 restore: 9032 sigprocmask(SIG_SETMASK, &oldset, NULL); 9033 9034 /* So, did we get a signal? */ 9035 //if (sig > 0) 9036 // raise(sig); /* run handler */ 9037 sig = check_and_run_traps(); 9038 if (sig /*&& sig != SIGCHLD - always true */) { 9039 /* see note 2 */ 9040 ret = 128 + sig; 9041 break; 9042 } 9043 /* SIGCHLD, or no signal, or ignored one, such as SIGQUIT. Repeat */ 9044 } 8742 9045 return ret; 8743 9046 }
Note:
See TracChangeset
for help on using the changeset viewer.