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