From 521220ed1aa63e53e2f30042ae8f00f683e2254d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 23 Dec 2020 23:44:55 +0100 Subject: hush: fix ^C in INTERACTIVE, !EDITING config function old new delta refill_HFILE_and_getc 88 170 +82 fgetc_interactive 226 250 +24 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 106/0) Total: 106 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index e0b519217..d3444c556 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1649,6 +1649,26 @@ static int refill_HFILE_and_getc(HFILE *fp) /* Already saw EOF */ return EOF; } +#if ENABLE_HUSH_INTERACTIVE && !ENABLE_FEATURE_EDITING + /* If user presses ^C, read() restarts after SIGINT (we use SA_RESTART). + * IOW: ^C will not immediately stop line input. + * But poll() is different: it does NOT restart after signals. + */ + if (fp == G.HFILE_stdin) { + struct pollfd pfd[1]; + pfd[0].fd = fp->fd; + pfd[0].events = POLLIN; + n = poll(pfd, 1, -1); + if (n < 0 + /*&& errno == EINTR - assumed true */ + && sigismember(&G.pending_set, SIGINT) + ) { + return '\0'; + } + } +#else +/* if FEATURE_EDITING=y, we do not use this routine for interactive input */ +#endif /* Try to buffer more input */ n = safe_read(fp->fd, fp->buf, sizeof(fp->buf)); if (n < 0) { @@ -2090,7 +2110,6 @@ static void hush_exit(int exitcode) #endif } - //TODO: return a mask of ALL handled sigs? static int check_and_run_traps(void) { @@ -2665,19 +2684,23 @@ static int get_user_input(struct in_str *i) */ check_and_run_traps(); fputs(prompt_str, stdout); + fflush_all(); } - fflush_all(); -//FIXME: here ^C or SIGINT will have effect only after r = hfgetc(i->file); /* In !ENABLE_FEATURE_EDITING we don't use read_line_input, * no ^C masking happens during fgetc, no special code for ^C: * it generates SIGINT as usual. */ check_and_run_traps(); - if (G.flag_SIGINT) - G.last_exitcode = 128 | SIGINT; - if (r != '\0') + if (r != '\0' && !G.flag_SIGINT) break; + if (G.flag_SIGINT) { + /* ^C or SIGINT: repeat */ + /* bash prints ^C even on real SIGINT (non-kbd generated) */ + /* kernel prints "^C" itself, just print newline: */ + write(STDOUT_FILENO, "\n", 1); + G.last_exitcode = 128 | SIGINT; + } } return r; # endif -- cgit v1.2.3