uboot/common/cli.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2000
   4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   5 *
   6 * Add to readline cmdline-editing by
   7 * (C) Copyright 2005
   8 * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
   9 */
  10
  11#include <common.h>
  12#include <bootstage.h>
  13#include <cli.h>
  14#include <cli_hush.h>
  15#include <command.h>
  16#include <console.h>
  17#include <env.h>
  18#include <fdtdec.h>
  19#include <hang.h>
  20#include <malloc.h>
  21#include <asm/global_data.h>
  22#include <dm/ofnode.h>
  23
  24#ifdef CONFIG_CMDLINE
  25/*
  26 * Run a command using the selected parser.
  27 *
  28 * @param cmd   Command to run
  29 * @param flag  Execution flags (CMD_FLAG_...)
  30 * @return 0 on success, or != 0 on error.
  31 */
  32int run_command(const char *cmd, int flag)
  33{
  34#if !CONFIG_IS_ENABLED(HUSH_PARSER)
  35        /*
  36         * cli_run_command can return 0 or 1 for success, so clean up
  37         * its result.
  38         */
  39        if (cli_simple_run_command(cmd, flag) == -1)
  40                return 1;
  41
  42        return 0;
  43#else
  44        int hush_flags = FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP;
  45
  46        if (flag & CMD_FLAG_ENV)
  47                hush_flags |= FLAG_CONT_ON_NEWLINE;
  48        return parse_string_outer(cmd, hush_flags);
  49#endif
  50}
  51
  52/*
  53 * Run a command using the selected parser, and check if it is repeatable.
  54 *
  55 * @param cmd   Command to run
  56 * @param flag  Execution flags (CMD_FLAG_...)
  57 * @return 0 (not repeatable) or 1 (repeatable) on success, -1 on error.
  58 */
  59int run_command_repeatable(const char *cmd, int flag)
  60{
  61#ifndef CONFIG_HUSH_PARSER
  62        return cli_simple_run_command(cmd, flag);
  63#else
  64        /*
  65         * parse_string_outer() returns 1 for failure, so clean up
  66         * its result.
  67         */
  68        if (parse_string_outer(cmd,
  69                               FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP))
  70                return -1;
  71
  72        return 0;
  73#endif
  74}
  75#else
  76__weak int board_run_command(const char *cmdline)
  77{
  78        printf("## Commands are disabled. Please enable CONFIG_CMDLINE.\n");
  79
  80        return 1;
  81}
  82#endif /* CONFIG_CMDLINE */
  83
  84int run_command_list(const char *cmd, int len, int flag)
  85{
  86        int need_buff = 1;
  87        char *buff = (char *)cmd;       /* cast away const */
  88        int rcode = 0;
  89
  90        if (len == -1) {
  91                len = strlen(cmd);
  92#ifdef CONFIG_HUSH_PARSER
  93                /* hush will never change our string */
  94                need_buff = 0;
  95#else
  96                /* the built-in parser will change our string if it sees \n */
  97                need_buff = strchr(cmd, '\n') != NULL;
  98#endif
  99        }
 100        if (need_buff) {
 101                buff = malloc(len + 1);
 102                if (!buff)
 103                        return 1;
 104                memcpy(buff, cmd, len);
 105                buff[len] = '\0';
 106        }
 107#ifdef CONFIG_HUSH_PARSER
 108        rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
 109#else
 110        /*
 111         * This function will overwrite any \n it sees with a \0, which
 112         * is why it can't work with a const char *. Here we are making
 113         * using of internal knowledge of this function, to avoid always
 114         * doing a malloc() which is actually required only in a case that
 115         * is pretty rare.
 116         */
 117#ifdef CONFIG_CMDLINE
 118        rcode = cli_simple_run_command_list(buff, flag);
 119#else
 120        rcode = board_run_command(buff);
 121#endif
 122#endif
 123        if (need_buff)
 124                free(buff);
 125
 126        return rcode;
 127}
 128
 129/****************************************************************************/
 130
 131#if defined(CONFIG_CMD_RUN)
 132int do_run(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 133{
 134        int i;
 135
 136        if (argc < 2)
 137                return CMD_RET_USAGE;
 138
 139        for (i = 1; i < argc; ++i) {
 140                char *arg;
 141
 142                arg = env_get(argv[i]);
 143                if (arg == NULL) {
 144                        printf("## Error: \"%s\" not defined\n", argv[i]);
 145                        return 1;
 146                }
 147
 148                if (run_command(arg, flag | CMD_FLAG_ENV) != 0)
 149                        return 1;
 150        }
 151        return 0;
 152}
 153#endif
 154
 155#if CONFIG_IS_ENABLED(OF_CONTROL)
 156bool cli_process_fdt(const char **cmdp)
 157{
 158        /* Allow the fdt to override the boot command */
 159        const char *env = ofnode_conf_read_str("bootcmd");
 160        if (env)
 161                *cmdp = env;
 162        /*
 163         * If the bootsecure option was chosen, use secure_boot_cmd().
 164         * Always use 'env' in this case, since bootsecure requres that the
 165         * bootcmd was specified in the FDT too.
 166         */
 167        return ofnode_conf_read_int("bootsecure", 0);
 168}
 169
 170/*
 171 * Runs the given boot command securely.  Specifically:
 172 * - Doesn't run the command with the shell (run_command or parse_string_outer),
 173 *   since that's a lot of code surface that an attacker might exploit.
 174 *   Because of this, we don't do any argument parsing--the secure boot command
 175 *   has to be a full-fledged u-boot command.
 176 * - Doesn't check for keypresses before booting, since that could be a
 177 *   security hole; also disables Ctrl-C.
 178 * - Doesn't allow the command to return.
 179 *
 180 * Upon any failures, this function will drop into an infinite loop after
 181 * printing the error message to console.
 182 */
 183void cli_secure_boot_cmd(const char *cmd)
 184{
 185#ifdef CONFIG_CMDLINE
 186        struct cmd_tbl *cmdtp;
 187#endif
 188        int rc;
 189
 190        if (!cmd) {
 191                printf("## Error: Secure boot command not specified\n");
 192                goto err;
 193        }
 194
 195        /* Disable Ctrl-C just in case some command is used that checks it. */
 196        disable_ctrlc(1);
 197
 198        /* Find the command directly. */
 199#ifdef CONFIG_CMDLINE
 200        cmdtp = find_cmd(cmd);
 201        if (!cmdtp) {
 202                printf("## Error: \"%s\" not defined\n", cmd);
 203                goto err;
 204        }
 205
 206        /* Run the command, forcing no flags and faking argc and argv. */
 207        rc = (cmdtp->cmd)(cmdtp, 0, 1, (char **)&cmd);
 208
 209#else
 210        rc = board_run_command(cmd);
 211#endif
 212
 213        /* Shouldn't ever return from boot command. */
 214        printf("## Error: \"%s\" returned (code %d)\n", cmd, rc);
 215
 216err:
 217        /*
 218         * Not a whole lot to do here.  Rebooting won't help much, since we'll
 219         * just end up right back here.  Just loop.
 220         */
 221        hang();
 222}
 223#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
 224
 225void cli_loop(void)
 226{
 227        bootstage_mark(BOOTSTAGE_ID_ENTER_CLI_LOOP);
 228#ifdef CONFIG_HUSH_PARSER
 229        parse_file_outer();
 230        /* This point is never reached */
 231        for (;;);
 232#elif defined(CONFIG_CMDLINE)
 233        cli_simple_loop();
 234#else
 235        printf("## U-Boot command line is disabled. Please enable CONFIG_CMDLINE\n");
 236#endif /*CONFIG_HUSH_PARSER*/
 237}
 238
 239void cli_init(void)
 240{
 241#ifdef CONFIG_HUSH_PARSER
 242        u_boot_hush_start();
 243#endif
 244
 245#if defined(CONFIG_HUSH_INIT_VAR)
 246        hush_init_var();
 247#endif
 248}
 249