[git commit] hush: fix ^C in INTERACTIVE, !EDITING config

Denys Vlasenko vda.linux at googlemail.com
Wed Dec 23 22:44:55 UTC 2020


commit: https://git.busybox.net/busybox/commit/?id=521220ed1aa63e53e2f30042ae8f00f683e2254d
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

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 <vda.linux at googlemail.com>
---
 shell/hush.c | 35 +++++++++++++++++++++++++++++------
 1 file changed, 29 insertions(+), 6 deletions(-)

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 <Enter>
 		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


More information about the busybox-cvs mailing list