diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 48 |
1 files changed, 36 insertions, 12 deletions
diff --git a/shell/ash.c b/shell/ash.c index a1d01447a..46c4f1675 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -428,7 +428,7 @@ static void forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) | |||
428 | /* ============ Shell options */ | 428 | /* ============ Shell options */ |
429 | 429 | ||
430 | /* If you add/change options hare, update --help text too */ | 430 | /* If you add/change options hare, update --help text too */ |
431 | static const char *const optletters_optnames[] = { | 431 | static const char *const optletters_optnames[] ALIGN_PTR = { |
432 | "e" "errexit", | 432 | "e" "errexit", |
433 | "f" "noglob", | 433 | "f" "noglob", |
434 | /* bash has '-o ignoreeof', but no short synonym -I for it */ | 434 | /* bash has '-o ignoreeof', but no short synonym -I for it */ |
@@ -845,7 +845,7 @@ raise_exception(int e) | |||
845 | /* | 845 | /* |
846 | * Called when a SIGINT is received. (If the user specifies | 846 | * Called when a SIGINT is received. (If the user specifies |
847 | * that SIGINT is to be trapped or ignored using the trap builtin, then | 847 | * that SIGINT is to be trapped or ignored using the trap builtin, then |
848 | * this routine is not called.) Suppressint is nonzero when interrupts | 848 | * this routine is not called.) suppress_int is nonzero when interrupts |
849 | * are held using the INT_OFF macro. (The test for iflag is just | 849 | * are held using the INT_OFF macro. (The test for iflag is just |
850 | * defensive programming.) | 850 | * defensive programming.) |
851 | */ | 851 | */ |
@@ -882,13 +882,12 @@ raise_interrupt(void) | |||
882 | } while (0) | 882 | } while (0) |
883 | #endif | 883 | #endif |
884 | 884 | ||
885 | static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void | 885 | static IF_NOT_ASH_OPTIMIZE_FOR_SIZE(inline) void |
886 | int_on(void) | 886 | int_on(void) |
887 | { | 887 | { |
888 | barrier(); | 888 | barrier(); |
889 | if (--suppress_int == 0 && pending_int) { | 889 | if (--suppress_int == 0 && pending_int) |
890 | raise_interrupt(); | 890 | raise_interrupt(); |
891 | } | ||
892 | } | 891 | } |
893 | #if DEBUG_INTONOFF | 892 | #if DEBUG_INTONOFF |
894 | # define INT_ON do { \ | 893 | # define INT_ON do { \ |
@@ -898,7 +897,7 @@ int_on(void) | |||
898 | #else | 897 | #else |
899 | # define INT_ON int_on() | 898 | # define INT_ON int_on() |
900 | #endif | 899 | #endif |
901 | static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void | 900 | static IF_NOT_ASH_OPTIMIZE_FOR_SIZE(inline) void |
902 | force_int_on(void) | 901 | force_int_on(void) |
903 | { | 902 | { |
904 | barrier(); | 903 | barrier(); |
@@ -4143,7 +4142,9 @@ signal_handler(int signo) | |||
4143 | if (!trap[SIGCHLD]) | 4142 | if (!trap[SIGCHLD]) |
4144 | return; | 4143 | return; |
4145 | } | 4144 | } |
4146 | 4145 | #if ENABLE_FEATURE_EDITING | |
4146 | bb_got_signal = signo; /* for read_line_input: "we got a signal" */ | ||
4147 | #endif | ||
4147 | gotsig[signo - 1] = 1; | 4148 | gotsig[signo - 1] = 1; |
4148 | pending_sig = signo; | 4149 | pending_sig = signo; |
4149 | 4150 | ||
@@ -11656,33 +11657,56 @@ preadfd(void) | |||
11656 | # endif | 11657 | # endif |
11657 | reinit_unicode_for_ash(); | 11658 | reinit_unicode_for_ash(); |
11658 | again: | 11659 | again: |
11660 | /* For shell, LI_INTERRUPTIBLE is set: | ||
11661 | * read_line_input will abort on either | ||
11662 | * getting EINTR in poll(), or if it sees bb_got_signal != 0 | ||
11663 | * (IOW: if signal arrives before poll() is reached). | ||
11664 | * Interactive testcases: | ||
11665 | * (while kill -INT $$; do sleep 1; done) & | ||
11666 | * #^^^ prints ^C, prints prompt, repeats | ||
11667 | * trap 'echo I' int; (while kill -INT $$; do sleep 1; done) & | ||
11668 | * #^^^ prints ^C, prints "I", prints prompt, repeats | ||
11669 | * trap 'echo T' term; (while kill $$; do sleep 1; done) & | ||
11670 | * #^^^ prints "T", prints prompt, repeats | ||
11671 | * #(bash 5.0.17 exits after first "T", looks like a bug) | ||
11672 | */ | ||
11673 | bb_got_signal = 0; | ||
11674 | INT_OFF; /* no longjmp'ing out of read_line_input please */ | ||
11659 | nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ); | 11675 | nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ); |
11676 | if (bb_got_signal == SIGINT) | ||
11677 | write(STDOUT_FILENO, "^C\n", 3); | ||
11678 | INT_ON; /* here non-blocked SIGINT will longjmp */ | ||
11660 | if (nr == 0) { | 11679 | if (nr == 0) { |
11661 | /* ^C pressed, "convert" to SIGINT */ | 11680 | /* ^C pressed, "convert" to SIGINT */ |
11662 | # if !ENABLE_PLATFORM_MINGW32 | 11681 | # if !ENABLE_PLATFORM_MINGW32 |
11663 | write(STDOUT_FILENO, "^C", 2); | 11682 | write(STDOUT_FILENO, "^C\n", 3); |
11664 | raise(SIGINT); | 11683 | raise(SIGINT); /* here non-blocked SIGINT will longjmp */ |
11665 | /* raise(SIGINT) did not work! (e.g. if SIGINT | 11684 | /* raise(SIGINT) did not work! (e.g. if SIGINT |
11666 | * is SIG_INGed on startup, it stays SIG_IGNed) | 11685 | * is SIG_IGNed on startup, it stays SIG_IGNed) |
11667 | */ | 11686 | */ |
11668 | # else | 11687 | # else |
11669 | raise_interrupt(); | 11688 | raise_interrupt(); |
11670 | # endif | 11689 | # endif |
11671 | if (trap[SIGINT]) { | 11690 | if (trap[SIGINT]) { |
11691 | empty_line_input: | ||
11672 | buf[0] = '\n'; | 11692 | buf[0] = '\n'; |
11673 | buf[1] = '\0'; | 11693 | buf[1] = '\0'; |
11674 | return 1; | 11694 | return 1; |
11675 | } | 11695 | } |
11676 | exitstatus = 128 + SIGINT; | 11696 | exitstatus = 128 + SIGINT; |
11677 | /* bash behavior on ^C + ignored SIGINT: */ | 11697 | /* bash behavior on ^C + ignored SIGINT: */ |
11678 | write(STDOUT_FILENO, "\n", 1); | ||
11679 | goto again; | 11698 | goto again; |
11680 | } | 11699 | } |
11681 | if (nr < 0) { | 11700 | if (nr < 0) { |
11682 | if (errno == 0) { | 11701 | if (errno == 0) { |
11683 | /* Ctrl+D pressed */ | 11702 | /* ^D pressed */ |
11684 | nr = 0; | 11703 | nr = 0; |
11685 | } | 11704 | } |
11705 | else if (errno == EINTR) { /* got signal? */ | ||
11706 | if (bb_got_signal != SIGINT) | ||
11707 | write(STDOUT_FILENO, "\n", 1); | ||
11708 | goto empty_line_input; | ||
11709 | } | ||
11686 | # if ENABLE_ASH_IDLE_TIMEOUT | 11710 | # if ENABLE_ASH_IDLE_TIMEOUT |
11687 | else if (errno == EAGAIN && timeout > 0) { | 11711 | else if (errno == EAGAIN && timeout > 0) { |
11688 | puts("\007timed out waiting for input: auto-logout"); | 11712 | puts("\007timed out waiting for input: auto-logout"); |