diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2023-01-26 12:56:33 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2023-01-26 12:56:33 +0100 |
| commit | 93e0898c663a533082b5f3c2e7dcce93ec47076d (patch) | |
| tree | d44936a40fcac122b94d4b235195e6832446b27b | |
| parent | c2739e11dee92770839ac9b2dbf020459baec7b9 (diff) | |
| download | busybox-w32-93e0898c663a533082b5f3c2e7dcce93ec47076d.tar.gz busybox-w32-93e0898c663a533082b5f3c2e7dcce93ec47076d.tar.bz2 busybox-w32-93e0898c663a533082b5f3c2e7dcce93ec47076d.zip | |
shell: fix SIGWINCH and SIGCHLD (in hush) interrupting line input, closes 15256
function old new delta
record_pending_signo 32 63 +31
lineedit_read_key 231 224 -7
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 31/-7) Total: 24 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | libbb/lineedit.c | 17 | ||||
| -rw-r--r-- | shell/ash.c | 3 | ||||
| -rw-r--r-- | shell/hush.c | 10 |
3 files changed, 20 insertions, 10 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index d6b2e76ff..b942f540a 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
| @@ -2180,7 +2180,8 @@ static int lineedit_read_key(char *read_key_buffer, int timeout) | |||
| 2180 | * "\xff\n",pause,"ls\n" invalid and thus won't lose "ls". | 2180 | * "\xff\n",pause,"ls\n" invalid and thus won't lose "ls". |
| 2181 | * | 2181 | * |
| 2182 | * If LI_INTERRUPTIBLE, return -1 if got EINTR in poll() | 2182 | * If LI_INTERRUPTIBLE, return -1 if got EINTR in poll() |
| 2183 | * inside read_key, or if bb_got_signal != 0 (IOW: if signal | 2183 | * inside read_key and bb_got_signal became != 0, |
| 2184 | * or if bb_got_signal != 0 (IOW: if signal | ||
| 2184 | * arrived before poll() is reached). | 2185 | * arrived before poll() is reached). |
| 2185 | * | 2186 | * |
| 2186 | * Note: read_key sets errno to 0 on success. | 2187 | * Note: read_key sets errno to 0 on success. |
| @@ -2197,14 +2198,16 @@ static int lineedit_read_key(char *read_key_buffer, int timeout) | |||
| 2197 | IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 0;) | 2198 | IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 0;) |
| 2198 | if (errno != EINTR) | 2199 | if (errno != EINTR) |
| 2199 | break; | 2200 | break; |
| 2201 | /* It was EINTR. Repeat read_key() unless... */ | ||
| 2200 | if (state->flags & LI_INTERRUPTIBLE) { | 2202 | if (state->flags & LI_INTERRUPTIBLE) { |
| 2201 | /* LI_INTERRUPTIBLE bails out on EINTR, | 2203 | /* LI_INTERRUPTIBLE bails out on EINTR |
| 2202 | * but nothing really guarantees that bb_got_signal | 2204 | * if bb_got_signal became nonzero. |
| 2203 | * is nonzero. Follow the least surprise principle: | 2205 | * (It may stay zero: for example, our SIGWINCH |
| 2206 | * handler does not set it. This is used for signals | ||
| 2207 | * which should not interrupt line editing). | ||
| 2204 | */ | 2208 | */ |
| 2205 | if (bb_got_signal == 0) | 2209 | if (bb_got_signal != 0) |
| 2206 | bb_got_signal = 255; | 2210 | goto ret; /* will return -1 */ |
| 2207 | goto ret; | ||
| 2208 | } | 2211 | } |
| 2209 | } | 2212 | } |
| 2210 | 2213 | ||
diff --git a/shell/ash.c b/shell/ash.c index 18ccc1329..5f8c8ea19 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
| @@ -10821,7 +10821,8 @@ preadfd(void) | |||
| 10821 | again: | 10821 | again: |
| 10822 | /* For shell, LI_INTERRUPTIBLE is set: | 10822 | /* For shell, LI_INTERRUPTIBLE is set: |
| 10823 | * read_line_input will abort on either | 10823 | * read_line_input will abort on either |
| 10824 | * getting EINTR in poll(), or if it sees bb_got_signal != 0 | 10824 | * getting EINTR in poll() and bb_got_signal became != 0, |
| 10825 | * or if it sees bb_got_signal != 0 | ||
| 10825 | * (IOW: if signal arrives before poll() is reached). | 10826 | * (IOW: if signal arrives before poll() is reached). |
| 10826 | * Interactive testcases: | 10827 | * Interactive testcases: |
| 10827 | * (while kill -INT $$; do sleep 1; done) & | 10828 | * (while kill -INT $$; do sleep 1; done) & |
diff --git a/shell/hush.c b/shell/hush.c index d111f0cc5..f064b8fd2 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -1946,7 +1946,12 @@ static void record_pending_signo(int sig) | |||
| 1946 | { | 1946 | { |
| 1947 | sigaddset(&G.pending_set, sig); | 1947 | sigaddset(&G.pending_set, sig); |
| 1948 | #if ENABLE_FEATURE_EDITING | 1948 | #if ENABLE_FEATURE_EDITING |
| 1949 | bb_got_signal = sig; /* for read_line_input: "we got a signal" */ | 1949 | if (sig != SIGCHLD |
| 1950 | || (G_traps && G_traps[SIGCHLD] && G_traps[SIGCHLD][0]) | ||
| 1951 | /* ^^^ if SIGCHLD, interrupt line reading only if it has a trap */ | ||
| 1952 | ) { | ||
| 1953 | bb_got_signal = sig; /* for read_line_input: "we got a signal" */ | ||
| 1954 | } | ||
| 1950 | #endif | 1955 | #endif |
| 1951 | #if ENABLE_HUSH_FAST | 1956 | #if ENABLE_HUSH_FAST |
| 1952 | if (sig == SIGCHLD) { | 1957 | if (sig == SIGCHLD) { |
| @@ -2669,7 +2674,8 @@ static int get_user_input(struct in_str *i) | |||
| 2669 | } else { | 2674 | } else { |
| 2670 | /* For shell, LI_INTERRUPTIBLE is set: | 2675 | /* For shell, LI_INTERRUPTIBLE is set: |
| 2671 | * read_line_input will abort on either | 2676 | * read_line_input will abort on either |
| 2672 | * getting EINTR in poll(), or if it sees bb_got_signal != 0 | 2677 | * getting EINTR in poll() and bb_got_signal became != 0, |
| 2678 | * or if it sees bb_got_signal != 0 | ||
| 2673 | * (IOW: if signal arrives before poll() is reached). | 2679 | * (IOW: if signal arrives before poll() is reached). |
| 2674 | * Interactive testcases: | 2680 | * Interactive testcases: |
| 2675 | * (while kill -INT $$; do sleep 1; done) & | 2681 | * (while kill -INT $$; do sleep 1; done) & |
