mirror of
https://github.com/u-boot/u-boot.git
synced 2025-05-08 19:11:53 +00:00
bootstd: Add support for updating elements of the cmdline
Add a bootflow command to update the command line more easily. This allows changing a particular parameter rather than editing a very long strings. It is also easier to handle with scripting. The new 'bootflow cmdline' command allows getting and setting single parameters. Fix up the example output while we are here, since there are a few new items. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
parent
d07861cc7a
commit
82c0938f1d
5 changed files with 293 additions and 2 deletions
|
@ -801,3 +801,56 @@ int cmdline_set_arg(char *buf, int maxlen, const char *cmdline,
|
||||||
|
|
||||||
return to - buf;
|
return to - buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bootflow_cmdline_set_arg(struct bootflow *bflow, const char *set_arg,
|
||||||
|
const char *new_val, bool set_env)
|
||||||
|
{
|
||||||
|
char buf[2048];
|
||||||
|
char *cmd = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = cmdline_set_arg(buf, sizeof(buf), bflow->cmdline, set_arg,
|
||||||
|
new_val, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = bootflow_cmdline_set(bflow, buf);
|
||||||
|
if (*buf) {
|
||||||
|
cmd = strdup(buf);
|
||||||
|
if (!cmd)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
free(bflow->cmdline);
|
||||||
|
bflow->cmdline = cmd;
|
||||||
|
|
||||||
|
if (set_env) {
|
||||||
|
ret = env_set("bootargs", bflow->cmdline);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmdline_get_arg(const char *cmdline, const char *arg, int *posp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = cmdline_set_arg(NULL, 1, cmdline, arg, NULL, posp);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bootflow_cmdline_get_arg(struct bootflow *bflow, const char *arg,
|
||||||
|
const char **val)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
ret = cmdline_get_arg(bflow->cmdline, arg, &pos);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
*val = bflow->cmdline + pos;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -431,6 +431,72 @@ static int do_bootflow_menu(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int do_bootflow_cmdline(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
|
char *const argv[])
|
||||||
|
{
|
||||||
|
struct bootstd_priv *std;
|
||||||
|
struct bootflow *bflow;
|
||||||
|
const char *op, *arg, *val = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (argc < 3)
|
||||||
|
return CMD_RET_USAGE;
|
||||||
|
|
||||||
|
ret = bootstd_get_priv(&std);
|
||||||
|
if (ret)
|
||||||
|
return CMD_RET_FAILURE;
|
||||||
|
|
||||||
|
bflow = std->cur_bootflow;
|
||||||
|
if (!bflow) {
|
||||||
|
printf("No bootflow selected\n");
|
||||||
|
return CMD_RET_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
op = argv[1];
|
||||||
|
arg = argv[2];
|
||||||
|
if (*op == 's') {
|
||||||
|
if (argc < 4)
|
||||||
|
return CMD_RET_USAGE;
|
||||||
|
val = argv[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*op) {
|
||||||
|
case 'c': /* clear */
|
||||||
|
val = "";
|
||||||
|
fallthrough;
|
||||||
|
case 's': /* set */
|
||||||
|
case 'd': /* delete */
|
||||||
|
ret = bootflow_cmdline_set_arg(bflow, arg, val, true);
|
||||||
|
break;
|
||||||
|
case 'g': /* get */
|
||||||
|
ret = bootflow_cmdline_get_arg(bflow, arg, &val);
|
||||||
|
if (ret >= 0)
|
||||||
|
printf("%.*s\n", ret, val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (ret) {
|
||||||
|
case -E2BIG:
|
||||||
|
printf("Argument too long\n");
|
||||||
|
break;
|
||||||
|
case -ENOENT:
|
||||||
|
printf("Argument not found\n");
|
||||||
|
break;
|
||||||
|
case -EINVAL:
|
||||||
|
printf("Mismatched quotes\n");
|
||||||
|
break;
|
||||||
|
case -EBADF:
|
||||||
|
printf("Value must be quoted\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (ret < 0)
|
||||||
|
printf("Unknown error: %dE\n", ret);
|
||||||
|
}
|
||||||
|
if (ret < 0)
|
||||||
|
return CMD_RET_FAILURE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif /* CONFIG_CMD_BOOTFLOW_FULL */
|
#endif /* CONFIG_CMD_BOOTFLOW_FULL */
|
||||||
|
|
||||||
#ifdef CONFIG_SYS_LONGHELP
|
#ifdef CONFIG_SYS_LONGHELP
|
||||||
|
@ -441,7 +507,8 @@ static char bootflow_help_text[] =
|
||||||
"bootflow select [<num>|<name>] - select a bootflow\n"
|
"bootflow select [<num>|<name>] - select a bootflow\n"
|
||||||
"bootflow info [-d] - show info on current bootflow (-d dump bootflow)\n"
|
"bootflow info [-d] - show info on current bootflow (-d dump bootflow)\n"
|
||||||
"bootflow boot - boot current bootflow (or first available if none selected)\n"
|
"bootflow boot - boot current bootflow (or first available if none selected)\n"
|
||||||
"bootflow menu [-t] - show a menu of available bootflows";
|
"bootflow menu [-t] - show a menu of available bootflows\n"
|
||||||
|
"bootflow cmdline [set|get|clear|delete] <param> [<value>] - update cmdline";
|
||||||
#else
|
#else
|
||||||
"scan - boot first available bootflow\n";
|
"scan - boot first available bootflow\n";
|
||||||
#endif
|
#endif
|
||||||
|
@ -455,5 +522,6 @@ U_BOOT_CMD_WITH_SUBCMDS(bootflow, "Boot flows", bootflow_help_text,
|
||||||
U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootflow_info),
|
U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootflow_info),
|
||||||
U_BOOT_SUBCMD_MKENT(boot, 1, 1, do_bootflow_boot),
|
U_BOOT_SUBCMD_MKENT(boot, 1, 1, do_bootflow_boot),
|
||||||
U_BOOT_SUBCMD_MKENT(menu, 2, 1, do_bootflow_menu),
|
U_BOOT_SUBCMD_MKENT(menu, 2, 1, do_bootflow_menu),
|
||||||
|
U_BOOT_SUBCMD_MKENT(cmdline, 4, 1, do_bootflow_cmdline),
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,7 +13,7 @@ Synopis
|
||||||
bootflow select [<num|name>]
|
bootflow select [<num|name>]
|
||||||
bootflow info [-d]
|
bootflow info [-d]
|
||||||
bootflow boot
|
bootflow boot
|
||||||
|
bootflow cmdline [set|get|clear|delete] <param> [<value>]
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
@ -198,6 +198,26 @@ bootflow boot
|
||||||
This boots the current bootflow.
|
This boots the current bootflow.
|
||||||
|
|
||||||
|
|
||||||
|
bootflow cmdline
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Some bootmeths can obtain the OS command line since it is stored with the OS.
|
||||||
|
In that case, you can use `bootflow cmdline` to adjust this. The command line
|
||||||
|
is assumed to be in the format used by Linux, i.e. a space-separated set of
|
||||||
|
parameters with optional values, e.g. "noinitrd console=/dev/tty0".
|
||||||
|
|
||||||
|
To change or add a parameter, use::
|
||||||
|
|
||||||
|
bootflow cmdline set <param> <value>
|
||||||
|
|
||||||
|
To clear a parameter value to empty you can use "" for the value, or use::
|
||||||
|
|
||||||
|
bootflow cmdline clear <param>
|
||||||
|
|
||||||
|
To delete a parameter entirely, use::
|
||||||
|
|
||||||
|
bootflow cmdline delete <param>
|
||||||
|
|
||||||
Example
|
Example
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
|
@ -484,4 +484,46 @@ int bootflow_menu_run(struct bootstd_priv *std, bool text_mode,
|
||||||
int cmdline_set_arg(char *buf, int maxlen, const char *cmdline,
|
int cmdline_set_arg(char *buf, int maxlen, const char *cmdline,
|
||||||
const char *set_arg, const char *new_val, int *posp);
|
const char *set_arg, const char *new_val, int *posp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bootflow_cmdline_set_arg() - Set a single argument for a bootflow
|
||||||
|
*
|
||||||
|
* Update the allocated cmdline and set the bootargs variable
|
||||||
|
*
|
||||||
|
* @bflow: Bootflow to update
|
||||||
|
* @arg: Argument to update (e.g. "console")
|
||||||
|
* @val: Value to set (e.g. "ttyS2") or NULL to delete the argument if present,
|
||||||
|
* "" to set it to an empty value (e.g. "console=") and BOOTFLOWCL_EMPTY to add
|
||||||
|
* it without any value ("initrd")
|
||||||
|
* @set_env: true to set the "bootargs" environment variable too
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ENOMEM if out of memory
|
||||||
|
*/
|
||||||
|
int bootflow_cmdline_set_arg(struct bootflow *bflow, const char *arg,
|
||||||
|
const char *val, bool set_env);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cmdline_get_arg() - Read an argument from a cmdline
|
||||||
|
*
|
||||||
|
* @cmdline: Command line to read, in the form:
|
||||||
|
*
|
||||||
|
* fred mary= jane=123 john="has spaces"
|
||||||
|
* @arg: Argument to read (may or may not exist)
|
||||||
|
* @posp: Returns position of argument (after any leading quote) if present
|
||||||
|
* Return: Length of argument value excluding quotes if found, -ENOENT if not
|
||||||
|
* found
|
||||||
|
*/
|
||||||
|
int cmdline_get_arg(const char *cmdline, const char *arg, int *posp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bootflow_cmdline_get_arg() - Read an argument from a cmdline
|
||||||
|
*
|
||||||
|
* @bootflow: Bootflow to read from
|
||||||
|
* @arg: Argument to read (may or may not exist)
|
||||||
|
* @valp: Returns a pointer to the argument (after any leading quote) if present
|
||||||
|
* Return: Length of argument value excluding quotes if found, -ENOENT if not
|
||||||
|
* found
|
||||||
|
*/
|
||||||
|
int bootflow_cmdline_get_arg(struct bootflow *bflow, const char *arg,
|
||||||
|
const char **val);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -837,3 +837,111 @@ static int test_bootflow_cmdline_set(struct unit_test_state *uts)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
BOOTSTD_TEST(test_bootflow_cmdline_set, 0);
|
BOOTSTD_TEST(test_bootflow_cmdline_set, 0);
|
||||||
|
|
||||||
|
/* Test of bootflow_cmdline_set_arg() */
|
||||||
|
static int bootflow_set_arg(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
struct bootflow s_bflow, *bflow = &s_bflow;
|
||||||
|
ulong mem_start;
|
||||||
|
|
||||||
|
ut_assertok(env_set("bootargs", NULL));
|
||||||
|
|
||||||
|
mem_start = ut_check_delta(0);
|
||||||
|
|
||||||
|
/* Do a simple sanity check. Rely on bootflow_cmdline() for the rest */
|
||||||
|
bflow->cmdline = NULL;
|
||||||
|
ut_assertok(bootflow_cmdline_set_arg(bflow, "fred", "123", false));
|
||||||
|
ut_asserteq_str(bflow->cmdline, "fred=123");
|
||||||
|
|
||||||
|
ut_assertok(bootflow_cmdline_set_arg(bflow, "mary", "and here", false));
|
||||||
|
ut_asserteq_str(bflow->cmdline, "fred=123 mary=\"and here\"");
|
||||||
|
|
||||||
|
ut_assertok(bootflow_cmdline_set_arg(bflow, "mary", NULL, false));
|
||||||
|
ut_asserteq_str(bflow->cmdline, "fred=123");
|
||||||
|
ut_assertok(bootflow_cmdline_set_arg(bflow, "fred", NULL, false));
|
||||||
|
ut_asserteq_ptr(bflow->cmdline, NULL);
|
||||||
|
|
||||||
|
ut_asserteq(0, ut_check_delta(mem_start));
|
||||||
|
|
||||||
|
ut_assertok(bootflow_cmdline_set_arg(bflow, "mary", "here", true));
|
||||||
|
ut_asserteq_str("mary=here", env_get("bootargs"));
|
||||||
|
ut_assertok(env_set("bootargs", NULL));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
BOOTSTD_TEST(bootflow_set_arg, 0);
|
||||||
|
|
||||||
|
/* Test of bootflow_cmdline_get_arg() */
|
||||||
|
static int bootflow_cmdline_get(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
/* empty string */
|
||||||
|
ut_asserteq(-ENOENT, cmdline_get_arg("", "fred", &pos));
|
||||||
|
|
||||||
|
/* arg with empty value */
|
||||||
|
ut_asserteq(0, cmdline_get_arg("fred= mary", "fred", &pos));
|
||||||
|
ut_asserteq(5, pos);
|
||||||
|
|
||||||
|
/* arg with a value */
|
||||||
|
ut_asserteq(2, cmdline_get_arg("fred=23", "fred", &pos));
|
||||||
|
ut_asserteq(5, pos);
|
||||||
|
|
||||||
|
/* arg with a value */
|
||||||
|
ut_asserteq(3, cmdline_get_arg("mary=1 fred=234", "fred", &pos));
|
||||||
|
ut_asserteq(12, pos);
|
||||||
|
|
||||||
|
/* arg with a value, after quoted arg */
|
||||||
|
ut_asserteq(3, cmdline_get_arg("mary=\"1 2\" fred=234", "fred", &pos));
|
||||||
|
ut_asserteq(16, pos);
|
||||||
|
|
||||||
|
/* arg in the middle */
|
||||||
|
ut_asserteq(0, cmdline_get_arg("mary=\"1 2\" fred john=23", "fred",
|
||||||
|
&pos));
|
||||||
|
ut_asserteq(15, pos);
|
||||||
|
|
||||||
|
/* quoted arg */
|
||||||
|
ut_asserteq(3, cmdline_get_arg("mary=\"1 2\" fred=\"3 4\" john=23",
|
||||||
|
"fred", &pos));
|
||||||
|
ut_asserteq(17, pos);
|
||||||
|
|
||||||
|
/* args starting with the same prefix */
|
||||||
|
ut_asserteq(1, cmdline_get_arg("mary=abc johnathon=3 john=1", "john",
|
||||||
|
&pos));
|
||||||
|
ut_asserteq(26, pos);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
BOOTSTD_TEST(bootflow_cmdline_get, 0);
|
||||||
|
|
||||||
|
static int bootflow_cmdline(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
ut_assertok(run_command("bootflow scan mmc", 0));
|
||||||
|
ut_assertok(run_command("bootflow sel 0", 0));
|
||||||
|
console_record_reset_enable();
|
||||||
|
|
||||||
|
ut_asserteq(1, run_command("bootflow cmdline get fred", 0));
|
||||||
|
ut_assert_nextline("Argument not found");
|
||||||
|
ut_assert_console_end();
|
||||||
|
|
||||||
|
ut_asserteq(0, run_command("bootflow cmdline set fred 123", 0));
|
||||||
|
ut_asserteq(0, run_command("bootflow cmdline get fred", 0));
|
||||||
|
ut_assert_nextline("123");
|
||||||
|
|
||||||
|
ut_asserteq(0, run_command("bootflow cmdline set mary abc", 0));
|
||||||
|
ut_asserteq(0, run_command("bootflow cmdline get mary", 0));
|
||||||
|
ut_assert_nextline("abc");
|
||||||
|
|
||||||
|
ut_asserteq(0, run_command("bootflow cmdline delete fred", 0));
|
||||||
|
ut_asserteq(1, run_command("bootflow cmdline get fred", 0));
|
||||||
|
ut_assert_nextline("Argument not found");
|
||||||
|
|
||||||
|
ut_asserteq(0, run_command("bootflow cmdline clear mary", 0));
|
||||||
|
ut_asserteq(0, run_command("bootflow cmdline get mary", 0));
|
||||||
|
ut_assert_nextline_empty();
|
||||||
|
|
||||||
|
ut_assert_console_end();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
BOOTSTD_TEST(bootflow_cmdline, 0);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue