Add run_command_list() to run a list of commands
This new function runs a list of commands separated by semicolon or newline.
We move this out of cmd_source so that it can be used by other code. The
PXE code also uses the new function.
Suggested-by: Michael Walle <michael@walle.cc>
Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c
index 77a7dd1..6b31dea 100644
--- a/common/cmd_pxe.c
+++ b/common/cmd_pxe.c
@@ -554,33 +554,19 @@
*/
static int label_localboot(struct pxe_label *label)
{
- char *localcmd, *dupcmd;
- int ret;
+ char *localcmd;
localcmd = from_env("localcmd");
if (!localcmd)
return -ENOENT;
- /*
- * dup the command to avoid any issues with the version of it existing
- * in the environment changing during the execution of the command.
- */
- dupcmd = strdup(localcmd);
-
- if (!dupcmd)
- return -ENOMEM;
-
if (label->append)
setenv("bootargs", label->append);
- printf("running: %s\n", dupcmd);
+ debug("running: %s\n", localcmd);
- ret = run_command(dupcmd, 0);
-
- free(dupcmd);
-
- return ret;
+ return run_command_list(localcmd, strlen(localcmd), 0);
}
/*
diff --git a/common/cmd_source.c b/common/cmd_source.c
index 32fff5c..c4cde98 100644
--- a/common/cmd_source.c
+++ b/common/cmd_source.c
@@ -39,9 +39,6 @@
#if defined(CONFIG_8xx)
#include <mpc8xx.h>
#endif
-#ifdef CONFIG_SYS_HUSH_PARSER
-#include <hush.h>
-#endif
int
source (ulong addr, const char *fit_uname)
@@ -49,8 +46,6 @@
ulong len;
image_header_t *hdr;
ulong *data;
- char *cmd;
- int rcode = 0;
int verify;
#if defined(CONFIG_FIT)
const void* fit_hdr;
@@ -151,49 +146,7 @@
}
debug ("** Script length: %ld\n", len);
-
- if ((cmd = malloc (len + 1)) == NULL) {
- return 1;
- }
-
- /* make sure cmd is null terminated */
- memmove (cmd, (char *)data, len);
- *(cmd + len) = 0;
-
-#ifdef CONFIG_SYS_HUSH_PARSER /*?? */
- rcode = parse_string_outer (cmd, FLAG_PARSE_SEMICOLON);
-#else
- {
- char *line = cmd;
- char *next = cmd;
-
- /*
- * break into individual lines,
- * and execute each line;
- * terminate on error.
- */
- while (*next) {
- if (*next == '\n') {
- *next = '\0';
- /* run only non-empty commands */
- if (*line) {
- debug ("** exec: \"%s\"\n",
- line);
- if (run_command(line, 0) < 0) {
- rcode = 1;
- break;
- }
- }
- line = next + 1;
- }
- ++next;
- }
- if (rcode == 0 && *line)
- rcode = (run_command(line, 0) >= 0);
- }
-#endif
- free (cmd);
- return rcode;
+ return run_command_list((char *)data, len, 0);
}
/**************************************************/
diff --git a/common/main.c b/common/main.c
index a933357..d96ba0a 100644
--- a/common/main.c
+++ b/common/main.c
@@ -30,6 +30,7 @@
#include <common.h>
#include <watchdog.h>
#include <command.h>
+#include <malloc.h>
#include <version.h>
#ifdef CONFIG_MODEM_SUPPORT
#include <malloc.h> /* for free() prototype */
@@ -1373,6 +1374,90 @@
#endif
}
+#ifndef CONFIG_SYS_HUSH_PARSER
+/**
+ * Execute a list of command separated by ; or \n using the built-in parser.
+ *
+ * This function cannot take a const char * for the command, since if it
+ * finds newlines in the string, it replaces them with \0.
+ *
+ * @param cmd String containing list of commands
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+static int builtin_run_command_list(char *cmd, int flag)
+{
+ char *line, *next;
+ int rcode = 0;
+
+ /*
+ * Break into individual lines, and execute each line; terminate on
+ * error.
+ */
+ line = next = cmd;
+ while (*next) {
+ if (*next == '\n') {
+ *next = '\0';
+ /* run only non-empty commands */
+ if (*line) {
+ debug("** exec: \"%s\"\n", line);
+ if (builtin_run_command(line, 0) < 0) {
+ rcode = 1;
+ break;
+ }
+ }
+ line = next + 1;
+ }
+ ++next;
+ }
+ if (rcode == 0 && *line)
+ rcode = (builtin_run_command(line, 0) >= 0);
+
+ return rcode;
+}
+#endif
+
+int run_command_list(const char *cmd, int len, int flag)
+{
+ int need_buff = 1;
+ char *buff = (char *)cmd; /* cast away const */
+ int rcode = 0;
+
+ if (len == -1) {
+ len = strlen(cmd);
+#ifdef CONFIG_SYS_HUSH_PARSER
+ /* hush will never change our string */
+ need_buff = 0;
+#else
+ /* the built-in parser will change our string if it sees \n */
+ need_buff = strchr(cmd, '\n') != NULL;
+#endif
+ }
+ if (need_buff) {
+ buff = malloc(len + 1);
+ if (!buff)
+ return 1;
+ memcpy(buff, cmd, len);
+ buff[len] = '\0';
+ }
+#ifdef CONFIG_SYS_HUSH_PARSER
+ rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
+#else
+ /*
+ * This function will overwrite any \n it sees with a \0, which
+ * is why it can't work with a const char *. Here we are making
+ * using of internal knowledge of this function, to avoid always
+ * doing a malloc() which is actually required only in a case that
+ * is pretty rare.
+ */
+ rcode = builtin_run_command_list(buff, flag);
+ if (need_buff)
+ free(buff);
+#endif
+
+ return rcode;
+}
+
/****************************************************************************/
#if defined(CONFIG_CMD_RUN)
diff --git a/include/common.h b/include/common.h
index 39859d3..55025c0 100644
--- a/include/common.h
+++ b/include/common.h
@@ -286,6 +286,19 @@
/* common/main.c */
void main_loop (void);
int run_command(const char *cmd, int flag);
+
+/**
+ * Run a list of commands separated by ; or even \0
+ *
+ * Note that if 'len' is not -1, then the command does not need to be nul
+ * terminated, Memory will be allocated for the command in that case.
+ *
+ * @param cmd List of commands to run, each separated bu semicolon
+ * @param len Length of commands excluding terminator if known (-1 if not)
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+int run_command_list(const char *cmd, int len, int flag);
int readline (const char *const prompt);
int readline_into_buffer(const char *const prompt, char *buffer,
int timeout);