diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-12 02:10:33 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-12 02:10:33 +0200 |
commit | f58f705c5812cec5d5308ae29baceeb648d08e24 (patch) | |
tree | 8028164dcbc39a2cc18afce67e7ef5d72926f060 /shell | |
parent | 9d6cbafe728c9100a35e29ba7a3729c5303e73ea (diff) | |
download | busybox-w32-f58f705c5812cec5d5308ae29baceeb648d08e24.tar.gz busybox-w32-f58f705c5812cec5d5308ae29baceeb648d08e24.tar.bz2 busybox-w32-f58f705c5812cec5d5308ae29baceeb648d08e24.zip |
hush: fix login shell's signal handling; add -l option so that it's easier to test
function old new delta
hush_main 958 1001 +43
install_special_sighandlers 47 52 +5
packed_usage 28752 28741 -11
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 48/-11) Total: 37 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 67 |
1 files changed, 35 insertions, 32 deletions
diff --git a/shell/hush.c b/shell/hush.c index b2c3a752e..cdd4be4e3 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -260,7 +260,7 @@ typedef void (*hush_sighandler_t)(int); | |||
260 | * therefore we don't show them either. | 260 | * therefore we don't show them either. |
261 | */ | 261 | */ |
262 | //usage:#define hush_trivial_usage | 262 | //usage:#define hush_trivial_usage |
263 | //usage: "[-nx] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" | 263 | //usage: "[-nxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" |
264 | //usage:#define hush_full_usage "\n\n" | 264 | //usage:#define hush_full_usage "\n\n" |
265 | //usage: "Unix shell interpreter" | 265 | //usage: "Unix shell interpreter" |
266 | 266 | ||
@@ -1493,8 +1493,8 @@ static sighandler_t pick_sighandler(unsigned sig) | |||
1493 | handler = record_pending_signo; | 1493 | handler = record_pending_signo; |
1494 | /* TTIN/TTOU/TSTS can't be set to record_pending_signo | 1494 | /* TTIN/TTOU/TSTS can't be set to record_pending_signo |
1495 | * in order to ignore them: they will be raised | 1495 | * in order to ignore them: they will be raised |
1496 | * in an endless loop then when we try to do some | 1496 | * in an endless loop when we try to do some |
1497 | * terminal ioctls! We do nave to _ignore_ these. | 1497 | * terminal ioctls! We do have to _ignore_ these. |
1498 | */ | 1498 | */ |
1499 | if (SPECIAL_JOBSTOP_SIGS & sigmask) | 1499 | if (SPECIAL_JOBSTOP_SIGS & sigmask) |
1500 | handler = SIG_IGN; | 1500 | handler = SIG_IGN; |
@@ -1508,9 +1508,6 @@ static void hush_exit(int exitcode) | |||
1508 | { | 1508 | { |
1509 | fflush_all(); | 1509 | fflush_all(); |
1510 | if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { | 1510 | if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { |
1511 | /* Prevent recursion: | ||
1512 | * trap "echo Hi; exit" EXIT; exit | ||
1513 | */ | ||
1514 | char *argv[3]; | 1511 | char *argv[3]; |
1515 | /* argv[0] is unused */ | 1512 | /* argv[0] is unused */ |
1516 | argv[1] = G.traps[0]; | 1513 | argv[1] = G.traps[0]; |
@@ -5474,7 +5471,8 @@ static void reset_traps_to_defaults(void) | |||
5474 | G_fatal_sig_mask = 0; | 5471 | G_fatal_sig_mask = 0; |
5475 | #endif | 5472 | #endif |
5476 | G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS; | 5473 | G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS; |
5477 | /* SIGQUIT and maybe SPECIAL_JOBSTOP_SIGS remain set in G.special_sig_mask */ | 5474 | /* SIGQUIT,SIGCHLD and maybe SPECIAL_JOBSTOP_SIGS |
5475 | * remain set in G.special_sig_mask */ | ||
5478 | 5476 | ||
5479 | if (!G.traps) | 5477 | if (!G.traps) |
5480 | return; | 5478 | return; |
@@ -5537,7 +5535,6 @@ static void re_execute_shell(char ***to_free, const char *s, | |||
5537 | for (sig = 1; sig < NSIG; sig++) { | 5535 | for (sig = 1; sig < NSIG; sig++) { |
5538 | if (G.traps[sig] && !G.traps[sig][0]) | 5536 | if (G.traps[sig] && !G.traps[sig][0]) |
5539 | empty_trap_mask |= 1LL << sig; | 5537 | empty_trap_mask |= 1LL << sig; |
5540 | ///vda: optimize | ||
5541 | } | 5538 | } |
5542 | } | 5539 | } |
5543 | 5540 | ||
@@ -7540,9 +7537,6 @@ static void install_special_sighandlers(void) | |||
7540 | { | 7537 | { |
7541 | unsigned mask; | 7538 | unsigned mask; |
7542 | 7539 | ||
7543 | if (G.special_sig_mask != 0) | ||
7544 | return; | ||
7545 | |||
7546 | /* Which signals are shell-special? */ | 7540 | /* Which signals are shell-special? */ |
7547 | mask = (1 << SIGQUIT) | (1 << SIGCHLD); | 7541 | mask = (1 << SIGQUIT) | (1 << SIGCHLD); |
7548 | if (G_interactive_fd) { | 7542 | if (G_interactive_fd) { |
@@ -7550,9 +7544,12 @@ static void install_special_sighandlers(void) | |||
7550 | if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ | 7544 | if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ |
7551 | mask |= SPECIAL_JOBSTOP_SIGS; | 7545 | mask |= SPECIAL_JOBSTOP_SIGS; |
7552 | } | 7546 | } |
7553 | G.special_sig_mask = mask; | 7547 | /* Careful, do not re-install handlers we already installed */ |
7554 | 7548 | if (G.special_sig_mask != mask) { | |
7555 | install_sighandlers(mask); | 7549 | unsigned diff = mask & ~G.special_sig_mask; |
7550 | G.special_sig_mask = mask; | ||
7551 | install_sighandlers(diff); | ||
7552 | } | ||
7556 | } | 7553 | } |
7557 | 7554 | ||
7558 | #if ENABLE_HUSH_JOB | 7555 | #if ENABLE_HUSH_JOB |
@@ -7573,17 +7570,14 @@ static void install_fatal_sighandlers(void) | |||
7573 | /* bash 3.2 seems to handle these just like 'fatal' ones */ | 7570 | /* bash 3.2 seems to handle these just like 'fatal' ones */ |
7574 | + (1 << SIGPIPE) | 7571 | + (1 << SIGPIPE) |
7575 | + (1 << SIGALRM) | 7572 | + (1 << SIGALRM) |
7576 | /* if we are interactive, SIGHUP, SIGTERM and SIGINT are masked. | 7573 | /* if we are interactive, SIGHUP, SIGTERM and SIGINT are special sigs. |
7577 | * if we aren't interactive... but in this case | 7574 | * if we aren't interactive... but in this case |
7578 | * we never want to restore pgrp on exit, and this fn is not called */ | 7575 | * we never want to restore pgrp on exit, and this fn is not called |
7576 | */ | ||
7579 | /*+ (1 << SIGHUP )*/ | 7577 | /*+ (1 << SIGHUP )*/ |
7580 | /*+ (1 << SIGTERM)*/ | 7578 | /*+ (1 << SIGTERM)*/ |
7581 | /*+ (1 << SIGINT )*/ | 7579 | /*+ (1 << SIGINT )*/ |
7582 | ; | 7580 | ; |
7583 | /* special_sig_mask'ed signals are set to record_pending_signo | ||
7584 | * no need to set handler for them. | ||
7585 | */ | ||
7586 | /*mask &= ~G.special_sig_mask; - they never overlap */ | ||
7587 | G_fatal_sig_mask = mask; | 7581 | G_fatal_sig_mask = mask; |
7588 | 7582 | ||
7589 | install_sighandlers(mask); | 7583 | install_sighandlers(mask); |
@@ -7632,6 +7626,10 @@ static int set_mode(int state, char mode, const char *o_opt) | |||
7632 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 7626 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
7633 | int hush_main(int argc, char **argv) | 7627 | int hush_main(int argc, char **argv) |
7634 | { | 7628 | { |
7629 | enum { | ||
7630 | OPT_login = (1 << 0), | ||
7631 | }; | ||
7632 | unsigned flags; | ||
7635 | int opt; | 7633 | int opt; |
7636 | unsigned builtin_argc; | 7634 | unsigned builtin_argc; |
7637 | char **e; | 7635 | char **e; |
@@ -7735,8 +7733,6 @@ int hush_main(int argc, char **argv) | |||
7735 | # endif | 7733 | # endif |
7736 | #endif | 7734 | #endif |
7737 | 7735 | ||
7738 | G.global_argc = argc; | ||
7739 | G.global_argv = argv; | ||
7740 | /* Initialize some more globals to non-zero values */ | 7736 | /* Initialize some more globals to non-zero values */ |
7741 | cmdedit_update_prompt(); | 7737 | cmdedit_update_prompt(); |
7742 | 7738 | ||
@@ -7752,14 +7748,14 @@ int hush_main(int argc, char **argv) | |||
7752 | * "sh -c <cmds>" or login shell's /etc/profile and friends. | 7748 | * "sh -c <cmds>" or login shell's /etc/profile and friends. |
7753 | * If we later decide that we are interactive, we run install_special_sighandlers() | 7749 | * If we later decide that we are interactive, we run install_special_sighandlers() |
7754 | * in order to intercept (more) signals. | 7750 | * in order to intercept (more) signals. |
7755 | //FIXME: re-running is currently most likely broken, it's a no-op. | ||
7756 | */ | 7751 | */ |
7757 | 7752 | ||
7758 | /* Parse options */ | 7753 | /* Parse options */ |
7759 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ | 7754 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ |
7755 | flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; | ||
7760 | builtin_argc = 0; | 7756 | builtin_argc = 0; |
7761 | while (1) { | 7757 | while (1) { |
7762 | opt = getopt(argc, argv, "+c:xins" | 7758 | opt = getopt(argc, argv, "+c:xinsl" |
7763 | #if !BB_MMU | 7759 | #if !BB_MMU |
7764 | "<:$:R:V:" | 7760 | "<:$:R:V:" |
7765 | # if ENABLE_HUSH_FUNCTIONS | 7761 | # if ENABLE_HUSH_FUNCTIONS |
@@ -7820,6 +7816,9 @@ int hush_main(int argc, char **argv) | |||
7820 | /* "-s" means "read from stdin", but this is how we always | 7816 | /* "-s" means "read from stdin", but this is how we always |
7821 | * operate, so simply do nothing here. */ | 7817 | * operate, so simply do nothing here. */ |
7822 | break; | 7818 | break; |
7819 | case 'l': | ||
7820 | flags |= OPT_login; | ||
7821 | break; | ||
7823 | #if !BB_MMU | 7822 | #if !BB_MMU |
7824 | case '<': /* "big heredoc" support */ | 7823 | case '<': /* "big heredoc" support */ |
7825 | full_write1_str(optarg); | 7824 | full_write1_str(optarg); |
@@ -7843,7 +7842,6 @@ int hush_main(int argc, char **argv) | |||
7843 | install_special_sighandlers(); | 7842 | install_special_sighandlers(); |
7844 | G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); | 7843 | G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); |
7845 | for (sig = 1; sig < NSIG; sig++) { | 7844 | for (sig = 1; sig < NSIG; sig++) { |
7846 | ///vda: fixme: more efficient code | ||
7847 | if (empty_trap_mask & (1LL << sig)) { | 7845 | if (empty_trap_mask & (1LL << sig)) { |
7848 | G.traps[sig] = xzalloc(1); /* == xstrdup(""); */ | 7846 | G.traps[sig] = xzalloc(1); /* == xstrdup(""); */ |
7849 | signal(sig, SIG_IGN); | 7847 | signal(sig, SIG_IGN); |
@@ -7886,13 +7884,18 @@ int hush_main(int argc, char **argv) | |||
7886 | } | 7884 | } |
7887 | } /* option parsing loop */ | 7885 | } /* option parsing loop */ |
7888 | 7886 | ||
7887 | /* Skip options. Try "hush -l": $1 should not be "-l"! */ | ||
7888 | G.global_argc = argc - (optind - 1); | ||
7889 | G.global_argv = argv + (optind - 1); | ||
7890 | G.global_argv[0] = argv[0]; | ||
7891 | |||
7889 | if (!G.root_pid) { | 7892 | if (!G.root_pid) { |
7890 | G.root_pid = getpid(); | 7893 | G.root_pid = getpid(); |
7891 | G.root_ppid = getppid(); | 7894 | G.root_ppid = getppid(); |
7892 | } | 7895 | } |
7893 | 7896 | ||
7894 | /* If we are login shell... */ | 7897 | /* If we are login shell... */ |
7895 | if (argv[0] && argv[0][0] == '-') { | 7898 | if (flags & OPT_login) { |
7896 | FILE *input; | 7899 | FILE *input; |
7897 | debug_printf("sourcing /etc/profile\n"); | 7900 | debug_printf("sourcing /etc/profile\n"); |
7898 | input = fopen_for_read("/etc/profile"); | 7901 | input = fopen_for_read("/etc/profile"); |
@@ -7911,17 +7914,17 @@ int hush_main(int argc, char **argv) | |||
7911 | */ | 7914 | */ |
7912 | } | 7915 | } |
7913 | 7916 | ||
7914 | if (argv[optind]) { | 7917 | if (G.global_argv[1]) { |
7915 | FILE *input; | 7918 | FILE *input; |
7916 | /* | 7919 | /* |
7917 | * "bash <script>" (which is never interactive (unless -i?)) | 7920 | * "bash <script>" (which is never interactive (unless -i?)) |
7918 | * sources $BASH_ENV here (without scanning $PATH). | 7921 | * sources $BASH_ENV here (without scanning $PATH). |
7919 | * If called as sh, does the same but with $ENV. | 7922 | * If called as sh, does the same but with $ENV. |
7920 | */ | 7923 | */ |
7921 | debug_printf("running script '%s'\n", argv[optind]); | 7924 | G.global_argc--; |
7922 | G.global_argv = argv + optind; | 7925 | G.global_argv++; |
7923 | G.global_argc = argc - optind; | 7926 | debug_printf("running script '%s'\n", G.global_argv[0]); |
7924 | input = xfopen_for_read(argv[optind]); | 7927 | input = xfopen_for_read(G.global_argv[0]); |
7925 | close_on_exec_on(fileno(input)); | 7928 | close_on_exec_on(fileno(input)); |
7926 | install_special_sighandlers(); | 7929 | install_special_sighandlers(); |
7927 | parse_and_run_file(input); | 7930 | parse_and_run_file(input); |
@@ -7984,7 +7987,7 @@ int hush_main(int argc, char **argv) | |||
7984 | } | 7987 | } |
7985 | } | 7988 | } |
7986 | 7989 | ||
7987 | /* Block some signals */ | 7990 | /* Install more signal handlers */ |
7988 | install_special_sighandlers(); | 7991 | install_special_sighandlers(); |
7989 | 7992 | ||
7990 | if (G_saved_tty_pgrp) { | 7993 | if (G_saved_tty_pgrp) { |