aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c39
1 files changed, 30 insertions, 9 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 086773dd7..55df54bd0 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -3679,7 +3679,9 @@ signal_handler(int signo)
3679 if (!trap[SIGCHLD]) 3679 if (!trap[SIGCHLD])
3680 return; 3680 return;
3681 } 3681 }
3682 3682#if ENABLE_FEATURE_EDITING
3683 bb_got_signal = signo; /* for read_line_input: "we got a signal" */
3684#endif
3683 gotsig[signo - 1] = 1; 3685 gotsig[signo - 1] = 1;
3684 pending_sig = signo; 3686 pending_sig = signo;
3685 3687
@@ -10784,33 +10786,52 @@ preadfd(void)
10784# endif 10786# endif
10785 reinit_unicode_for_ash(); 10787 reinit_unicode_for_ash();
10786 again: 10788 again:
10787//BUG: not in INT_OFF/INT_ON section - SIGINT et al would longjmp out of read_line_input()! 10789 /* For shell, LI_INTERRUPTIBLE is set:
10788//This would cause a memory leak in interactive shell 10790 * read_line_input will abort on either
10789//(repeated internal allocations in read_line_input): 10791 * getting EINTR in poll(), or if it sees bb_got_signal != 0
10790// (while kill -INT $$; do :; done) & 10792 * (IOW: if signal arrives before poll() is reached).
10793 * Interactive testcases:
10794 * (while kill -INT $$; do sleep 1; done) &
10795 * #^^^ prints ^C, prints prompt, repeats
10796 * trap 'echo I' int; (while kill -INT $$; do sleep 1; done) &
10797 * #^^^ prints ^C, prints "I", prints prompt, repeats
10798 * trap 'echo T' term; (while kill $$; do sleep 1; done) &
10799 * #^^^ prints "T", prints prompt, repeats
10800 * #(bash 5.0.17 exits after first "T", looks like a bug)
10801 */
10802 bb_got_signal = 0;
10803 INT_OFF; /* no longjmp'ing out of read_line_input please */
10791 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ); 10804 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
10805 if (bb_got_signal == SIGINT)
10806 write(STDOUT_FILENO, "^C\n", 3);
10807 INT_ON; /* here non-blocked SIGINT will longjmp */
10792 if (nr == 0) { 10808 if (nr == 0) {
10793 /* ^C pressed, "convert" to SIGINT */ 10809 /* ^C pressed, "convert" to SIGINT */
10794 write(STDOUT_FILENO, "^C", 2); 10810 write(STDOUT_FILENO, "^C\n", 3);
10795 raise(SIGINT); 10811 raise(SIGINT); /* here non-blocked SIGINT will longjmp */
10796 /* raise(SIGINT) did not work! (e.g. if SIGINT 10812 /* raise(SIGINT) did not work! (e.g. if SIGINT
10797 * is SIG_IGNed on startup, it stays SIG_IGNed) 10813 * is SIG_IGNed on startup, it stays SIG_IGNed)
10798 */ 10814 */
10799 if (trap[SIGINT]) { 10815 if (trap[SIGINT]) {
10816 empty_line_input:
10800 buf[0] = '\n'; 10817 buf[0] = '\n';
10801 buf[1] = '\0'; 10818 buf[1] = '\0';
10802 return 1; 10819 return 1;
10803 } 10820 }
10804 exitstatus = 128 + SIGINT; 10821 exitstatus = 128 + SIGINT;
10805 /* bash behavior on ^C + ignored SIGINT: */ 10822 /* bash behavior on ^C + ignored SIGINT: */
10806 write(STDOUT_FILENO, "\n", 1);
10807 goto again; 10823 goto again;
10808 } 10824 }
10809 if (nr < 0) { 10825 if (nr < 0) {
10810 if (errno == 0) { 10826 if (errno == 0) {
10811 /* Ctrl+D pressed */ 10827 /* ^D pressed */
10812 nr = 0; 10828 nr = 0;
10813 } 10829 }
10830 else if (errno == EINTR) { /* got signal? */
10831 if (bb_got_signal != SIGINT)
10832 write(STDOUT_FILENO, "\n", 1);
10833 goto empty_line_input;
10834 }
10814# if ENABLE_ASH_IDLE_TIMEOUT 10835# if ENABLE_ASH_IDLE_TIMEOUT
10815 else if (errno == EAGAIN && timeout > 0) { 10836 else if (errno == EAGAIN && timeout > 0) {
10816 puts("\007timed out waiting for input: auto-logout"); 10837 puts("\007timed out waiting for input: auto-logout");