diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2022-01-17 03:02:40 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2022-01-17 11:46:23 +0100 |
commit | 12566e7f9b5e5c5d445bc4d36991d134b431dc6c (patch) | |
tree | 2571356a77f7d421da368e9b31dad182e83b2408 | |
parent | a277506a64404e6c4472ff89c944c4f353db1c33 (diff) | |
download | busybox-w32-12566e7f9b5e5c5d445bc4d36991d134b431dc6c.tar.gz busybox-w32-12566e7f9b5e5c5d445bc4d36991d134b431dc6c.tar.bz2 busybox-w32-12566e7f9b5e5c5d445bc4d36991d134b431dc6c.zip |
ash,hush: fix handling of SIGINT while waiting for interactive input
function old new delta
lineedit_read_key 160 237 +77
__pgetc 522 589 +67
fgetc_interactive 244 309 +65
safe_read_key - 39 +39
read_key 588 607 +19
record_pending_signo 23 32 +9
signal_handler 75 81 +6
.rodata 104312 104309 -3
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 6/1 up/down: 282/-3) Total: 279 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | editors/vi.c | 4 | ||||
-rw-r--r-- | include/libbb.h | 5 | ||||
-rw-r--r-- | libbb/lineedit.c | 24 | ||||
-rw-r--r-- | libbb/read_key.c | 16 | ||||
-rw-r--r-- | miscutils/hexedit.c | 2 | ||||
-rw-r--r-- | miscutils/less.c | 4 | ||||
-rw-r--r-- | procps/top.c | 2 | ||||
-rw-r--r-- | shell/ash.c | 39 | ||||
-rw-r--r-- | shell/hush.c | 67 |
9 files changed, 122 insertions, 41 deletions
diff --git a/editors/vi.c b/editors/vi.c index 3dbe5b471..d37cd48a3 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -1122,7 +1122,7 @@ static int readit(void) // read (maybe cursor) key from stdin | |||
1122 | // on nonblocking stdin. | 1122 | // on nonblocking stdin. |
1123 | // Note: read_key sets errno to 0 on success. | 1123 | // Note: read_key sets errno to 0 on success. |
1124 | again: | 1124 | again: |
1125 | c = read_key(STDIN_FILENO, readbuffer, /*timeout:*/ -1); | 1125 | c = safe_read_key(STDIN_FILENO, readbuffer, /*timeout:*/ -1); |
1126 | if (c == -1) { // EOF/error | 1126 | if (c == -1) { // EOF/error |
1127 | if (errno == EAGAIN) // paranoia | 1127 | if (errno == EAGAIN) // paranoia |
1128 | goto again; | 1128 | goto again; |
@@ -4770,7 +4770,7 @@ static void edit_file(char *fn) | |||
4770 | uint64_t k; | 4770 | uint64_t k; |
4771 | write1(ESC"[999;999H" ESC"[6n"); | 4771 | write1(ESC"[999;999H" ESC"[6n"); |
4772 | fflush_all(); | 4772 | fflush_all(); |
4773 | k = read_key(STDIN_FILENO, readbuffer, /*timeout_ms:*/ 100); | 4773 | k = safe_read_key(STDIN_FILENO, readbuffer, /*timeout_ms:*/ 100); |
4774 | if ((int32_t)k == KEYCODE_CURSOR_POS) { | 4774 | if ((int32_t)k == KEYCODE_CURSOR_POS) { |
4775 | uint32_t rc = (k >> 32); | 4775 | uint32_t rc = (k >> 32); |
4776 | columns = (rc & 0x7fff); | 4776 | columns = (rc & 0x7fff); |
diff --git a/include/libbb.h b/include/libbb.h index 91b456915..b45ce91c5 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1908,6 +1908,8 @@ enum { | |||
1908 | * >=0: poll() for TIMEOUT milliseconds, return -1/EAGAIN on timeout | 1908 | * >=0: poll() for TIMEOUT milliseconds, return -1/EAGAIN on timeout |
1909 | */ | 1909 | */ |
1910 | int64_t read_key(int fd, char *buffer, int timeout) FAST_FUNC; | 1910 | int64_t read_key(int fd, char *buffer, int timeout) FAST_FUNC; |
1911 | /* This version loops on EINTR: */ | ||
1912 | int64_t safe_read_key(int fd, char *buffer, int timeout) FAST_FUNC; | ||
1911 | void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; | 1913 | void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; |
1912 | 1914 | ||
1913 | 1915 | ||
@@ -1961,7 +1963,8 @@ enum { | |||
1961 | USERNAME_COMPLETION = 4 * ENABLE_FEATURE_USERNAME_COMPLETION, | 1963 | USERNAME_COMPLETION = 4 * ENABLE_FEATURE_USERNAME_COMPLETION, |
1962 | VI_MODE = 8 * ENABLE_FEATURE_EDITING_VI, | 1964 | VI_MODE = 8 * ENABLE_FEATURE_EDITING_VI, |
1963 | WITH_PATH_LOOKUP = 0x10, | 1965 | WITH_PATH_LOOKUP = 0x10, |
1964 | FOR_SHELL = DO_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION, | 1966 | LI_INTERRUPTIBLE = 0x20, |
1967 | FOR_SHELL = DO_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION | LI_INTERRUPTIBLE, | ||
1965 | }; | 1968 | }; |
1966 | line_input_t *new_line_input_t(int flags) FAST_FUNC; | 1969 | line_input_t *new_line_input_t(int flags) FAST_FUNC; |
1967 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 1970 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index e14c78707..f76afd37d 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -2161,12 +2161,30 @@ static int lineedit_read_key(char *read_key_buffer, int timeout) | |||
2161 | * insist on full MB_CUR_MAX buffer to declare input like | 2161 | * insist on full MB_CUR_MAX buffer to declare input like |
2162 | * "\xff\n",pause,"ls\n" invalid and thus won't lose "ls". | 2162 | * "\xff\n",pause,"ls\n" invalid and thus won't lose "ls". |
2163 | * | 2163 | * |
2164 | * If LI_INTERRUPTIBLE, return -1 if got EINTR in poll() | ||
2165 | * inside read_key, or if bb_got_signal != 0 (IOW: if signal | ||
2166 | * arrived before poll() is reached). | ||
2167 | * | ||
2164 | * Note: read_key sets errno to 0 on success. | 2168 | * Note: read_key sets errno to 0 on success. |
2165 | */ | 2169 | */ |
2166 | IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;) | 2170 | do { |
2167 | ic = read_key(STDIN_FILENO, read_key_buffer, timeout); | 2171 | if ((state->flags & LI_INTERRUPTIBLE) && bb_got_signal) { |
2168 | IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 0;) | 2172 | errno = EINTR; |
2173 | return -1; | ||
2174 | } | ||
2175 | //FIXME: still races here with signals, but small window to poll() inside read_key | ||
2176 | IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;) | ||
2177 | ic = read_key(STDIN_FILENO, read_key_buffer, timeout); | ||
2178 | IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 0;) | ||
2179 | } while (!(state->flags & LI_INTERRUPTIBLE) && errno == EINTR); | ||
2180 | |||
2169 | if (errno) { | 2181 | if (errno) { |
2182 | /* LI_INTERRUPTIBLE can bail out with EINTR here, | ||
2183 | * but nothing really guarantees that bb_got_signal | ||
2184 | * is nonzero. Follow the least surprise principle: | ||
2185 | */ | ||
2186 | if (errno == EINTR && bb_got_signal == 0) | ||
2187 | bb_got_signal = 255; /* something nonzero */ | ||
2170 | #if ENABLE_UNICODE_SUPPORT | 2188 | #if ENABLE_UNICODE_SUPPORT |
2171 | if (errno == EAGAIN && unicode_idx != 0) | 2189 | if (errno == EAGAIN && unicode_idx != 0) |
2172 | goto pushback; | 2190 | goto pushback; |
diff --git a/libbb/read_key.c b/libbb/read_key.c index 03b7da656..829ae215c 100644 --- a/libbb/read_key.c +++ b/libbb/read_key.c | |||
@@ -126,7 +126,10 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
126 | * if fd can be in non-blocking mode. | 126 | * if fd can be in non-blocking mode. |
127 | */ | 127 | */ |
128 | if (timeout >= -1) { | 128 | if (timeout >= -1) { |
129 | if (safe_poll(&pfd, 1, timeout) == 0) { | 129 | n = poll(&pfd, 1, timeout); |
130 | if (n < 0 && errno == EINTR) | ||
131 | return n; | ||
132 | if (n == 0) { | ||
130 | /* Timed out */ | 133 | /* Timed out */ |
131 | errno = EAGAIN; | 134 | errno = EAGAIN; |
132 | return -1; | 135 | return -1; |
@@ -138,7 +141,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
138 | * When we were reading 3 bytes here, we were eating | 141 | * When we were reading 3 bytes here, we were eating |
139 | * "li" too, and cat was getting wrong input. | 142 | * "li" too, and cat was getting wrong input. |
140 | */ | 143 | */ |
141 | n = safe_read(fd, buffer, 1); | 144 | n = read(fd, buffer, 1); |
142 | if (n <= 0) | 145 | if (n <= 0) |
143 | return -1; | 146 | return -1; |
144 | } | 147 | } |
@@ -284,6 +287,15 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
284 | goto start_over; | 287 | goto start_over; |
285 | } | 288 | } |
286 | 289 | ||
290 | int64_t FAST_FUNC safe_read_key(int fd, char *buffer, int timeout) | ||
291 | { | ||
292 | int64_t r; | ||
293 | do { | ||
294 | r = read_key(fd, buffer, timeout); | ||
295 | } while (errno == EINTR); | ||
296 | return r; | ||
297 | } | ||
298 | |||
287 | void FAST_FUNC read_key_ungets(char *buffer, const char *str, unsigned len) | 299 | void FAST_FUNC read_key_ungets(char *buffer, const char *str, unsigned len) |
288 | { | 300 | { |
289 | unsigned cur_len = (unsigned char)buffer[0]; | 301 | unsigned cur_len = (unsigned char)buffer[0]; |
diff --git a/miscutils/hexedit.c b/miscutils/hexedit.c index f8ff9b62b..15ad78377 100644 --- a/miscutils/hexedit.c +++ b/miscutils/hexedit.c | |||
@@ -292,7 +292,7 @@ int hexedit_main(int argc UNUSED_PARAM, char **argv) | |||
292 | fflush_all(); | 292 | fflush_all(); |
293 | G.in_read_key = 1; | 293 | G.in_read_key = 1; |
294 | if (!bb_got_signal) | 294 | if (!bb_got_signal) |
295 | key = read_key(STDIN_FILENO, G.read_key_buffer, -1); | 295 | key = safe_read_key(STDIN_FILENO, G.read_key_buffer, -1); |
296 | G.in_read_key = 0; | 296 | G.in_read_key = 0; |
297 | if (bb_got_signal) | 297 | if (bb_got_signal) |
298 | key = CTRL('X'); | 298 | key = CTRL('X'); |
diff --git a/miscutils/less.c b/miscutils/less.c index 82c4b21f0..8a0525cb7 100644 --- a/miscutils/less.c +++ b/miscutils/less.c | |||
@@ -1137,9 +1137,9 @@ static int64_t getch_nowait(void) | |||
1137 | #endif | 1137 | #endif |
1138 | } | 1138 | } |
1139 | 1139 | ||
1140 | /* We have kbd_fd in O_NONBLOCK mode, read inside read_key() | 1140 | /* We have kbd_fd in O_NONBLOCK mode, read inside safe_read_key() |
1141 | * would not block even if there is no input available */ | 1141 | * would not block even if there is no input available */ |
1142 | key64 = read_key(kbd_fd, kbd_input, /*timeout off:*/ -2); | 1142 | key64 = safe_read_key(kbd_fd, kbd_input, /*timeout off:*/ -2); |
1143 | if ((int)key64 == -1) { | 1143 | if ((int)key64 == -1) { |
1144 | if (errno == EAGAIN) { | 1144 | if (errno == EAGAIN) { |
1145 | /* No keyboard input available. Since poll() did return, | 1145 | /* No keyboard input available. Since poll() did return, |
diff --git a/procps/top.c b/procps/top.c index 4cd545c69..804d6f258 100644 --- a/procps/top.c +++ b/procps/top.c | |||
@@ -913,7 +913,7 @@ static unsigned handle_input(unsigned scan_mask, duration_t interval) | |||
913 | while (1) { | 913 | while (1) { |
914 | int32_t c; | 914 | int32_t c; |
915 | 915 | ||
916 | c = read_key(STDIN_FILENO, G.kbd_input, interval * 1000); | 916 | c = safe_read_key(STDIN_FILENO, G.kbd_input, interval * 1000); |
917 | if (c == -1 && errno != EAGAIN) { | 917 | if (c == -1 && errno != EAGAIN) { |
918 | /* error/EOF */ | 918 | /* error/EOF */ |
919 | option_mask32 |= OPT_EOF; | 919 | option_mask32 |= OPT_EOF; |
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"); |
diff --git a/shell/hush.c b/shell/hush.c index 7d0dc67e4..6dc2ecaac 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -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++; |