"Das U-Boot" Source Tree
at master 348 lines 7.6 kB view raw
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 <bootretry.h> 12#include <cli.h> 13#include <command.h> 14#include <console.h> 15#include <env.h> 16#include <log.h> 17#include <linux/ctype.h> 18 19#define DEBUG_PARSER 0 /* set to 1 to debug */ 20 21#define debug_parser(fmt, args...) \ 22 debug_cond(DEBUG_PARSER, fmt, ##args) 23 24int cli_simple_process_macros(const char *input, char *output, int max_size) 25{ 26 char c, prev; 27 const char *varname_start = NULL; 28 int inputcnt = strlen(input); 29 int outputcnt = max_size; 30 int state = 0; /* 0 = waiting for '$' */ 31 int ret; 32 33 /* 1 = waiting for '(' or '{' */ 34 /* 2 = waiting for ')' or '}' */ 35 /* 3 = waiting for ''' */ 36 char __maybe_unused *output_start = output; 37 38 debug_parser("[PROCESS_MACROS] INPUT len %zd: \"%s\"\n", strlen(input), 39 input); 40 41 prev = '\0'; /* previous character */ 42 43 while (inputcnt && outputcnt) { 44 c = *input++; 45 inputcnt--; 46 47 if (state != 3) { 48 /* remove one level of escape characters */ 49 if ((c == '\\') && (prev != '\\')) { 50 if (inputcnt-- == 0) 51 break; 52 prev = c; 53 c = *input++; 54 } 55 } 56 57 switch (state) { 58 case 0: /* Waiting for (unescaped) $ */ 59 if ((c == '\'') && (prev != '\\')) { 60 state = 3; 61 break; 62 } 63 if ((c == '$') && (prev != '\\')) { 64 state++; 65 } else { 66 *(output++) = c; 67 outputcnt--; 68 } 69 break; 70 case 1: /* Waiting for ( */ 71 if (c == '(' || c == '{') { 72 state++; 73 varname_start = input; 74 } else { 75 state = 0; 76 *(output++) = '$'; 77 outputcnt--; 78 79 if (outputcnt) { 80 *(output++) = c; 81 outputcnt--; 82 } 83 } 84 break; 85 case 2: /* Waiting for ) */ 86 if (c == ')' || c == '}') { 87 int i; 88 char envname[CONFIG_SYS_CBSIZE], *envval; 89 /* Varname # of chars */ 90 int envcnt = input - varname_start - 1; 91 92 /* Get the varname */ 93 for (i = 0; i < envcnt; i++) 94 envname[i] = varname_start[i]; 95 envname[i] = 0; 96 97 /* Get its value */ 98 envval = env_get(envname); 99 100 /* Copy into the line if it exists */ 101 if (envval != NULL) 102 while ((*envval) && outputcnt) { 103 *(output++) = *(envval++); 104 outputcnt--; 105 } 106 /* Look for another '$' */ 107 state = 0; 108 } 109 break; 110 case 3: /* Waiting for ' */ 111 if ((c == '\'') && (prev != '\\')) { 112 state = 0; 113 } else { 114 *(output++) = c; 115 outputcnt--; 116 } 117 break; 118 } 119 prev = c; 120 } 121 122 ret = inputcnt ? -ENOSPC : 0; 123 if (outputcnt) { 124 *output = 0; 125 } else { 126 *(output - 1) = 0; 127 ret = -ENOSPC; 128 } 129 130 debug_parser("[PROCESS_MACROS] OUTPUT len %zd: \"%s\"\n", 131 strlen(output_start), output_start); 132 133 return ret; 134} 135 136#ifdef CONFIG_CMDLINE 137int cli_simple_parse_line(char *line, char *argv[]) 138{ 139 int nargs = 0; 140 141 debug_parser("%s: \"%s\"\n", __func__, line); 142 while (nargs < CONFIG_SYS_MAXARGS) { 143 /* skip any white space */ 144 while (isblank(*line)) 145 ++line; 146 147 if (*line == '\0') { /* end of line, no more args */ 148 argv[nargs] = NULL; 149 debug_parser("%s: nargs=%d\n", __func__, nargs); 150 return nargs; 151 } 152 153 argv[nargs++] = line; /* begin of argument string */ 154 155 /* find end of string */ 156 while (*line && !isblank(*line)) 157 ++line; 158 159 if (*line == '\0') { /* end of line, no more args */ 160 argv[nargs] = NULL; 161 debug_parser("parse_line: nargs=%d\n", nargs); 162 return nargs; 163 } 164 165 *line++ = '\0'; /* terminate current arg */ 166 } 167 168 printf("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS); 169 170 debug_parser("%s: nargs=%d\n", __func__, nargs); 171 return nargs; 172} 173 174 /* 175 * WARNING: 176 * 177 * We must create a temporary copy of the command since the command we get 178 * may be the result from env_get(), which returns a pointer directly to 179 * the environment data, which may change magicly when the command we run 180 * creates or modifies environment variables (like "bootp" does). 181 */ 182int cli_simple_run_command(const char *cmd, int flag) 183{ 184 char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */ 185 char *token; /* start of token in cmdbuf */ 186 char *sep; /* end of token (separator) in cmdbuf */ 187 char finaltoken[CONFIG_SYS_CBSIZE]; 188 char *str = cmdbuf; 189 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */ 190 int argc, inquotes; 191 int repeatable = 1; 192 int rc = 0; 193 194 debug_parser("[RUN_COMMAND] cmd[%p]=\"", cmd); 195 if (DEBUG_PARSER) { 196 /* use puts - string may be loooong */ 197 puts(cmd ? cmd : "NULL"); 198 puts("\"\n"); 199 } 200 clear_ctrlc(); /* forget any previous Control C */ 201 202 if (!cmd || !*cmd) 203 return -1; /* empty command */ 204 205 if (strlen(cmd) >= CONFIG_SYS_CBSIZE) { 206 puts("## Command too long!\n"); 207 return -1; 208 } 209 210 strcpy(cmdbuf, cmd); 211 212 /* Process separators and check for invalid 213 * repeatable commands 214 */ 215 216 debug_parser("[PROCESS_SEPARATORS] %s\n", cmd); 217 while (*str) { 218 /* 219 * Find separator, or string end 220 * Allow simple escape of ';' by writing "\;" 221 */ 222 for (inquotes = 0, sep = str; *sep; sep++) { 223 if ((*sep == '\'') && 224 (*(sep - 1) != '\\')) 225 inquotes = !inquotes; 226 227 if (!inquotes && 228 (*sep == ';') && /* separator */ 229 (sep != str) && /* past string start */ 230 (*(sep - 1) != '\\')) /* and NOT escaped */ 231 break; 232 } 233 234 /* 235 * Limit the token to data between separators 236 */ 237 token = str; 238 if (*sep) { 239 str = sep + 1; /* start of command for next pass */ 240 *sep = '\0'; 241 } else { 242 str = sep; /* no more commands for next pass */ 243 } 244 debug_parser("token: \"%s\"\n", token); 245 246 /* find macros in this token and replace them */ 247 cli_simple_process_macros(token, finaltoken, 248 sizeof(finaltoken)); 249 250 /* Extract arguments */ 251 argc = cli_simple_parse_line(finaltoken, argv); 252 if (argc == 0) { 253 rc = -1; /* no command at all */ 254 continue; 255 } 256 257 if (cmd_process(flag, argc, argv, &repeatable, NULL)) 258 rc = -1; 259 260 /* Did the user stop this? */ 261 if (had_ctrlc()) 262 return -1; /* if stopped then not repeatable */ 263 } 264 265 return rc ? rc : repeatable; 266} 267 268void cli_simple_loop(void) 269{ 270 static char lastcommand[CONFIG_SYS_CBSIZE + 1] = { 0, }; 271 272 int len; 273 int flag; 274 int rc = 1; 275 276 for (;;) { 277 if (rc >= 0) { 278 /* Saw enough of a valid command to 279 * restart the timeout. 280 */ 281 bootretry_reset_cmd_timeout(); 282 } 283 len = cli_readline(CONFIG_SYS_PROMPT); 284 285 flag = 0; /* assume no special flags for now */ 286 if (len > 0) 287 strlcpy(lastcommand, console_buffer, 288 CONFIG_SYS_CBSIZE + 1); 289 else if (len == 0) 290 flag |= CMD_FLAG_REPEAT; 291#ifdef CONFIG_BOOT_RETRY_TIME 292 else if (len == -2) { 293 /* -2 means timed out, retry autoboot 294 */ 295 puts("\nTimed out waiting for command\n"); 296# ifdef CONFIG_RESET_TO_RETRY 297 /* Reinit board to run initialization code again */ 298 do_reset(NULL, 0, 0, NULL); 299# else 300 return; /* retry autoboot */ 301# endif 302 } 303#endif 304 305 if (len == -1) 306 puts("<INTERRUPT>\n"); 307 else 308 rc = run_command_repeatable(lastcommand, flag); 309 310 if (rc <= 0) { 311 /* invalid command or not repeatable, forget it */ 312 lastcommand[0] = 0; 313 } 314 } 315} 316 317int cli_simple_run_command_list(char *cmd, int flag) 318{ 319 char *line, *next; 320 int rcode = 0; 321 322 /* 323 * Break into individual lines, and execute each line; terminate on 324 * error. 325 */ 326 next = cmd; 327 line = cmd; 328 while (*next) { 329 if (*next == '\n') { 330 *next = '\0'; 331 /* run only non-empty commands */ 332 if (*line) { 333 debug("** exec: \"%s\"\n", line); 334 if (cli_simple_run_command(line, 0) < 0) { 335 rcode = 1; 336 break; 337 } 338 } 339 line = next + 1; 340 } 341 ++next; 342 } 343 if (rcode == 0 && *line) 344 rcode = (cli_simple_run_command(line, 0) < 0); 345 346 return rcode; 347} 348#endif