summaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorDenys Vlasenko2022-01-17 03:02:40 +0100
committerDenys Vlasenko2022-01-17 11:46:23 +0100
commit12566e7f9b5e5c5d445bc4d36991d134b431dc6c (patch)
tree2571356a77f7d421da368e9b31dad182e83b2408 /libbb
parenta277506a64404e6c4472ff89c944c4f353db1c33 (diff)
downloadbusybox-12566e7f9b5e5c5d445bc4d36991d134b431dc6c.zip
busybox-12566e7f9b5e5c5d445bc4d36991d134b431dc6c.tar.gz
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>
Diffstat (limited to 'libbb')
-rw-r--r--libbb/lineedit.c24
-rw-r--r--libbb/read_key.c16
2 files changed, 35 insertions, 5 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index e14c787..f76afd3 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -2161,12 +2161,30 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
* insist on full MB_CUR_MAX buffer to declare input like
* "\xff\n",pause,"ls\n" invalid and thus won't lose "ls".
*
+ * If LI_INTERRUPTIBLE, return -1 if got EINTR in poll()
+ * inside read_key, or if bb_got_signal != 0 (IOW: if signal
+ * arrived before poll() is reached).
+ *
* Note: read_key sets errno to 0 on success.
*/
- IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;)
- ic = read_key(STDIN_FILENO, read_key_buffer, timeout);
- IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 0;)
+ do {
+ if ((state->flags & LI_INTERRUPTIBLE) && bb_got_signal) {
+ errno = EINTR;
+ return -1;
+ }
+//FIXME: still races here with signals, but small window to poll() inside read_key
+ IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;)
+ ic = read_key(STDIN_FILENO, read_key_buffer, timeout);
+ IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 0;)
+ } while (!(state->flags & LI_INTERRUPTIBLE) && errno == EINTR);
+
if (errno) {
+ /* LI_INTERRUPTIBLE can bail out with EINTR here,
+ * but nothing really guarantees that bb_got_signal
+ * is nonzero. Follow the least surprise principle:
+ */
+ if (errno == EINTR && bb_got_signal == 0)
+ bb_got_signal = 255; /* something nonzero */
#if ENABLE_UNICODE_SUPPORT
if (errno == EAGAIN && unicode_idx != 0)
goto pushback;
diff --git a/libbb/read_key.c b/libbb/read_key.c
index 03b7da6..829ae21 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)
* if fd can be in non-blocking mode.
*/
if (timeout >= -1) {
- if (safe_poll(&pfd, 1, timeout) == 0) {
+ n = poll(&pfd, 1, timeout);
+ if (n < 0 && errno == EINTR)
+ return n;
+ if (n == 0) {
/* Timed out */
errno = EAGAIN;
return -1;
@@ -138,7 +141,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
* When we were reading 3 bytes here, we were eating
* "li" too, and cat was getting wrong input.
*/
- n = safe_read(fd, buffer, 1);
+ n = read(fd, buffer, 1);
if (n <= 0)
return -1;
}
@@ -284,6 +287,15 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
goto start_over;
}
+int64_t FAST_FUNC safe_read_key(int fd, char *buffer, int timeout)
+{
+ int64_t r;
+ do {
+ r = read_key(fd, buffer, timeout);
+ } while (errno == EINTR);
+ return r;
+}
+
void FAST_FUNC read_key_ungets(char *buffer, const char *str, unsigned len)
{
unsigned cur_len = (unsigned char)buffer[0];