All of lore.kernel.org
 help / color / mirror / Atom feed
From: Francis Laniel <francis.laniel@amarulasolutions.com>
To: u-boot@lists.denx.de
Cc: Michael Nazzareno Trimarchi <michael@amarulasolutions.com>,
	Tom Rini <trini@konsulko.com>, Harald Seiler <hws@denx.de>,
	Simon Glass <sjg@chromium.org>,
	Francis Laniel <francis.laniel@amarulasolutions.com>
Subject: [PATCH v11 22/24] cli: hush_2021: Add upstream commits up to 2nd October 2023.
Date: Tue,  7 Nov 2023 23:41:19 +0200	[thread overview]
Message-ID: <20231107214121.132079-23-francis.laniel@amarulasolutions.com> (raw)
In-Reply-To: <20231107214121.132079-1-francis.laniel@amarulasolutions.com>

This commit adds the following hush busybox upstream commits:
791b222dd55d ("sleep: fix "sleep -- ARGS"")
5353df91cba7 ("Update applet size estimates")
e41e481fd571 ("hush: fix a compile failure")
07a95cfcabb0 ("ash: disable check for "good" function name, bash does not check this")
e5692e2342c6 ("hush: quote values in "readonly" output")
96769486e20f ("shell: move varcmp() to shell_common.h and use it in hush")
bab8828b0dad ("hush: fix expansion of space in "a=${a:+$a }c" construct")
b5be8da350b5 ("hush: make "false" built-in")
6824298ab4d3 ("hush: fix ELIF cmd1;cmd2 THEN ... not executing cmd2, closes 15571")
3a7f00eadcf4 ("hush: add comment about abort on syntax error %{^}")
acae889dd972 ("ash,hush: tab completion of functions and aliases")
90b607d79a13 ("hush: quote variable values printed by "set" (match ash behavior)")
6748e6494c22 ("hush (NOMMU): fix LINENO in execed children")
fd5fb2d2b596 ("hush: speed up "big heredoc" code")
1409432d072e ("hush: add TODO comment")
93ae7464e6e4 ("hush: restore SIGHUP handling, this time explain why we do what we do")
1fdb33bd07e5 ("hush: restore tty pgrp on SIGHUP")
6101b6d3eaa0 ("hush: remove special handling of SIGHUP")
93e0898c663a ("shell: fix SIGWINCH and SIGCHLD (in hush) interrupting line input, closes 15256")
969e00816835 ("hush: code shrink")
27be0e8cfeb6 ("shell: fix compile failures in some configs")
7d1c7d833785 ("ash,hush: use HOME for tab completion and prompts")
21afddefd258 ("hush: fix "error: invalid preprocessing directive ##"")
e53c7dbafc78 ("hush: fix set -n to act immediately, not just after run_list()")
574b9c446da1 ("hush: fix var_LINENO3.tests failure")
49bcf9f40cff ("hush: speed up ${x//\*/|} too")
53b2fdcdba4c ("*: add NOINLINEs where code noticeably shrinks")
7c3e96d4b3d4 ("shell: use more compact SHELL_ASH / HUSH config defines. no code changes")
62f1eed1e191 ("hush: in a comment, document what -i might be doing")
aaf3d5ba74c5 ("shell: tweak --help")
db5546ca1018 ("libbb: code shrink: introduce and use [_]exit_SUCCESS()")
931c55f9e2b4 ("libbb: invert the meaning of SETUP_ENV_NO_CHDIR -> SETUP_ENV_CHDIR")
12566e7f9b5e ("ash,hush: fix handling of SIGINT while waiting for interactive input")
987be932ed3c ("*: slap on a few ALIGN_PTR where appropriate")

Signed-off-by: Francis Laniel <francis.laniel@amarulasolutions.com>
---
 common/cli_hush_2021.c     |  20 +-
 common/cli_hush_upstream.c | 407 ++++++++++++++++++++++++++-----------
 2 files changed, 304 insertions(+), 123 deletions(-)

diff --git a/common/cli_hush_2021.c b/common/cli_hush_2021.c
index 0a207d147b..15a5d3134e 100644
--- a/common/cli_hush_2021.c
+++ b/common/cli_hush_2021.c
@@ -26,7 +26,7 @@
 /*
  * BusyBox Version: UPDATE THIS WHEN PULLING NEW UPSTREAM REVISION!
  */
-#define BB_VER			"1.34.0.git37460f5daff9"
+#define BB_VER			"1.35.0.git7d1c7d833785"
 
 /*
  * Define hush features by the names used upstream.
@@ -236,6 +236,24 @@ static size_t list_size(char **list)
 	return size;
 }
 
+static int varcmp(const char *p, const char *q)
+{
+	int c, d;
+
+	while ((c = *p) == (d = *q)) {
+		if (c == '\0' || c == '=')
+			goto out;
+		p++;
+		q++;
+	}
+	if (c == '=')
+		c = '\0';
+	if (d == '=')
+		d = '\0';
+out:
+	return c - d;
+}
+
 struct in_str;
 static int u_boot_cli_readline(struct in_str *i);
 
diff --git a/common/cli_hush_upstream.c b/common/cli_hush_upstream.c
index 23392939e1..709c055d2f 100644
--- a/common/cli_hush_upstream.c
+++ b/common/cli_hush_upstream.c
@@ -91,7 +91,7 @@
  * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*"
  */
 //config:config HUSH
-//config:	bool "hush (68 kb)"
+//config:	bool "hush (70 kb)"
 //config:	default y
 //config:	select SHELL_HUSH
 //config:	help
@@ -339,7 +339,7 @@
  * therefore we don't show them either.
  */
 //usage:#define hush_trivial_usage
-//usage:	"[-enxl] [-c 'SCRIPT' [ARG0 ARGS] | FILE [ARGS] | -s [ARGS]]"
+//usage:	"[-enxl] [-c 'SCRIPT' [ARG0 ARGS] | FILE ARGS | -s ARGS]"
 //usage:#define hush_full_usage "\n\n"
 //usage:	"Unix shell interpreter"
 
@@ -374,7 +374,7 @@
 # define F_DUPFD_CLOEXEC F_DUPFD
 #endif
 
-#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS && !(ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH)
+#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS && !ENABLE_SHELL_ASH
 # include "embedded_scripts.h"
 #else
 # define NUM_SCRIPTS 0
@@ -574,7 +574,7 @@ enum {
 #define NULL_O_STRING { NULL }
 
 #ifndef debug_printf_parse
-static const char *const assignment_flag[] = {
+static const char *const assignment_flag[] ALIGN_PTR = {
 	"MAYBE_ASSIGNMENT",
 	"DEFINITELY_ASSIGNMENT",
 	"NOT_ASSIGNMENT",
@@ -958,6 +958,7 @@ struct globals {
 #if ENABLE_HUSH_INTERACTIVE
 	smallint promptmode; /* 0: PS1, 1: PS2 */
 #endif
+	/* set by signal handler if SIGINT is received _and_ its trap is not set */
 	smallint flag_SIGINT;
 #ifndef __U_BOOT__
 #if ENABLE_HUSH_LOOPS
@@ -1134,6 +1135,7 @@ static int builtin_export(char **argv) FAST_FUNC;
 #if ENABLE_HUSH_READONLY
 static int builtin_readonly(char **argv) FAST_FUNC;
 #endif
+static int builtin_false(char **argv) FAST_FUNC;
 #if ENABLE_HUSH_JOB
 static int builtin_fg_bg(char **argv) FAST_FUNC;
 static int builtin_jobs(char **argv) FAST_FUNC;
@@ -1234,6 +1236,7 @@ static const struct built_in_command bltins1[] ALIGN_PTR = {
 #if ENABLE_HUSH_EXPORT
 	BLTIN("export"   , builtin_export  , "Set environment variables"),
 #endif
+	BLTIN("false"    , builtin_false   , NULL),
 #if ENABLE_HUSH_JOB
 	BLTIN("fg"       , builtin_fg_bg   , "Bring job to foreground"),
 #endif
@@ -1507,6 +1510,7 @@ static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s)
 {
 	bb_error_msg("syntax error: unterminated %s", s);
 //? source4.tests fails: in bash, echo ${^} in script does not terminate the script
+// (but bash --posix, or if bash is run as "sh", does terminate in script, so maybe uncomment this?)
 //	die_if_script();
 }
 
@@ -1918,7 +1922,13 @@ static void restore_G_args(save_arg_t *sv, char **argv)
  * SIGQUIT: ignore
  * SIGTERM (interactive): ignore
  * SIGHUP (interactive):
- *    send SIGCONT to stopped jobs, send SIGHUP to all jobs and exit
+ *    Send SIGCONT to stopped jobs, send SIGHUP to all jobs and exit.
+ *    Kernel would do this for us ("orphaned process group" handling
+ *    according to POSIX) if we are a session leader and thus our death
+ *    frees the controlling tty, but to be bash-compatible, we also do it
+ *    for every interactive shell's death by SIGHUP.
+ *    (Also, we need to restore tty pgrp, otherwise e.g. Midnight Commander
+ *    backgrounds when hush started from it gets killed by SIGHUP).
  * SIGTTIN, SIGTTOU, SIGTSTP (if job control is on): ignore
  *    Note that ^Z is handled not by trapping SIGTSTP, but by seeing
  *    that all pipe members are stopped. Try this in bash:
@@ -2034,6 +2044,14 @@ enum {
 static void record_pending_signo(int sig)
 {
 	sigaddset(&G.pending_set, sig);
+#if ENABLE_FEATURE_EDITING
+	if (sig != SIGCHLD
+	 || (G_traps && G_traps[SIGCHLD] && G_traps[SIGCHLD][0])
+	 /* ^^^ if SIGCHLD, interrupt line reading only if it has a trap */
+	) {
+		bb_got_signal = sig; /* for read_line_input: "we got a signal" */
+	}
+#endif
 #if ENABLE_HUSH_FAST
 	if (sig == SIGCHLD) {
 		G.count_SIGCHLD++;
@@ -2265,20 +2283,27 @@ static int check_and_run_traps(void)
 			break;
 #if ENABLE_HUSH_JOB
 		case SIGHUP: {
-//TODO: why are we doing this? ash and dash don't do this,
-//they have no handler for SIGHUP at all,
-//they rely on kernel to send SIGHUP+SIGCONT to orphaned process groups
-			struct pipe *job;
-			debug_printf_exec("%s: sig:%d default SIGHUP handler\n", __func__, sig);
-			/* bash is observed to signal whole process groups,
-			 * not individual processes */
-			for (job = G.job_list; job; job = job->next) {
-				if (job->pgrp <= 0)
-					continue;
-				debug_printf_exec("HUPing pgrp %d\n", job->pgrp);
-				if (kill(- job->pgrp, SIGHUP) == 0)
-					kill(- job->pgrp, SIGCONT);
+			/* if (G_interactive_fd) - no need to check, the handler
+			 * is only installed if we *are* interactive */
+			{
+				/* bash compat: "Before exiting, an interactive
+				 * shell resends the SIGHUP to all jobs, running
+				 * or stopped.  Stopped jobs are sent SIGCONT
+				 * to ensure that they receive the SIGHUP."
+				 */
+				struct pipe *job;
+				debug_printf_exec("%s: sig:%d default SIGHUP handler\n", __func__, sig);
+				/* bash is observed to signal whole process groups,
+				 * not individual processes */
+				for (job = G.job_list; job; job = job->next) {
+					if (job->pgrp <= 0)
+						continue;
+					debug_printf_exec("HUPing pgrp %d\n", job->pgrp);
+					if (kill(- job->pgrp, SIGHUP) == 0)
+						kill(- job->pgrp, SIGCONT);
+				}
 			}
+			/* this restores tty pgrp, then kills us with SIGHUP */
 			sigexit(SIGHUP);
 		}
 #endif
@@ -2327,14 +2352,14 @@ static const char *get_cwd(int force)
 /*
  * Shell and environment variable support
  */
-static struct variable **get_ptr_to_local_var(const char *name, unsigned len)
+static struct variable **get_ptr_to_local_var(const char *name)
 {
 	struct variable **pp;
 	struct variable *cur;
 
 	pp = &G.top_var;
 	while ((cur = *pp) != NULL) {
-		if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=')
+		if (varcmp(cur->varstr, name) == 0)
 			return pp;
 		pp = &cur->next;
 	}
@@ -2344,21 +2369,20 @@ static struct variable **get_ptr_to_local_var(const char *name, unsigned len)
 static const char* FAST_FUNC get_local_var_value(const char *name)
 {
 	struct variable **vpp;
-	unsigned len = strlen(name);
 
 	if (G.expanded_assignments) {
 		char **cpp = G.expanded_assignments;
 		while (*cpp) {
 			char *cp = *cpp;
-			if (strncmp(cp, name, len) == 0 && cp[len] == '=')
-				return cp + len + 1;
+			if (varcmp(cp, name) == 0)
+				return strchr(cp, '=') + 1;
 			cpp++;
 		}
 	}
 
-	vpp = get_ptr_to_local_var(name, len);
+	vpp = get_ptr_to_local_var(name);
 	if (vpp)
-		return (*vpp)->varstr + len + 1;
+		return strchr((*vpp)->varstr, '=') + 1;
 
 #ifndef __U_BOOT__
 	if (strcmp(name, "PPID") == 0)
@@ -2394,13 +2418,11 @@ static const char* FAST_FUNC get_local_var_value(const char *name)
 
 #ifndef __U_BOOT__
 #if ENABLE_HUSH_GETOPTS
-static void handle_changed_special_names(const char *name, unsigned name_len)
+static void handle_changed_special_names(const char *name)
 {
-	if (name_len == 6) {
-		if (strncmp(name, "OPTIND", 6) == 0) {
-			G.getopt_count = 0;
-			return;
-		}
+	if (varcmp(name, "OPTIND") == 0) {
+		G.getopt_count = 0;
+		return;
 	}
 }
 #else
@@ -2575,16 +2597,21 @@ int set_local_var_2021(char *str, int flags)
 #endif /* !__U_BOOT__ */
 	free(free_me);
 
-	handle_changed_special_names(cur->varstr, name_len - 1);
+	handle_changed_special_names(cur->varstr);
 
 	return retval;
 }
 
 #ifndef __U_BOOT__
+static int set_local_var0(char *str)
+{
+	return set_local_var(str, 0);
+}
+
 static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val)
 {
 	char *var = xasprintf("%s=%s", name, val);
-	set_local_var(var, /*flag:*/ 0);
+	set_local_var0(var);
 }
 
 /* Used at startup and after each cd */
@@ -2595,16 +2622,14 @@ static void set_pwd_var(unsigned flag)
 #endif /* !__U_BOOT__ */
 
 #if ENABLE_HUSH_UNSET || ENABLE_HUSH_GETOPTS
-static int unset_local_var_len(const char *name, int name_len)
+static int unset_local_var(const char *name)
 {
 	struct variable *cur;
 	struct variable **cur_pp;
 
 	cur_pp = &G.top_var;
 	while ((cur = *cur_pp) != NULL) {
-		if (strncmp(cur->varstr, name, name_len) == 0
-		 && cur->varstr[name_len] == '='
-		) {
+		if (varcmp(cur->varstr, name) == 0) {
 			if (cur->flg_read_only) {
 				bb_error_msg("%s: readonly variable", name);
 				return EXIT_FAILURE;
@@ -2623,15 +2648,10 @@ static int unset_local_var_len(const char *name, int name_len)
 	}
 
 	/* Handle "unset LINENO" et al even if did not find the variable to unset */
-	handle_changed_special_names(name, name_len);
+	handle_changed_special_names(name);
 
 	return EXIT_SUCCESS;
 }
-
-static int unset_local_var(const char *name)
-{
-	return unset_local_var_len(name, strlen(name));
-}
 #endif
 
 
@@ -2678,7 +2698,7 @@ static void set_vars_and_save_old(char **strings)
 		eq = strchr(*s, '=');
 		if (HUSH_DEBUG && !eq)
 			bb_simple_error_msg_and_die("BUG in varexp4");
-		var_pp = get_ptr_to_local_var(*s, eq - *s);
+		var_pp = get_ptr_to_local_var(*s);
 		if (var_pp) {
 			var_p = *var_pp;
 			if (var_p->flg_read_only) {
@@ -2788,30 +2808,54 @@ static void get_user_input(struct in_str *i)
 	for (;;) {
 		reinit_unicode_for_hush();
 		G.flag_SIGINT = 0;
-		/* buglet: SIGINT will not make new prompt to appear _at once_,
-		 * only after <Enter>. (^C works immediately) */
-		r = read_line_input(G.line_input_state, prompt_str,
+
+		bb_got_signal = 0;
+		if (!sigisemptyset(&G.pending_set)) {
+			/* Whoops, already got a signal, do not call read_line_input */
+			bb_got_signal = r = -1;
+		} else {
+			/* For shell, LI_INTERRUPTIBLE is set:
+			 * read_line_input will abort on either
+			 * getting EINTR in poll() and bb_got_signal became != 0,
+			 * or if it sees bb_got_signal != 0
+			 * (IOW: if signal arrives before poll() is reached).
+			 * Interactive testcases:
+			 * (while kill -INT $$; do sleep 1; done) &
+			 * #^^^ prints ^C, prints prompt, repeats
+			 * trap 'echo I' int; (while kill -INT $$; do sleep 1; done) &
+			 * #^^^ prints ^C, prints "I", prints prompt, repeats
+			 * trap 'echo T' term; (while kill $$; do sleep 1; done) &
+			 * #^^^ prints "T", prints prompt, repeats
+			 * #(bash 5.0.17 exits after first "T", looks like a bug)
+			 */
+			r = read_line_input(G.line_input_state, prompt_str,
 				G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1
-		);
-		/* read_line_input intercepts ^C, "convert" it to SIGINT */
-		if (r == 0) {
-			raise(SIGINT);
+			);
+			/* read_line_input intercepts ^C, "convert" it to SIGINT */
+			if (r == 0)
+				raise(SIGINT);
+		}
+		/* bash prints ^C (before running a trap, if any)
+		 * both on keyboard ^C and on real SIGINT (non-kbd generated).
+		 */
+		if (sigismember(&G.pending_set, SIGINT)) {
+			write(STDOUT_FILENO, "^C\n", 3);
+			G.last_exitcode = 128 | SIGINT;
 		}
 		check_and_run_traps();
-		if (r != 0 && !G.flag_SIGINT)
+		if (r == 0) /* keyboard ^C? */
+			continue; /* go back, read another input line */
+		if (r > 0) /* normal input? (no ^C, no ^D, no signals) */
 			break;
-		/* ^C or SIGINT: repeat */
-		/* bash prints ^C even on real SIGINT (non-kbd generated) */
-		write(STDOUT_FILENO, "^C\n", 3);
-		G.last_exitcode = 128 | SIGINT;
-	}
-	if (r < 0) {
-		/* EOF/error detected */
-		/* ^D on interactive input goes to next line before exiting: */
-		write(STDOUT_FILENO, "\n", 1);
-		i->p = NULL;
-		i->peek_buf[0] = r = EOF;
-		return r;
+		if (!bb_got_signal) {
+			/* r < 0: ^D/EOF/error detected (but not signal) */
+			/* ^D on interactive input goes to next line before exiting: */
+			write(STDOUT_FILENO, "\n", 1);
+			i->p = NULL;
+			i->peek_buf[0] = r = EOF;
+			return r;
+		}
+		/* it was a signal: go back, read another input line */
 	}
 	i->p = G.user_input_buf;
 	return (unsigned char)*i->p++;
@@ -2991,6 +3035,12 @@ static int i_getch(struct in_str *i)
 		if (ch != '\0') {
 			i->p++;
 			i->last_char = ch;
+#if ENABLE_HUSH_LINENO_VAR
+			if (ch == '\n') {
+				G.parse_lineno++;
+				debug_printf_parse("G.parse_lineno++ = %u\n", G.parse_lineno);
+			}
+#endif
 			return ch;
 		}
 		return EOF;
@@ -3638,7 +3688,7 @@ static int glob_brace(char *pattern, o_string *o, int n)
 	 * NEXT points past the terminator of the first element, and REST
 	 * points past the final }.  We will accumulate result names from
 	 * recursive runs for each brace alternative in the buffer using
-	 * GLOB_APPEND.  */
+	 * GLOB_APPEND. */
 
 	p = begin + 1;
 	while (1) {
@@ -3954,7 +4004,7 @@ static void free_pipe_list(struct pipe *pi)
 #ifndef debug_print_tree
 static void debug_print_tree(struct pipe *pi, int lvl)
 {
-	static const char *const PIPE[] = {
+	static const char *const PIPE[] ALIGN_PTR = {
 		[PIPE_SEQ] = "SEQ",
 		[PIPE_AND] = "AND",
 		[PIPE_OR ] = "OR" ,
@@ -3989,7 +4039,7 @@ static void debug_print_tree(struct pipe *pi, int lvl)
 		[RES_XXXX ] = "XXXX" ,
 		[RES_SNTX ] = "SNTX" ,
 	};
-	static const char *const CMDTYPE[] = {
+	static const char *const CMDTYPE[] ALIGN_PTR = {
 		"{}",
 		"()",
 		"[noglob]",
@@ -4576,7 +4626,7 @@ static int done_word(struct parse_context *ctx)
 		 || endofname(command->argv[0])[0] != '\0'
 		) {
 			/* bash says just "not a valid identifier" */
-			syntax_error("bad variable name in for");
+			syntax_error("bad for loop variable");
 			return 1;
 		}
 		/* Force FOR to have just one word (variable name) */
@@ -4967,6 +5017,11 @@ static int parse_group(struct parse_context *ctx,
 			syntax_error_unexpected_ch(ch);
 			return -1;
 		}
+//bash allows functions named "123", "..", "return"!
+//		if (endofname(command->argv[0])[0] != '\0') {
+//			syntax_error("bad function name");
+//			return -1;
+//		}
 		nommu_addchr(&ctx->as_string, ch);
 		command->cmd_type = CMD_FUNCDEF;
 		goto skip;
@@ -5354,7 +5409,7 @@ static int parse_dollar_squote(o_string *as_string, o_string *dest, struct in_st
 # undef as_string
 }
 #else
-# #define parse_dollar_squote(as_string, dest, input) 0
+# define parse_dollar_squote(as_string, dest, input) 0
 #endif /* BASH_DOLLAR_SQUOTE */
 #endif /* !__U_BOOT__ */
 
@@ -6721,7 +6776,7 @@ static char *encode_then_expand_vararg(const char *str, int handle_squotes, int
 
 /* Expanding ARG in ${var+ARG}, ${var-ARG}
  */
-static int encode_then_append_var_plusminus(o_string *output, int n,
+static NOINLINE int encode_then_append_var_plusminus(o_string *output, int n,
 		char *str, int dquoted)
 {
 	struct in_str input;
@@ -6754,7 +6809,7 @@ static int encode_then_append_var_plusminus(o_string *output, int n,
 		if (!dest.o_expflags) {
 			if (ch == EOF)
 				break;
-			if (!dquoted && strchr(G.ifs, ch)) {
+			if (!dquoted && !(output->o_expflags & EXP_FLAG_SINGLEWORD) && strchr(G.ifs, ch)) {
 				/* PREFIX${x:d${e}f ...} and we met space: expand "d${e}f" and start new word.
 				 * do not assume we are at the start of the word (PREFIX above).
 				 */
@@ -6886,16 +6941,21 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
 /* ${var/[/]pattern[/repl]} helpers */
 static char *strstr_pattern(char *val, const char *pattern, int *size)
 {
-	int sz = strcspn(pattern, "*?[\\");
-	if (pattern[sz] == '\0') {
+	int first_escaped = (pattern[0] == '\\' && pattern[1]);
+	/* "first_escaped" trick allows to treat e.g. "\*no_glob_chars"
+	 * as literal too (as it is semi-common, and easy to accomodate
+	 * by just using str + 1).
+	 */
+	int sz = strcspn(pattern + first_escaped * 2, "*?[\\");
+	if ((pattern + first_escaped * 2)[sz] == '\0') {
 		/* Optimization for trivial patterns.
 		 * Testcase for very slow replace (performs about 22k replaces):
 		 * x=::::::::::::::::::::::
 		 * x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;echo ${#x}
 		 * echo "${x//:/|}"
 		 */
-		*size = sz;
-		return strstr(val, pattern);
+		*size = sz + first_escaped;
+		return strstr(val, pattern + first_escaped);
 	}
 
 	while (1) {
@@ -7371,7 +7431,7 @@ static NOINLINE int expand_one_var(o_string *output, int n,
 							val = NULL;
 						} else {
 							char *new_var = xasprintf("%s=%s", var, val);
-							set_local_var(new_var, /*flag:*/ 0);
+							set_local_var0(new_var);
 						}
 					}
 				}
@@ -7859,6 +7919,9 @@ static void re_execute_shell(char ***to_free, const char *s,
 		if (!cur->flg_export || cur->flg_read_only)
 			cnt += 2;
 	}
+# if ENABLE_HUSH_LINENO_VAR
+	cnt += 2;
+# endif
 # if ENABLE_HUSH_FUNCTIONS
 	for (funcp = G.top_func; funcp; funcp = funcp->next)
 		cnt += 3;
@@ -7880,6 +7943,10 @@ static void re_execute_shell(char ***to_free, const char *s,
 			*pp++ = cur->varstr;
 		}
 	}
+# if ENABLE_HUSH_LINENO_VAR
+	*pp++ = (char *) "-L";
+	*pp++ = utoa(G.execute_lineno);
+# endif
 # if ENABLE_HUSH_FUNCTIONS
 	for (funcp = G.top_func; funcp; funcp = funcp->next) {
 		*pp++ = (char *) "-F";
@@ -8026,7 +8093,11 @@ static int parse_and_run_string(const char *s)
 #endif /* __U_BOOT__ */
 {
 	struct in_str input;
+#ifndef __U_BOOT__
+	IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;)
+#else /* __U_BOOT__ */
 	//IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;)
+#endif /* __U_BOOT__ */
 
 	setup_string_in_str(&input, s);
 #ifndef __U_BOOT__
@@ -8034,7 +8105,11 @@ static int parse_and_run_string(const char *s)
 #else /* __U_BOOT__ */
 	return parse_and_run_stream(&input, '\0');
 #endif /* __U_BOOT__ */
-	//IF_HUSH_LINENO_VAR(G.parse_lineno = sv;)
+#ifndef __U_BOOT__
+	IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;)
+#else /* __U_BOOT__ */
+	//IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;)
+#endif /* __U_BOOT__ */
 }
 
 #ifdef __U_BOOT__
@@ -8142,7 +8217,7 @@ static int generate_stream_from_string(const char *s, pid_t *pid_p)
 		if (is_prefixed_with(s, "trap")
 		 && skip_whitespace(s + 4)[0] == '\0'
 		) {
-			static const char *const argv[] = { NULL, NULL };
+			static const char *const argv[] ALIGN_PTR = { NULL, NULL };
 			builtin_trap((char**)argv);
 			fflush_all(); /* important */
 			_exit(0);
@@ -8671,8 +8746,8 @@ static const struct built_in_command *find_builtin(const char *name)
 	return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]);
 }
 
-#if ENABLE_HUSH_JOB && EDITING_HAS_get_exe_name
-static const char * FAST_FUNC get_builtin_name(int i)
+#if ENABLE_HUSH_JOB && ENABLE_FEATURE_TAB_COMPLETION
+static const char * FAST_FUNC hush_command_name(int i)
 {
 	if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) {
 		return bltins1[i].b_cmd;
@@ -8681,6 +8756,16 @@ static const char * FAST_FUNC get_builtin_name(int i)
 	if (i < ARRAY_SIZE(bltins2)) {
 		return bltins2[i].b_cmd;
 	}
+# if ENABLE_HUSH_FUNCTIONS
+	{
+		struct function *funcp;
+		i -= ARRAY_SIZE(bltins2);
+		for (funcp = G.top_func; funcp; funcp = funcp->next) {
+			if (--i < 0)
+				return funcp->name;
+		}
+	}
+# endif
 	return NULL;
 }
 #endif
@@ -9107,7 +9192,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
 		 * expand_assignments(): think about ... | var=`sleep 1` | ...
 		 */
 		free_strings(new_env);
-		_exit(EXIT_SUCCESS);
+		_exit_SUCCESS();
 	}
 
 	sv_shadowed = G.shadowed_vars_pp;
@@ -9288,7 +9373,7 @@ static void pseudo_exec(nommu_save_t *nommu_save,
 
 	/* Case when we are here: ... | >file */
 	debug_printf_exec("pseudo_exec'ed null command\n");
-	_exit(EXIT_SUCCESS);
+	_exit_SUCCESS();
 }
 
 #if ENABLE_HUSH_JOB
@@ -9895,7 +9980,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
 #endif
 				debug_printf_env("set shell var:'%s'->'%s'\n", *argv, p);
 #ifndef __U_BOOT__
-				if (set_local_var(p, /*flag:*/ 0)) {
+				if (set_local_var0(p)) {
 #else /* __U_BOOT__ */
 				if (set_local_var_2021(p, /*flag:*/ 0)) {
 #endif
@@ -10296,7 +10381,7 @@ static int run_list(struct pipe *pi)
 #endif
 
 #ifndef __U_BOOT__
-	debug_printf_exec("run_list start lvl %d\n", G.run_list_level);
+	debug_printf_exec("run_list lvl %d start\n", G.run_list_level);
 	debug_enter();
 #endif /* !__U_BOOT__ */
 
@@ -10362,7 +10447,7 @@ static int run_list(struct pipe *pi)
 #endif /* !__U_BOOT__ */
 
 		IF_HAS_KEYWORDS(rword = pi->res_word;)
-		debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n",
+		debug_printf_exec(": rword:%d cond_code:%d last_rword:%d\n",
 				rword, cond_code, last_rword);
 
 		sv_errexit_depth = G.errexit_depth;
@@ -10396,23 +10481,29 @@ static int run_list(struct pipe *pi)
 			}
 		}
 		last_followup = pi->followup;
-		IF_HAS_KEYWORDS(last_rword = rword;)
 #if ENABLE_HUSH_IF
-		if (cond_code) {
+		if (cond_code != 0) {
 			if (rword == RES_THEN) {
 				/* if false; then ... fi has exitcode 0! */
 				G.last_exitcode = rcode = EXIT_SUCCESS;
 				/* "if <false> THEN cmd": skip cmd */
+				debug_printf_exec("skipped THEN cmd because IF condition was false\n");
+				last_rword = rword;
 				continue;
 			}
 		} else {
-			if (rword == RES_ELSE || rword == RES_ELIF) {
+			if (rword == RES_ELSE
+			 || (rword == RES_ELIF && last_rword != RES_ELIF)
+			) {
 				/* "if <true> then ... ELSE/ELIF cmd":
 				 * skip cmd and all following ones */
+				debug_printf_exec("skipped ELSE/ELIF branch because IF condition was true\n");
 				break;
 			}
+			//if (rword == RES_THEN): "if <true> THEN cmd", run cmd (fall through)
 		}
 #endif
+		IF_HAS_KEYWORDS(last_rword = rword;)
 #if ENABLE_HUSH_LOOPS
 		if (rword == RES_FOR) { /* && pi->num_cmds - always == 1 */
 			if (!for_lcur) {
@@ -10421,7 +10512,7 @@ static int run_list(struct pipe *pi)
 				static const char encoded_dollar_at[] ALIGN1 = {
 					SPECIAL_VAR_SYMBOL, '@' | 0x80, SPECIAL_VAR_SYMBOL, '\0'
 				}; /* encoded representation of "$@" */
-				static const char *const encoded_dollar_at_argv[] = {
+				static const char *const encoded_dollar_at_argv[] ALIGN_PTR = {
 					encoded_dollar_at, NULL
 				}; /* argv list with one element: "$@" */
 				char **vals;
@@ -10452,7 +10543,7 @@ static int run_list(struct pipe *pi)
 			/* Insert next value from for_lcur */
 			/* note: *for_lcur already has quotes removed, $var expanded, etc */
 #ifndef __U_BOOT__
-			set_local_var(xasprintf("%s=%s", pi->cmds[0].argv[0], *for_lcur++), /*flag:*/ 0);
+			set_local_var_from_halves(pi->cmds[0].argv[0], *for_lcur++);
 #else /* __U_BOOT__ */
 			/* We cannot use xasprintf, so we emulate it. */
 			char *full_var;
@@ -10501,7 +10592,7 @@ static int run_list(struct pipe *pi)
 				);
 				/* TODO: which FNM_xxx flags to use? */
 				cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0);
-				debug_printf_exec("fnmatch(pattern:'%s',str:'%s'):%d\n",
+				debug_printf_exec("cond_code=fnmatch(pattern:'%s',str:'%s'):%d\n",
 						pattern, case_word, cond_code);
 				free(pattern);
 				if (cond_code == 0) {
@@ -10548,8 +10639,11 @@ static int run_list(struct pipe *pi)
 		G.flag_break_continue = 0;
 #endif
 #endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
+		rcode = r = G.o_opt[OPT_O_NOEXEC] ? 0 : run_pipe(pi);
+		/* NB: rcode is a smalluint, r is int */
+#else /* __U_BOOT__ */
 		rcode = r = run_pipe(pi); /* NB: rcode is a smalluint, r is int */
-#ifdef __U_BOOT__
 		if (r <= EXIT_RET_CODE) {
 			int previous_rcode = G.last_exitcode;
 			/*
@@ -10673,8 +10767,10 @@ static int run_list(struct pipe *pi)
 
 		/* Analyze how result affects subsequent commands */
 #if ENABLE_HUSH_IF
-		if (rword == RES_IF || rword == RES_ELIF)
+		if (rword == RES_IF || rword == RES_ELIF) {
+			debug_printf_exec("cond_code=rcode:%d\n", rcode);
 			cond_code = rcode;
+		}
 #endif
 #ifndef __U_BOOT__
  check_jobs_and_continue:
@@ -10718,7 +10814,7 @@ static int run_list(struct pipe *pi)
 #endif
 #ifndef __U_BOOT__
 	debug_leave();
-	debug_printf_exec("run_list lvl %d return %d\n", G.run_list_level + 1, rcode);
+	debug_printf_exec("run_list lvl %d return %d\n", G.run_list_level, rcode);
 #endif /* !__U_BOOT__ */
 	return rcode;
 }
@@ -10839,7 +10935,10 @@ static int set_mode(int state, char mode, const char *o_opt)
 	int idx;
 	switch (mode) {
 	case 'n':
-		G.o_opt[OPT_O_NOEXEC] = state;
+		/* set -n has no effect in interactive shell */
+		/* Try: while set -n; do echo $-; done */
+		if (!G_interactive_fd)
+			G.o_opt[OPT_O_NOEXEC] = state;
 		break;
 	case 'x':
 		IF_HUSH_MODE_X(G_x_mode = state;)
@@ -10896,6 +10995,20 @@ int hush_main(int argc, char **argv)
 	INIT_G();
 	if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */
 		G.last_exitcode = EXIT_SUCCESS;
+#if !BB_MMU
+	/* "Big heredoc" support via "sh -< STRING" invocation.
+	 * Check it first (do not bother to run the usual init code,
+	 * it is not needed for this case).
+	 */
+	if (argv[1]
+	 && argv[1][0] == '-' && argv[1][1] == '<' /*&& !argv[1][2]*/
+	 /*&& argv[2] && !argv[3] - we don't check some conditions */
+	) {
+		full_write1_str(argv[2]);
+		_exit(0);
+	}
+	G.argv0_for_re_execing = argv[0];
+#endif
 #if ENABLE_HUSH_TRAP
 # if ENABLE_HUSH_FUNCTIONS
 	G.return_exitcode = -1;
@@ -10906,13 +11019,10 @@ int hush_main(int argc, char **argv)
 #if ENABLE_HUSH_FAST
 	G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
 #endif
-#if !BB_MMU
-	G.argv0_for_re_execing = argv[0];
-#endif
 
 	cached_getpid = getpid();   /* for tcsetpgrp() during init */
 	G.root_pid = cached_getpid; /* for $PID  (NOMMU can override via -$HEXPID:HEXPPID:...) */
-	G.root_ppid = getppid();    /* for $PPID (NOMMU can override)  */
+	G.root_ppid = getppid();    /* for $PPID (NOMMU can override) */
 
 	/* Deal with HUSH_VERSION */
 	debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
@@ -11024,7 +11134,10 @@ int hush_main(int argc, char **argv)
 		int opt = getopt(argc, argv, "+" /* stop at 1st non-option */
 				"cexinsl"
 #if !BB_MMU
-				"<:$:R:V:"
+				"$:R:V:"
+# if ENABLE_HUSH_LINENO_VAR
+				"L:"
+# endif
 # if ENABLE_HUSH_FUNCTIONS
 				"F:"
 # endif
@@ -11043,6 +11156,29 @@ int hush_main(int argc, char **argv)
 			/* Well, we cannot just declare interactiveness,
 			 * we have to have some stuff (ctty, etc) */
 			/* G_interactive_fd++; */
+//There are a few cases where bash -i -c 'SCRIPT'
+//has visible effect (differs from bash -c 'SCRIPT'):
+//it ignores TERM:
+//	bash -i -c 'kill $$; echo ALIVE'
+//	ALIVE
+//it resets SIG_IGNed HUP to SIG_DFL:
+//	trap '' hup; bash -i -c 'kill -hup $$; echo ALIVE'
+//	Hangup   [the message is not printed by bash, it's the shell which started it]
+//is talkative about jobs and exiting:
+//	bash -i -c 'sleep 1 & exit'
+//	[1] 16170
+//	exit
+//includes $ENV file (only if run as "sh"):
+//	echo last >/tmp/ENV; ENV=/tmp/ENV sh -i -c 'echo HERE'
+//	last: cannot open /var/log/wtmp: No such file or directory
+//	HERE
+//(under "bash", it's the opposite: it runs $BASH_ENV file only *without* -i).
+//
+//ash -i -c 'sleep 3; sleep 3', on ^C, drops into a prompt instead of exiting
+//(this may be a bug, bash does not do this).
+//(ash -i -c 'sleep 3' won't show this, the last command gets auto-"exec"ed)
+//
+//None of the above feel like useful features people would rely on.
 			break;
 		case 's':
 			G.opt_s = 1;
@@ -11051,9 +11187,6 @@ int hush_main(int argc, char **argv)
 			flags |= OPT_login;
 			break;
 #if !BB_MMU
-		case '<': /* "big heredoc" support */
-			full_write1_str(optarg);
-			_exit(0);
 		case '$': {
 			unsigned long long empty_trap_mask;
 
@@ -11103,6 +11236,11 @@ int hush_main(int argc, char **argv)
 		case 'V':
 			set_local_var(xstrdup(optarg), opt == 'R' ? SETFLAG_MAKE_RO : 0);
 			break;
+# if ENABLE_HUSH_LINENO_VAR
+		case 'L':
+			G.parse_lineno = xatou(optarg);
+			break;
+# endif
 # if ENABLE_HUSH_FUNCTIONS
 		case 'F': {
 			struct function *funcp = new_function(optarg);
@@ -11307,8 +11445,11 @@ int hush_main(int argc, char **argv)
 
 # if ENABLE_FEATURE_EDITING
 		G.line_input_state = new_line_input_t(FOR_SHELL);
-#  if EDITING_HAS_get_exe_name
-		G.line_input_state->get_exe_name = get_builtin_name;
+#  if ENABLE_FEATURE_TAB_COMPLETION
+		G.line_input_state->get_exe_name = hush_command_name;
+#  endif
+#  if EDITING_HAS_sh_get_var
+		G.line_input_state->sh_get_var = get_local_var_value;
 #  endif
 # endif
 # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0
@@ -11394,6 +11535,11 @@ static int FAST_FUNC builtin_true(char **argv UNUSED_PARAM)
 	return 0;
 }
 
+static int FAST_FUNC builtin_false(char **argv UNUSED_PARAM)
+{
+	return 1;
+}
+
 #if ENABLE_HUSH_TEST || ENABLE_HUSH_ECHO || ENABLE_HUSH_PRINTF || ENABLE_HUSH_KILL
 static NOINLINE int run_applet_main(char **argv, int (*applet_main_func)(int argc, char **argv))
 {
@@ -11444,14 +11590,6 @@ static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM)
 }
 #endif
 
-static char **skip_dash_dash(char **argv)
-{
-	argv++;
-	if (argv[0] && argv[0][0] == '-' && argv[0][1] == '-' && argv[0][2] == '\0')
-		argv++;
-	return argv;
-}
-
 static int FAST_FUNC builtin_cd(char **argv)
 {
 	const char *newdir;
@@ -11734,9 +11872,15 @@ static int FAST_FUNC builtin_umask(char **argv)
 }
 #endif
 
-#if ENABLE_HUSH_EXPORT || ENABLE_HUSH_TRAP
+#if ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY || ENABLE_HUSH_SET || ENABLE_HUSH_TRAP
 static void print_escaped(const char *s)
 {
+//TODO? bash "set" does not quote variables which contain only alnums and "%+,-./:=@_~",
+// (but "export" quotes all variables, even with only these chars).
+// I think quoting strings with %+,=~ looks better
+// (example: "set" printing var== instead of var='=' looks strange)
+// IOW: do not quote "-./:@_": / is used in pathnames, : in PATH, -._ often in file names, @ in emails
+
 	if (*s == '\'')
 		goto squote;
 	do {
@@ -11765,7 +11909,7 @@ static int helper_export_local(char **argv, unsigned flags)
 		if (*name_end == '\0') {
 			struct variable *var, **vpp;
 
-			vpp = get_ptr_to_local_var(name, name_end - name);
+			vpp = get_ptr_to_local_var(name);
 			var = vpp ? *vpp : NULL;
 
 			if (flags & SETFLAG_UNEXPORT) {
@@ -11867,8 +12011,8 @@ static int FAST_FUNC builtin_export(char **argv)
 
 				if (!p) /* wtf? take next variable */
 					continue;
-				/* export var= */
-				printf("export %.*s", (int)(p - s) + 1, s);
+				/* "export VAR=" */
+				printf("%s %.*s", "export", (int)(p - s) + 1, s);
 				print_escaped(p + 1);
 				putchar('\n');
 # endif
@@ -11889,6 +12033,9 @@ static int FAST_FUNC builtin_local(char **argv)
 		bb_error_msg("%s: not in a function", argv[0]);
 		return EXIT_FAILURE; /* bash compat */
 	}
+//TODO? ash and bash support "local -" special form,
+//which saves/restores $- around function call (including async returns, such as ^C)
+//(IOW: it makes "set +/-..." effects local)
 	argv++;
 	/* Since all builtins run in a nested variable level,
 	 * need to use level - 1 here. Or else the variable will be removed at once
@@ -11909,8 +12056,15 @@ static int FAST_FUNC builtin_readonly(char **argv)
 		struct variable *e;
 		for (e = G.top_var; e; e = e->next) {
 			if (e->flg_read_only) {
-//TODO: quote value: readonly VAR='VAL'
-				printf("readonly %s\n", e->varstr);
+				const char *s = e->varstr;
+				const char *p = strchr(s, '=');
+
+				if (!p) /* wtf? take next variable */
+					continue;
+				/* "readonly VAR=" */
+				printf("%s %.*s", "readonly", (int)(p - s) + 1, s);
+				print_escaped(p + 1);
+				putchar('\n');
 			}
 		}
 		return EXIT_SUCCESS;
@@ -11988,8 +12142,17 @@ static int FAST_FUNC builtin_set(char **argv)
 
 	if (arg == NULL) {
 		struct variable *e;
-		for (e = G.top_var; e; e = e->next)
-			puts(e->varstr);
+		for (e = G.top_var; e; e = e->next) {
+			const char *s = e->varstr;
+			const char *p = strchr(s, '=');
+
+			if (!p) /* wtf? take next variable */
+				continue;
+			/* var= */
+			printf("%.*s", (int)(p - s) + 1, s);
+			print_escaped(p + 1);
+			putchar('\n');
+		}
 		return EXIT_SUCCESS;
 	}
 
@@ -12422,7 +12585,7 @@ static int FAST_FUNC builtin_fg_bg(char **argv)
 	/* TODO: bash prints a string representation
 	 * of job being foregrounded (like "sleep 1 | cat") */
 	if (argv[0][0] == 'f' && G_saved_tty_pgrp) {
-		/* Put the job into the foreground.  */
+		/* Put the job into the foreground. */
 		tcsetpgrp(G_interactive_fd, pi->pgrp);
 	}
 
-- 
2.34.1


  parent reply	other threads:[~2023-11-07 21:45 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-07 21:40 [PATCH v11 00/24] Modernize U-Boot shell Francis Laniel
2023-11-07 21:40 ` [PATCH v11 01/24] test: Add framework to test hush behavior Francis Laniel
2023-11-07 21:40 ` [PATCH v11 02/24] test: hush: Test hush if/else Francis Laniel
2023-11-07 21:41 ` [PATCH v11 03/24] test/py: hush_if_test: Remove the test file Francis Laniel
2023-11-07 21:41 ` [PATCH v11 04/24] test: hush: Test hush variable expansion Francis Laniel
2023-11-07 21:41 ` [PATCH v11 05/24] test: hush: Test hush commands list Francis Laniel
2023-11-07 21:41 ` [PATCH v11 06/24] test: hush: Test hush loops Francis Laniel
2023-11-07 21:41 ` [PATCH v11 07/24] cli: Add Busybox upstream hush.c file Francis Laniel
2023-11-07 21:41 ` [PATCH v11 08/24] cli: Port Busybox 2021 hush to U-Boot Francis Laniel
2023-11-09 13:37   ` Tom Rini
2023-11-09 19:12   ` [PATCH] squash! Remove some ifndef __U_BOOT__ checks in new hush Tom Rini
2023-11-07 21:41 ` [PATCH v11 09/24] cli: Add menu for hush parser Francis Laniel
2023-11-09 13:38   ` Tom Rini
2023-11-07 21:41 ` [PATCH v11 10/24] global_data.h: add GD_FLG_HUSH_OLD_PARSER flag Francis Laniel
2023-11-07 21:41 ` [PATCH v11 11/24] cmd: Add new cli command Francis Laniel
2023-11-07 21:41 ` [PATCH v11 12/24] cli: Enables using hush 2021 parser as command line parser Francis Laniel
2023-11-07 21:41 ` [PATCH v11 13/24] cli: hush_2021: Enable variables expansion for hush 2021 Francis Laniel
2023-11-07 21:41 ` [PATCH v11 14/24] cli: hush_2021: Add functions to be called from run_command() Francis Laniel
2023-11-07 21:41 ` [PATCH v11 15/24] cli: add hush 2021 as parser for run_command*() Francis Laniel
2023-11-07 21:41 ` [PATCH v11 16/24] test: hush: Fix instructions list tests for hush 2021 Francis Laniel
2023-11-07 21:41 ` [PATCH v11 17/24] test: hush: Fix variable expansion " Francis Laniel
2023-11-07 21:41 ` [PATCH v11 18/24] cli: hush_2021: Enable using < and > as string compare operators Francis Laniel
2023-11-07 21:41 ` [PATCH v11 19/24] cli: hush_2021: Enable if keyword Francis Laniel
2023-11-07 21:41 ` [PATCH v11 20/24] cli: hush_2021: Enable loops Francis Laniel
2023-11-07 21:41 ` [PATCH v11 21/24] test: hush: Fix loop tests for hush 2021 Francis Laniel
2023-11-07 21:41 ` Francis Laniel [this message]
2023-11-07 21:41 ` [PATCH v11 23/24] DO NOT MERGE: only to make CI happy Francis Laniel
2023-11-09 13:37   ` Tom Rini
2023-11-07 21:41 ` [PATCH v11 24/24] DO NOT MERGE: ci: Build the world in any case Francis Laniel
2023-11-08 22:56   ` Tom Rini
2023-11-08 12:14 ` [PATCH v11 00/24] Modernize U-Boot shell Peter Robinson
2023-11-09  1:15   ` Simon Glass
2023-11-09  2:42   ` Tom Rini
2023-11-09 13:37   ` Tom Rini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231107214121.132079-23-francis.laniel@amarulasolutions.com \
    --to=francis.laniel@amarulasolutions.com \
    --cc=hws@denx.de \
    --cc=michael@amarulasolutions.com \
    --cc=sjg@chromium.org \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.