From c5f991d2ad8ea2d872fad64dee2fd660bb0a1b20 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 25 Feb 2019 09:03:30 +0100 Subject: Shell: Handle aborting loops better It's easy to get stuck in an infinite loop in the hush shell: while true; do sleep 1; done The 'sleep' command will check for ctrl-c with the ctrlc() function. This will abort the sleep command. Hush then checks for ctrl-c again in the loop. The ctrl-c in the buffer has already been eaten by the sleep command, so the loop will continue. With this patch we remember the presence of a ctrl-c character in a variable instead of checking for a new character each time. The variable must be resetted explicitly by calling ctrlc_handled() which will be called by the shell in the outer loop. Signed-off-by: Sascha Hauer --- common/console.c | 28 +++++++++++++++++++++++----- common/hush.c | 3 ++- common/parser.c | 1 + 3 files changed, 26 insertions(+), 6 deletions(-) (limited to 'common') diff --git a/common/console.c b/common/console.c index 47ccf2e54d..b6685ecf6a 100644 --- a/common/console.c +++ b/common/console.c @@ -574,18 +574,36 @@ void console_flush(void) } EXPORT_SYMBOL(console_flush); -#ifndef ARCH_HAS_CTRLC +static int ctrlc_abort; + +void ctrlc_handled(void) +{ + ctrlc_abort = 0; +} + /* test if ctrl-c was pressed */ -int ctrlc (void) +int ctrlc(void) { + int ret = 0; + + if (ctrlc_abort) + return 1; + poller_call(); +#ifdef ARCH_HAS_CTRLC + ret = arch_ctrlc(); +#else if (tstc() && getchar() == 3) - return 1; - return 0; + ret = 1; +#endif + + if (ret) + ctrlc_abort = 1; + + return ret; } EXPORT_SYMBOL(ctrlc); -#endif /* ARCH_HAS_CTRC */ BAREBOX_MAGICVAR_NAMED(global_linux_bootargs_console, global.linux.bootargs.console, "console= argument for Linux from the stdout-path property in /chosen node"); diff --git a/common/hush.c b/common/hush.c index d2f9cc70f5..dab9b04081 100644 --- a/common/hush.c +++ b/common/hush.c @@ -1734,7 +1734,7 @@ static int parse_stream_outer(struct p_context *ctx, struct in_str *inp, int fla return 1; } b_free(&temp); - } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ + } while (!ctrlc() && rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ return code; } @@ -1932,6 +1932,7 @@ int run_shell(void) login(); do { + ctrlc_handled(); setup_file_in_str(&input); rcode = parse_stream_outer(&ctx, &input, FLAG_PARSE_SEMICOLON); if (rcode < -1) { diff --git a/common/parser.c b/common/parser.c index 397d268da1..fb9ef42e7f 100644 --- a/common/parser.c +++ b/common/parser.c @@ -283,6 +283,7 @@ int run_shell(void) /* invalid command or not repeatable, forget it */ lastcommand[0] = 0; } + ctrlc_handled(); } } return 0; -- cgit v1.2.3