From 9a068377313c1feabb55072d2d1157999cf9d15e Mon Sep 17 00:00:00 2001 From: Francis Laniel Date: Fri, 22 Dec 2023 22:02:32 +0100 Subject: cli: Enables using modern hush parser as command line parser If one defines HUSH_MODERN_PARSER, it is then possible to use modern parser with: => cli get old => cli set modern => cli get modern Reviewed-by: Simon Glass Signed-off-by: Francis Laniel --- common/Makefile | 1 + common/cli.c | 38 ++++++++++++++++++++++++++++++++------ common/cli_hush_modern.c | 3 +++ common/cli_hush_upstream.c | 46 +++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 77 insertions(+), 11 deletions(-) (limited to 'common') diff --git a/common/Makefile b/common/Makefile index 3bb33b4e36d..f010c2a1b9b 100644 --- a/common/Makefile +++ b/common/Makefile @@ -10,6 +10,7 @@ obj-y += main.o obj-y += exports.o obj-y += cli_getch.o cli_simple.o cli_readline.o obj-$(CONFIG_HUSH_OLD_PARSER) += cli_hush.o +obj-$(CONFIG_HUSH_MODERN_PARSER) += cli_hush_modern.o obj-$(CONFIG_AUTOBOOT) += autoboot.o obj-y += version.o diff --git a/common/cli.c b/common/cli.c index d419671e8c8..b3eb512b623 100644 --- a/common/cli.c +++ b/common/cli.c @@ -43,12 +43,15 @@ int run_command(const char *cmd, int flag) return 1; return 0; -#else +#elif CONFIG_IS_ENABLED(HUSH_OLD_PARSER) int hush_flags = FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP; if (flag & CMD_FLAG_ENV) hush_flags |= FLAG_CONT_ON_NEWLINE; return parse_string_outer(cmd, hush_flags); +#else /* HUSH_MODERN_PARSER */ + /* Not yet implemented. */ + return 1; #endif } @@ -108,7 +111,12 @@ int run_command_list(const char *cmd, int len, int flag) buff[len] = '\0'; } #ifdef CONFIG_HUSH_PARSER +#if CONFIG_IS_ENABLED(HUSH_OLD_PARSER) rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON); +#else /* HUSH_MODERN_PARSER */ + /* Not yet implemented. */ + rcode = 1; +#endif #else /* * This function will overwrite any \n it sees with a \0, which @@ -254,8 +262,13 @@ err: void cli_loop(void) { bootstage_mark(BOOTSTAGE_ID_ENTER_CLI_LOOP); -#ifdef CONFIG_HUSH_PARSER - parse_file_outer(); +#if CONFIG_IS_ENABLED(HUSH_PARSER) + if (gd->flags & GD_FLG_HUSH_MODERN_PARSER) + parse_and_run_file(); + else if (gd->flags & GD_FLG_HUSH_OLD_PARSER) + parse_file_outer(); + + printf("Problem\n"); /* This point is never reached */ for (;;); #elif defined(CONFIG_CMDLINE) @@ -268,10 +281,23 @@ void cli_loop(void) void cli_init(void) { #ifdef CONFIG_HUSH_PARSER + /* This if block is used to initialize hush parser gd flag. */ if (!(gd->flags & GD_FLG_HUSH_OLD_PARSER) - && CONFIG_IS_ENABLED(HUSH_OLD_PARSER)) - gd->flags |= GD_FLG_HUSH_OLD_PARSER; - u_boot_hush_start(); + && !(gd->flags & GD_FLG_HUSH_MODERN_PARSER)) { + if (CONFIG_IS_ENABLED(HUSH_OLD_PARSER)) + gd->flags |= GD_FLG_HUSH_OLD_PARSER; + else if (CONFIG_IS_ENABLED(HUSH_MODERN_PARSER)) + gd->flags |= GD_FLG_HUSH_MODERN_PARSER; + } + + if (gd->flags & GD_FLG_HUSH_OLD_PARSER) { + u_boot_hush_start(); + } else if (gd->flags & GD_FLG_HUSH_MODERN_PARSER) { + u_boot_hush_start_modern(); + } else { + printf("No valid hush parser to use, cli will not initialized!\n"); + return; + } #endif #if defined(CONFIG_HUSH_INIT_VAR) diff --git a/common/cli_hush_modern.c b/common/cli_hush_modern.c index 34278fdca2f..626fed089b2 100644 --- a/common/cli_hush_modern.c +++ b/common/cli_hush_modern.c @@ -221,6 +221,9 @@ static uint8_t xfunc_error_retval; static const char defifsvar[] __aligned(1) = "IFS= \t\n"; #define defifs (defifsvar + 4) +/* This define is used to check if exit command was called. */ +#define EXIT_RET_CODE -2 + /* * This define is used for changes that need be done directly in the upstream * sources still. Ideally, its use should be minimized as much as possible. diff --git a/common/cli_hush_upstream.c b/common/cli_hush_upstream.c index 3f2e4a54956..4b6ab20f3b1 100644 --- a/common/cli_hush_upstream.c +++ b/common/cli_hush_upstream.c @@ -7913,7 +7913,17 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger) } debug_print_tree(pipe_list, 0); debug_printf_exec("parse_and_run_stream: run_and_free_list\n"); +#ifndef __U_BOOT__ run_and_free_list(pipe_list); +#else /* __U_BOOT__ */ + int rcode = run_and_free_list(pipe_list); + /* + * We reset input string to not run the following command, so running + * 'exit; echo foo' does not print foo. + */ + if (rcode <= EXIT_RET_CODE) + setup_file_in_str(inp); +#endif /* __U_BOOT__ */ empty = 0; if (G_flag_return_in_progress == 1) break; @@ -10368,13 +10378,39 @@ static int run_list(struct pipe *pi) #endif /* !__U_BOOT__ */ rcode = r = run_pipe(pi); /* NB: rcode is a smalluint, r is int */ #ifdef __U_BOOT__ - if (r == -2) { - /* -2 indicates exit was called, so we need to quit now. */ - G.last_exitcode = rcode; + if (r <= EXIT_RET_CODE) { + int previous_rcode = G.last_exitcode; + /* + * This magic is to get the exit code given by the user. + * Contrary to old shell code, we use + EXIT_RET_CODE as EXIT_RET_CODE + * equals -2. + */ + G.last_exitcode = -r + EXIT_RET_CODE; - break; + /* + * This case deals with the following: + * => setenv inner 'echo entry inner; exit; echo inner done' + * => setenv outer 'echo entry outer; run inner; echo outer done' + * => run outer + * So, if we are in inner, we need to break and not run the other + * commands. + * Otherwise, we just continue in outer. + * As return code are propagated, we use the previous value to check if + * exit was just called or was propagated. + */ + if (previous_rcode != r) { + /* + * If run from run_command, run_command_flags will be set, so we check + * this to know if we are in main input shell. + */ + if (!G.run_command_flags) + printf("exit not allowed from main input shell.\n"); + + break; + } + continue; } -#endif +#endif /* __U_BOOT__ */ if (r != -1) { /* We ran a builtin, function, or group. * rcode is already known -- cgit v1.2.3