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