diff options
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 79 |
1 files changed, 53 insertions, 26 deletions
diff --git a/shell/hush.c b/shell/hush.c index 982fc356a..ae81f0da5 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -564,7 +564,7 @@ enum { | |||
564 | #define NULL_O_STRING { NULL } | 564 | #define NULL_O_STRING { NULL } |
565 | 565 | ||
566 | #ifndef debug_printf_parse | 566 | #ifndef debug_printf_parse |
567 | static const char *const assignment_flag[] = { | 567 | static const char *const assignment_flag[] ALIGN_PTR = { |
568 | "MAYBE_ASSIGNMENT", | 568 | "MAYBE_ASSIGNMENT", |
569 | "DEFINITELY_ASSIGNMENT", | 569 | "DEFINITELY_ASSIGNMENT", |
570 | "NOT_ASSIGNMENT", | 570 | "NOT_ASSIGNMENT", |
@@ -918,6 +918,7 @@ struct globals { | |||
918 | #if ENABLE_HUSH_INTERACTIVE | 918 | #if ENABLE_HUSH_INTERACTIVE |
919 | smallint promptmode; /* 0: PS1, 1: PS2 */ | 919 | smallint promptmode; /* 0: PS1, 1: PS2 */ |
920 | #endif | 920 | #endif |
921 | /* set by signal handler if SIGINT is received _and_ its trap is not set */ | ||
921 | smallint flag_SIGINT; | 922 | smallint flag_SIGINT; |
922 | #if ENABLE_HUSH_LOOPS | 923 | #if ENABLE_HUSH_LOOPS |
923 | smallint flag_break_continue; | 924 | smallint flag_break_continue; |
@@ -1944,6 +1945,9 @@ enum { | |||
1944 | static void record_pending_signo(int sig) | 1945 | static void record_pending_signo(int sig) |
1945 | { | 1946 | { |
1946 | sigaddset(&G.pending_set, sig); | 1947 | sigaddset(&G.pending_set, sig); |
1948 | #if ENABLE_FEATURE_EDITING | ||
1949 | bb_got_signal = sig; /* for read_line_input: "we got a signal" */ | ||
1950 | #endif | ||
1947 | #if ENABLE_HUSH_FAST | 1951 | #if ENABLE_HUSH_FAST |
1948 | if (sig == SIGCHLD) { | 1952 | if (sig == SIGCHLD) { |
1949 | G.count_SIGCHLD++; | 1953 | G.count_SIGCHLD++; |
@@ -2652,30 +2656,53 @@ static int get_user_input(struct in_str *i) | |||
2652 | for (;;) { | 2656 | for (;;) { |
2653 | reinit_unicode_for_hush(); | 2657 | reinit_unicode_for_hush(); |
2654 | G.flag_SIGINT = 0; | 2658 | G.flag_SIGINT = 0; |
2655 | /* buglet: SIGINT will not make new prompt to appear _at once_, | 2659 | |
2656 | * only after <Enter>. (^C works immediately) */ | 2660 | bb_got_signal = 0; |
2657 | r = read_line_input(G.line_input_state, prompt_str, | 2661 | if (!sigisemptyset(&G.pending_set)) { |
2662 | /* Whoops, already got a signal, do not call read_line_input */ | ||
2663 | bb_got_signal = r = -1; | ||
2664 | } else { | ||
2665 | /* For shell, LI_INTERRUPTIBLE is set: | ||
2666 | * read_line_input will abort on either | ||
2667 | * getting EINTR in poll(), or if it sees bb_got_signal != 0 | ||
2668 | * (IOW: if signal arrives before poll() is reached). | ||
2669 | * Interactive testcases: | ||
2670 | * (while kill -INT $$; do sleep 1; done) & | ||
2671 | * #^^^ prints ^C, prints prompt, repeats | ||
2672 | * trap 'echo I' int; (while kill -INT $$; do sleep 1; done) & | ||
2673 | * #^^^ prints ^C, prints "I", prints prompt, repeats | ||
2674 | * trap 'echo T' term; (while kill $$; do sleep 1; done) & | ||
2675 | * #^^^ prints "T", prints prompt, repeats | ||
2676 | * #(bash 5.0.17 exits after first "T", looks like a bug) | ||
2677 | */ | ||
2678 | r = read_line_input(G.line_input_state, prompt_str, | ||
2658 | G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1 | 2679 | G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1 |
2659 | ); | 2680 | ); |
2660 | /* read_line_input intercepts ^C, "convert" it to SIGINT */ | 2681 | /* read_line_input intercepts ^C, "convert" it to SIGINT */ |
2661 | if (r == 0) { | 2682 | if (r == 0) |
2662 | raise(SIGINT); | 2683 | raise(SIGINT); |
2684 | } | ||
2685 | /* bash prints ^C (before running a trap, if any) | ||
2686 | * both on keyboard ^C and on real SIGINT (non-kbd generated). | ||
2687 | */ | ||
2688 | if (sigismember(&G.pending_set, SIGINT)) { | ||
2689 | write(STDOUT_FILENO, "^C\n", 3); | ||
2690 | G.last_exitcode = 128 | SIGINT; | ||
2663 | } | 2691 | } |
2664 | check_and_run_traps(); | 2692 | check_and_run_traps(); |
2665 | if (r != 0 && !G.flag_SIGINT) | 2693 | if (r == 0) /* keyboard ^C? */ |
2694 | continue; /* go back, read another input line */ | ||
2695 | if (r > 0) /* normal input? (no ^C, no ^D, no signals) */ | ||
2666 | break; | 2696 | break; |
2667 | /* ^C or SIGINT: repeat */ | 2697 | if (!bb_got_signal) { |
2668 | /* bash prints ^C even on real SIGINT (non-kbd generated) */ | 2698 | /* r < 0: ^D/EOF/error detected (but not signal) */ |
2669 | write(STDOUT_FILENO, "^C\n", 3); | 2699 | /* ^D on interactive input goes to next line before exiting: */ |
2670 | G.last_exitcode = 128 | SIGINT; | 2700 | write(STDOUT_FILENO, "\n", 1); |
2671 | } | 2701 | i->p = NULL; |
2672 | if (r < 0) { | 2702 | i->peek_buf[0] = r = EOF; |
2673 | /* EOF/error detected */ | 2703 | return r; |
2674 | /* ^D on interactive input goes to next line before exiting: */ | 2704 | } |
2675 | write(STDOUT_FILENO, "\n", 1); | 2705 | /* it was a signal: go back, read another input line */ |
2676 | i->p = NULL; | ||
2677 | i->peek_buf[0] = r = EOF; | ||
2678 | return r; | ||
2679 | } | 2706 | } |
2680 | i->p = G.user_input_buf; | 2707 | i->p = G.user_input_buf; |
2681 | return (unsigned char)*i->p++; | 2708 | return (unsigned char)*i->p++; |
@@ -3655,7 +3682,7 @@ static void free_pipe_list(struct pipe *pi) | |||
3655 | #ifndef debug_print_tree | 3682 | #ifndef debug_print_tree |
3656 | static void debug_print_tree(struct pipe *pi, int lvl) | 3683 | static void debug_print_tree(struct pipe *pi, int lvl) |
3657 | { | 3684 | { |
3658 | static const char *const PIPE[] = { | 3685 | static const char *const PIPE[] ALIGN_PTR = { |
3659 | [PIPE_SEQ] = "SEQ", | 3686 | [PIPE_SEQ] = "SEQ", |
3660 | [PIPE_AND] = "AND", | 3687 | [PIPE_AND] = "AND", |
3661 | [PIPE_OR ] = "OR" , | 3688 | [PIPE_OR ] = "OR" , |
@@ -3690,7 +3717,7 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
3690 | [RES_XXXX ] = "XXXX" , | 3717 | [RES_XXXX ] = "XXXX" , |
3691 | [RES_SNTX ] = "SNTX" , | 3718 | [RES_SNTX ] = "SNTX" , |
3692 | }; | 3719 | }; |
3693 | static const char *const CMDTYPE[] = { | 3720 | static const char *const CMDTYPE[] ALIGN_PTR = { |
3694 | "{}", | 3721 | "{}", |
3695 | "()", | 3722 | "()", |
3696 | "[noglob]", | 3723 | "[noglob]", |
@@ -7632,7 +7659,7 @@ static int generate_stream_from_string(const char *s, pid_t *pid_p) | |||
7632 | if (is_prefixed_with(s, "trap") | 7659 | if (is_prefixed_with(s, "trap") |
7633 | && skip_whitespace(s + 4)[0] == '\0' | 7660 | && skip_whitespace(s + 4)[0] == '\0' |
7634 | ) { | 7661 | ) { |
7635 | static const char *const argv[] = { NULL, NULL }; | 7662 | static const char *const argv[] ALIGN_PTR = { NULL, NULL }; |
7636 | builtin_trap((char**)argv); | 7663 | builtin_trap((char**)argv); |
7637 | fflush_all(); /* important */ | 7664 | fflush_all(); /* important */ |
7638 | _exit(0); | 7665 | _exit(0); |
@@ -9799,7 +9826,7 @@ static int run_list(struct pipe *pi) | |||
9799 | static const char encoded_dollar_at[] ALIGN1 = { | 9826 | static const char encoded_dollar_at[] ALIGN1 = { |
9800 | SPECIAL_VAR_SYMBOL, '@' | 0x80, SPECIAL_VAR_SYMBOL, '\0' | 9827 | SPECIAL_VAR_SYMBOL, '@' | 0x80, SPECIAL_VAR_SYMBOL, '\0' |
9801 | }; /* encoded representation of "$@" */ | 9828 | }; /* encoded representation of "$@" */ |
9802 | static const char *const encoded_dollar_at_argv[] = { | 9829 | static const char *const encoded_dollar_at_argv[] ALIGN_PTR = { |
9803 | encoded_dollar_at, NULL | 9830 | encoded_dollar_at, NULL |
9804 | }; /* argv list with one element: "$@" */ | 9831 | }; /* argv list with one element: "$@" */ |
9805 | char **vals; | 9832 | char **vals; |
@@ -10361,7 +10388,7 @@ int hush_main(int argc, char **argv) | |||
10361 | //it ignores TERM: | 10388 | //it ignores TERM: |
10362 | // bash -i -c 'kill $$; echo ALIVE' | 10389 | // bash -i -c 'kill $$; echo ALIVE' |
10363 | // ALIVE | 10390 | // ALIVE |
10364 | //it resets SIG_INGed HUP to SIG_DFL: | 10391 | //it resets SIG_IGNed HUP to SIG_DFL: |
10365 | // trap '' hup; bash -i -c 'kill -hup $$; echo ALIVE' | 10392 | // trap '' hup; bash -i -c 'kill -hup $$; echo ALIVE' |
10366 | // Hangup [the message is not printed by bash, it's the shell which started it] | 10393 | // Hangup [the message is not printed by bash, it's the shell which started it] |
10367 | //is talkative about jobs and exiting: | 10394 | //is talkative about jobs and exiting: |