3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * See file CREDITS for list of people who contributed to this
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
27 #if defined(CFG_HUSH_PARSER)
31 #if defined(CONFIG_SILENT_CONSOLE)
32 DECLARE_GLOBAL_DATA_PTR;
35 #define MAX_STOPSTR_LEN 16
37 static char *delete_char(char *buffer, char *p, int *colp, int *np, int plen);
38 static int parse_line(char *, char *[]);
40 char console_buffer[CFG_CBSIZE]; /* console I/O buffer */
41 static char erase_seq[] = "\b \b"; /* erase sequence */
42 static char tab_seq[] = " "; /* used to expand TABs */
45 * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
46 * returns: 0 - no key string, allow autoboot
47 * 1 - got key string, abort
49 #if defined(CONFIG_BOOTDELAY) &&\
50 (CONFIG_BOOTDELAY >= 0)
51 static __inline__ int abortboot(int bootdelay)
56 int envstopstr_len = 0;
60 char stopstr[MAX_STOPSTR_LEN] = { 0 };
62 #if defined(CONFIG_SILENT_CONSOLE)
63 if (gd->flags & GD_FLG_SILENT) {
64 /* Restore serial console */
65 console_assign(stdout, "serial");
66 console_assign(stderr, "serial");
73 /* Check value of 'bootstopkey' and just ignore it if it's over limit */
74 envstopstr = getenv("bootstopkey");
76 envstopstr_len = strlen(envstopstr);
78 if (envstopstr_len > MAX_STOPSTR_LEN)
82 #if defined(CONFIG_MENUPROMPT)
83 printf(CONFIG_MENUPROMPT, bootdelay);
86 * Use custom CONFIG_MENUPROMPT if bootstopkey
87 * string contains nonprintable characters (e.g. ESC)
90 printf("Enter '%s' to stop booting: %2d", envstopstr, bootdelay);
92 printf("Hit any key to stop booting: %2d", bootdelay);
95 while ((bootdelay > 0) && (!abort)) {
100 /* delay 500 * 2 ms */
101 for (i = 0; !abort && i < 500; ++i, udelay(2000)) {
102 if (!tstc() || tested)
110 /* Interrupt by any key if bootstopkey isn't used */
117 /* Consume characters up to the strlen(envstopstr) */
118 if (stopstr_len < envstopstr_len)
119 stopstr[stopstr_len++] = c;
121 if (stopstr_len == envstopstr_len) {
123 if (memcmp(envstopstr, stopstr,
124 envstopstr_len) == 0) {
132 printf("\b\b%2d", bootdelay);
136 #if defined(CONFIG_SILENT_CONSOLE)
138 /* Permanently enable normal console output */
139 gd->flags &= ~(GD_FLG_SILENT);
140 } else if (gd->flags & GD_FLG_SILENT) {
141 /* Restore silent console */
142 console_assign(stdout, "nulldev");
143 console_assign(stderr, "nulldev");
149 #endif /* CONFIG_BOOTDELAY && CONFIG_BOOTDELAY >= 0 */
160 #if defined(CONFIG_BTN_RECOVERY_SCRIPT)
165 #ifndef CFG_HUSH_PARSER
166 static char lastcommand[CFG_CBSIZE] = { 0, };
171 #if defined(CONFIG_BOOTDELAY) &&\
172 (CONFIG_BOOTDELAY >= 0)
177 #if defined(CFG_HUSH_PARSER)
181 /* Get boot command */
182 bootcmd = getenv("bootcmd");
184 #if defined(CONFIG_BOOTCOMMAND)
186 setenv("bootcmd", CONFIG_BOOTCOMMAND);
188 bootcmd = getenv("bootcmd");
191 /* Recovery mode before normal boot */
192 #if defined(CONFIG_BTN_RECOVERY_SCRIPT)
193 if (reset_button_status()) {
194 #if defined(CONFIG_SILENT_CONSOLE)
195 if (gd->flags & GD_FLG_SILENT) {
196 /* Restore serial console */
197 console_assign(stdout, "serial");
198 console_assign(stderr, "serial");
201 /* Enable normal console output */
202 gd->flags &= ~(GD_FLG_SILENT);
205 /* Do we have recovery script in env var at all? */
206 c = getenv("recovery");
208 printf_wrn("recovery script is missing\n"
209 " in env, use 'defenv' to reset env\n\n");
212 * Always clear values of variables used in recovery
213 * script as they could be accidentally saved before
215 setenv("stop_boot", NULL);
218 run_command("run recovery", 0);
220 /* Should we stop booting after recovery mode? */
221 c = getenv("stop_boot");
222 stop_boot = c ? (int)simple_strtol(c, NULL, 10) : 0;
225 setenv("stop_boot", NULL);
232 #endif /* CONFIG_RECOVERY_MODE */
234 #if defined(CONFIG_BOOTDELAY) &&\
235 (CONFIG_BOOTDELAY >= 0)
236 /* Get boot delay (seconds) */
237 s = getenv("bootdelay");
238 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
240 if (bootdelay >= 0 && bootcmd && !abortboot(bootdelay)) {
242 #ifndef CFG_HUSH_PARSER
243 run_command(bootcmd, 0);
245 parse_string_outer(bootcmd, FLAG_PARSE_SEMICOLON |
246 FLAG_EXIT_FROM_LOOP);
252 #ifndef CFG_HUSH_PARSER
253 run_command(bootcmd, 0);
255 parse_string_outer(bootcmd, FLAG_PARSE_SEMICOLON |
256 FLAG_EXIT_FROM_LOOP);
259 #endif /* CONFIG_BOOTDELAY && CONFIG_BOOTDELAY >= 0 */
261 /* Main loop for monitor command processing */
262 #if defined(CFG_HUSH_PARSER)
265 /* This point is never reached */
270 len = readline(CFG_PROMPT);
272 /* Assume no special flags for now */
276 strcpy(lastcommand, console_buffer);
278 flag |= CMD_FLAG_REPEAT;
281 puts("<INTERRUPT>\n");
283 rc = run_command(lastcommand, flag);
285 /* Invalid command or not repeatable, forget it */
289 #endif /* CFG_HUSH_PARSER */
293 * Prompt for input and read a line.
294 * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
295 * time out when time goes past endtime (timebase time in ticks).
296 * Return: number of read characters
300 int readline(const char * const prompt)
302 char *p = console_buffer;
303 int plen = 0; /* prompt length */
304 int n = 0; /* buffer index */
305 int col; /* output column cnt */
310 plen = strlen(prompt);
318 /* Special character handling */
325 return p - console_buffer;
332 console_buffer[0] = '\0';
334 /* ^U - erase line */
345 /* ^W - erase word */
347 p = delete_char(console_buffer, p, &col, &n, plen);
348 while ((n > 0) && (*p != ' '))
349 p = delete_char(console_buffer, p, &col, &n, plen);
353 /* DEL - backspace */
356 p = delete_char(console_buffer, p, &col, &n, plen);
358 /* Must be a normal character then */
360 if (n < CFG_CBSIZE - 2) {
363 puts(tab_seq + (col & 07));
364 col += 8 - (col & 07);
381 static char *delete_char(char *buffer,
392 if (*(--p) == '\t') {
393 /* Will retype the whole line */
394 while (*colp > plen) {
399 for (s = buffer; s < p; ++s) {
401 puts(tab_seq + ((*colp) & 07));
402 *colp += 8 - ((*colp) & 07);
417 int parse_line(char *line, char *argv[])
421 while (nargs < CFG_MAXARGS) {
422 /* Skip any white space */
423 while ((*line == ' ') || (*line == '\t'))
426 /* End of line, no more args */
432 /* Begin of argument string */
433 argv[nargs++] = line;
435 /* Find end of string */
436 while (*line && (*line != ' ') && (*line != '\t'))
439 /* End of line, no more args */
445 /* Terminate current arg */
449 printf_err("too many args (max. %d)\n", CFG_MAXARGS);
454 static void process_macros(const char *input, char *output)
456 const char *varname_start = NULL;
457 int inputcnt = strlen(input);
458 int outputcnt = CFG_CBSIZE;
460 int state = 0; /* 0 = waiting for '$'
461 1 = waiting for '(' or '{'
462 2 = waiting for ')' or '}'
463 3 = waiting for ''' */
465 /* Previous character */
468 while (inputcnt && outputcnt) {
473 /* Remove one level of escape characters */
474 if ((c == '\\') && (prev != '\\')) {
484 /* Waiting for (unescaped) $ */
486 if ((c == '\'') && (prev != '\\')) {
491 if ((c == '$') && (prev != '\\')) {
501 if (c == '(' || c == '{') {
503 varname_start = input;
518 if (c == ')' || c == '}') {
519 int envcnt = input - varname_start - 1; /* Varname # of chars */
520 char envname[CFG_CBSIZE], *envval;
523 /* Get the varname */
524 for (i = 0; i < envcnt; i++)
525 envname[i] = varname_start[i];
530 envval = getenv(envname);
532 /* Copy into the line if it exists */
533 if (envval != NULL) {
534 while ((*envval) && outputcnt) {
535 *(output++) = *(envval++);
540 /* Look for another '$' */
547 if ((c == '\'') && (prev != '\\')) {
566 * 1 - command executed, repeatable
567 * 0 - command executed but not repeatable, interrupted commands are
568 * always considered not repeatable
569 * -1 - not executed (unrecognized, bootd recursion or too many args)
570 * (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
571 * considered unrecognized)
575 * We must create a temporary copy of the command since the command we get
576 * may be the result from getenv(), which returns a pointer directly to
577 * the environment data, which may change magicly when the command we run
578 * creates or modifies environment variables (like "bootp" does).
581 int run_command(const char *cmd, int flag){
583 char *argv[CFG_MAXARGS + 1]; /* NULL terminated */
584 char cmdbuf[CFG_CBSIZE]; /* Working copy of cmd */
585 char *token; /* Start of token in cmdbuf */
586 char *sep; /* End of token (separator) in cmdbuf */
587 char finaltoken[CFG_CBSIZE];
593 /* Forget any previous Control-C */
600 if (strlen(cmd) >= CFG_CBSIZE) {
601 printf_err("command too long!\n");
607 /* Process separators and check for invalid repeatable commands */
610 * Find separator, or string end
611 * Allow simple escape of ';' by writing "\;"
613 for (inquotes = 0, sep = str; *sep; sep++) {
614 if ((*sep == '\'') && (*(sep - 1) != '\\'))
615 inquotes = !inquotes;
617 if(!inquotes && (*sep == ';')
618 && (sep != str) && (*(sep - 1) != '\\'))
622 /* Limit the token to data between separators */
626 /* Start of command for next pass */
630 /* No more commands for next pass */
634 /* Find macros in this token and replace them */
635 process_macros(token, finaltoken);
637 /* Extract arguments */
638 if ((argc = parse_line(finaltoken, argv)) == 0) {
639 /* No command at all */
644 /* Look up command in command table */
645 if ((cmdtp = find_cmd(argv[0])) == NULL) {
646 printf_err("unknown command '%s' - try 'help'\n", argv[0]);
649 /* Give up after bad command */
654 /* Found - check max args */
655 if (argc > cmdtp->maxargs) {
656 print_cmd_help(cmdtp);
658 /* Give up if too many args */
663 /* OK - call function to do the command */
664 if ((cmdtp->cmd)(cmdtp, flag, argc, argv) != 0)
667 repeatable &= cmdtp->repeatable;
669 /* Did the user stop this? If stopped then not repeatable */
674 return rc ? rc : repeatable;
677 #if defined(CONFIG_CMD_RUN)
678 int do_run(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
683 print_cmd_help(cmdtp);
687 for (i=1; i<argc; ++i) {
690 if ((arg = getenv(argv[i])) == NULL) {
691 printf_err("'%s' not defined\n", argv[i]);
695 #ifndef CFG_HUSH_PARSER
696 if (run_command(arg, flag) == -1)
699 if (parse_string_outer(arg, FLAG_PARSE_SEMICOLON |
700 FLAG_EXIT_FROM_LOOP) != 0)
707 #endif /* CONFIG_CMD_RUN */