[RFC PATCH v1 12/21] cli: hush_2021: Enable variables expansion for hush 2021.

Francis Laniel francis.laniel at amarulasolutions.com
Fri Dec 31 17:13:18 CET 2021


The following commit enables variables expansion for hush 2021, both for local
and environment variables.
So the following commands:
foo=bar
echo $foo
setenv bar foo
echo $bar
leads to "bar" and "foo" being printed on console output.

Signed-off-by: Francis Laniel <francis.laniel at amarulasolutions.com>
---
 common/cli_hush_2021.c          | 17 ++++++++
 common/cli_hush_2021_upstream.c | 74 ++++++++++++++++++++++++++++++---
 2 files changed, 86 insertions(+), 5 deletions(-)

diff --git a/common/cli_hush_2021.c b/common/cli_hush_2021.c
index 52e249d8be..342be3beb8 100644
--- a/common/cli_hush_2021.c
+++ b/common/cli_hush_2021.c
@@ -225,6 +225,23 @@ static const char* endofname(const char *name)
 	return name;
 }
 
+/**
+ * list_size() - returns the number of elements in char ** before NULL.
+ *
+ * Argument must contain NULL to signalize its end.
+ *
+ * @list The list to count the number of element.
+ * @return The number of element in list.
+ */
+static size_t list_size(char **list)
+{
+	size_t size;
+
+	for(size = 0; list[size] != NULL; size++);
+
+	return size;
+}
+
 struct in_str;
 static int u_boot_cli_readline(struct in_str *i);
 
diff --git a/common/cli_hush_2021_upstream.c b/common/cli_hush_2021_upstream.c
index 06649a6011..51e351cdc6 100644
--- a/common/cli_hush_2021_upstream.c
+++ b/common/cli_hush_2021_upstream.c
@@ -3475,7 +3475,6 @@ static int o_get_last_ptr(o_string *o, int n)
 	return ((int)(uintptr_t)list[n-1]) + string_start;
 }
 
-#ifndef __U_BOOT__
 /*
  * Globbing routines.
  *
@@ -3730,8 +3729,10 @@ static int glob_needed(const char *s)
  */
 static int perform_glob(o_string *o, int n)
 {
+#ifndef __U_BOOT__
 	glob_t globdata;
 	int gr;
+#endif /* __U_BOOT__ */
 	char *pattern;
 
 	debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data);
@@ -3740,13 +3741,16 @@ static int perform_glob(o_string *o, int n)
 	pattern = o->data + o_get_last_ptr(o, n);
 	debug_printf_glob("glob pattern '%s'\n", pattern);
 	if (!glob_needed(pattern)) {
+#ifndef __U_BOOT__
  literal:
+#endif /* __U_BOOT__ */
 		/* unbackslash last string in o in place, fix length */
 		o->length = unbackslash(pattern) - o->data;
 		debug_printf_glob("glob pattern '%s' is literal\n", pattern);
 		return o_save_ptr_helper(o, n);
 	}
 
+#ifndef __U_BOOT__
 	memset(&globdata, 0, sizeof(globdata));
 	/* Can't use GLOB_NOCHECK: it does not unescape the string.
 	 * If we glob "*.\*" and don't find anything, we need
@@ -3782,16 +3786,22 @@ static int perform_glob(o_string *o, int n)
 	if (DEBUG_GLOB)
 		debug_print_list("perform_glob returning", o, n);
 	return n;
+#else /* __U_BOOT__ */
+	/*
+	 * NOTE We only use perform glob to call unbackslash to remove backslash
+	 * from string once expanded.
+	 * So, it seems OK to return this if no previous return was done.
+	 */
+	return o_save_ptr_helper(o, n);
+#endif /* __U_BOOT__ */
 }
 
-#endif /* !__U_BOOT__ */
 #endif /* !HUSH_BRACE_EXPANSION */
 
 /* If o->o_expflags & EXP_FLAG_GLOB, glob the string so far remembered.
  * Otherwise, just finish current list[] and start new */
 static int o_save_ptr(o_string *o, int n)
 {
-#ifndef __U_BOOT__
 	if (o->o_expflags & EXP_FLAG_GLOB) {
 		/* If o->has_empty_slot, list[n] was already globbed
 		 * (if it was requested back then when it was filled)
@@ -3799,7 +3809,6 @@ static int o_save_ptr(o_string *o, int n)
 		if (!o->has_empty_slot)
 			return perform_glob(o, n); /* o_save_ptr_helper is inside */
 	}
-#endif /* !__U_BOOT__ */
 	return o_save_ptr_helper(o, n);
 }
 
@@ -7012,7 +7021,20 @@ static NOINLINE int expand_one_var(o_string *output, int n,
 		}
 #endif /* !__U_BOOT__ */
 		default:
+#ifndef __U_BOOT__
 			val = get_local_var_value(var);
+#else /* __U_BOOT__ */
+			/*
+			 * Environment variable set with setenv* have to be
+			 * expanded.
+			 * So, we first search if the variable exists in
+			 * environment, if this is not the case, we default to
+			 * local value.
+			 */
+			val = env_get(var);
+			if (!val)
+				val = get_local_var_value(var);
+#endif /* __U_BOOT__ */
 		}
 	}
 
@@ -9944,7 +9966,30 @@ static NOINLINE int run_pipe(struct pipe *pi)
 #endif /* !__U_BOOT__ */
 		command = &pi->cmds[cmd_no];
 		cmd_no++;
-		if (command->argv) {
+
+#ifdef __U_BOOT__
+		/* Replace argv and argc by expanded if it exists. */
+		if (argv_expanded) {
+			/*
+			 * We need to save a pointer to argv, we will restore it
+			 * later, so it will be freed when pipe is freed.
+			 */
+			argv = command->argv;
+
+			/*
+			 * After expansion, there can be more or less argument, so we need to
+			 * update argc, for example:
+			 * - More arguments:
+			 *   foo='bar quuz'
+			 *   echo $foo
+			 * - Less arguments:
+			 *   echo $foo (if foo was never set)
+			 */
+			command->argc = list_size(argv_expanded);
+			command->argv = argv_expanded;
+		}
+#endif /* __U_BOOT__ */
+			if (command->argv) {
 			debug_printf_exec(": pipe member '%s' '%s'...\n",
 					command->argv[0], command->argv[1]);
 		} else {
@@ -10059,6 +10104,25 @@ static NOINLINE int run_pipe(struct pipe *pi)
 		rcode = cmd_process(G.do_repeat ? CMD_FLAG_REPEAT : 0,
 				    command->argc, command->argv,
 				    &(G.flag_repeat), NULL);
+
+		if (argv_expanded) {
+			/*
+			 * expand_strvec_to_strvec() allocates memory to expand
+			 * argv, we need to free it.
+			 */
+			free(argv_expanded);
+
+			/*
+			 * We also restore command->argv to its original value
+			 * so no memory leak happens.
+			 */
+			command->argv = argv;
+
+			/*
+			 * NOTE argc exists only in U-Boot, so argv freeing does
+			 * not rely on it as this code exists in BusyBox.
+			 */
+		}
 #endif /* __U_BOOT__ */
 	}
 
-- 
2.25.1



More information about the U-Boot mailing list