blob: 9ee32a58046e1fa43669607fa2be36b2845810b7 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * (C) Copyright 2000
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
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.
12 *
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.
17 *
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,
21 * MA 02111-1307 USA
22 */
23
wdenka6c7ad22002-12-03 21:28:10 +000024/* #define DEBUG */
25
wdenkc6097192002-11-03 00:24:07 +000026#include <common.h>
27#include <watchdog.h>
28#include <command.h>
29#include <cmd_nvedit.h>
30#include <cmd_bootm.h>
31#include <malloc.h>
32#if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY)
33#include <cmd_boot.h> /* for do_reset() prototype */
34#endif
35
36#ifdef CFG_HUSH_PARSER
37#include <hush.h>
38#endif
39
40#define MAX_DELAY_STOP_STR 32
41
42static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
43static int parse_line (char *, char *[]);
44#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
45static int abortboot(int);
46#endif
47
48#undef DEBUG_PARSER
49
50char console_buffer[CFG_CBSIZE]; /* console I/O buffer */
51
52static char erase_seq[] = "\b \b"; /* erase sequence */
53static char tab_seq[] = " "; /* used to expand TABs */
54
55#ifdef CONFIG_BOOT_RETRY_TIME
56static uint64_t endtime = 0; /* must be set, default is instant timeout */
57static int retry_time = -1; /* -1 so can call readline before main_loop */
58#endif
59
60#define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
61
62#ifndef CONFIG_BOOT_RETRY_MIN
63#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
64#endif
65
66#ifdef CONFIG_MODEM_SUPPORT
67int do_mdm_init = 0;
68extern void mdm_init(void); /* defined in board.c */
69#endif
70
71/***************************************************************************
72 * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
73 * returns: 0 - no key string, allow autoboot
74 * 1 - got key string, abort
75 */
76#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
77# if defined(CONFIG_AUTOBOOT_KEYED)
78static __inline__ int abortboot(int bootdelay)
79{
80 int abort = 0;
81 uint64_t etime = endtick(bootdelay);
82 struct
83 {
84 char* str;
85 u_int len;
86 int retry;
87 }
88 delaykey [] =
89 {
90 { str: getenv ("bootdelaykey"), retry: 1 },
91 { str: getenv ("bootdelaykey2"), retry: 1 },
92 { str: getenv ("bootstopkey"), retry: 0 },
93 { str: getenv ("bootstopkey2"), retry: 0 },
94 };
95
96 char presskey [MAX_DELAY_STOP_STR];
97 u_int presskey_len = 0;
98 u_int presskey_max = 0;
99 u_int i;
100
101# ifdef CONFIG_AUTOBOOT_PROMPT
102 printf (CONFIG_AUTOBOOT_PROMPT, bootdelay);
103# endif
104
105# ifdef CONFIG_AUTOBOOT_DELAY_STR
106 if (delaykey[0].str == NULL)
107 delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
108# endif
109# ifdef CONFIG_AUTOBOOT_DELAY_STR2
110 if (delaykey[1].str == NULL)
111 delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
112# endif
113# ifdef CONFIG_AUTOBOOT_STOP_STR
114 if (delaykey[2].str == NULL)
115 delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
116# endif
117# ifdef CONFIG_AUTOBOOT_STOP_STR2
118 if (delaykey[3].str == NULL)
119 delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
120# endif
121
122 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
123 delaykey[i].len = delaykey[i].str == NULL ?
124 0 : strlen (delaykey[i].str);
125 delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
126 MAX_DELAY_STOP_STR : delaykey[i].len;
127
128 presskey_max = presskey_max > delaykey[i].len ?
129 presskey_max : delaykey[i].len;
130
131# if DEBUG_BOOTKEYS
132 printf("%s key:<%s>\n",
133 delaykey[i].retry ? "delay" : "stop",
134 delaykey[i].str ? delaykey[i].str : "NULL");
135# endif
136 }
137
138 /* In order to keep up with incoming data, check timeout only
139 * when catch up.
140 */
141 while (!abort && get_ticks() <= etime) {
142 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
143 if (delaykey[i].len > 0 &&
144 presskey_len >= delaykey[i].len &&
145 memcmp (presskey + presskey_len - delaykey[i].len,
146 delaykey[i].str,
147 delaykey[i].len) == 0) {
148# if DEBUG_BOOTKEYS
149 printf("got %skey\n",
150 delaykey[i].retry ? "delay" : "stop");
151# endif
152
153# ifdef CONFIG_BOOT_RETRY_TIME
154 /* don't retry auto boot */
155 if (! delaykey[i].retry)
156 retry_time = -1;
157# endif
158 abort = 1;
159 }
160 }
161
162 if (tstc()) {
163 if (presskey_len < presskey_max) {
164 presskey [presskey_len ++] = getc();
165 }
166 else {
167 for (i = 0; i < presskey_max - 1; i ++)
168 presskey [i] = presskey [i + 1];
169
170 presskey [i] = getc();
171 }
172 }
173 }
174# if DEBUG_BOOTKEYS
175 if (!abort)
176 printf("key timeout\n");
177# endif
178
179 return abort;
180}
181
182# else /* !defined(CONFIG_AUTOBOOT_KEYED) */
183
wdenkc7de8292002-11-19 11:04:11 +0000184#ifdef CONFIG_MENUKEY
185static int menukey = 0;
186#endif
187
wdenkc6097192002-11-03 00:24:07 +0000188static __inline__ int abortboot(int bootdelay)
189{
190 int abort = 0;
191
wdenkc7de8292002-11-19 11:04:11 +0000192#ifdef CONFIG_MENUPROMPT
193 printf(CONFIG_MENUPROMPT, bootdelay);
194#else
wdenkc6097192002-11-03 00:24:07 +0000195 printf("Hit any key to stop autoboot: %2d ", bootdelay);
wdenkc7de8292002-11-19 11:04:11 +0000196#endif
wdenkc6097192002-11-03 00:24:07 +0000197
198#if defined CONFIG_ZERO_BOOTDELAY_CHECK
199 /*
200 * Check if key already pressed
201 * Don't check if bootdelay < 0
202 */
203 if (bootdelay >= 0) {
204 if (tstc()) { /* we got a key press */
205 (void) getc(); /* consume input */
206 printf ("\b\b\b 0\n");
207 return 1; /* don't auto boot */
208 }
209 }
210#endif
211
212 while (bootdelay > 0) {
213 int i;
214
215 --bootdelay;
216 /* delay 100 * 10ms */
217 for (i=0; !abort && i<100; ++i) {
218 if (tstc()) { /* we got a key press */
219 abort = 1; /* don't auto boot */
220 bootdelay = 0; /* no more delay */
wdenkc7de8292002-11-19 11:04:11 +0000221# ifdef CONFIG_MENUKEY
222 menukey = getc();
223# else
wdenkc6097192002-11-03 00:24:07 +0000224 (void) getc(); /* consume input */
wdenkc7de8292002-11-19 11:04:11 +0000225# endif
wdenkc6097192002-11-03 00:24:07 +0000226 break;
227 }
228 udelay (10000);
229 }
230
231 printf ("\b\b\b%2d ", bootdelay);
232 }
233
234 putc ('\n');
235
236 return abort;
237}
238# endif /* CONFIG_AUTOBOOT_KEYED */
239#endif /* CONFIG_BOOTDELAY >= 0 */
240
241/****************************************************************************/
242
243void main_loop (void)
244{
245#ifndef CFG_HUSH_PARSER
246 static char lastcommand[CFG_CBSIZE] = { 0, };
247 int len;
248 int rc = 1;
249 int flag;
250#endif
251
252#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
253 char *s;
254 int bootdelay;
255#endif
256#ifdef CONFIG_PREBOOT
257 char *p;
258#endif
259
260#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
261 ulong bmp = 0; /* default bitmap */
262 extern int trab_vfd (ulong bitmap);
263
264#ifdef CONFIG_MODEM_SUPPORT
265 if (do_mdm_init)
266 bmp = 1; /* alternate bitmap */
267#endif
268 trab_vfd (bmp);
269#endif /* CONFIG_VFD && VFD_TEST_LOGO */
270
271#ifdef CONFIG_MODEM_SUPPORT
272 debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
273 if (do_mdm_init) {
274 uchar *str = strdup(getenv("mdm_cmd"));
275 setenv ("preboot", str); /* set or delete definition */
276 if (str != NULL)
277 free (str);
278 mdm_init(); /* wait for modem connection */
279 }
280#endif /* CONFIG_MODEM_SUPPORT */
281
282#ifdef CFG_HUSH_PARSER
283 u_boot_hush_start ();
284#endif
285
286#ifdef CONFIG_PREBOOT
287 if ((p = getenv ("preboot")) != NULL) {
288# ifdef CONFIG_AUTOBOOT_KEYED
289 int prev = disable_ctrlc(1); /* disable Control C checking */
290# endif
291
292# ifndef CFG_HUSH_PARSER
293 run_command (p, 0);
294# else
295 parse_string_outer(p, FLAG_PARSE_SEMICOLON |
296 FLAG_EXIT_FROM_LOOP);
297# endif
298
299# ifdef CONFIG_AUTOBOOT_KEYED
300 disable_ctrlc(prev); /* restore Control C checking */
301# endif
302 }
303#endif /* CONFIG_PREBOOT */
304
305#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
306 s = getenv ("bootdelay");
307 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
308
wdenka6c7ad22002-12-03 21:28:10 +0000309 debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
wdenkc6097192002-11-03 00:24:07 +0000310
311# ifdef CONFIG_BOOT_RETRY_TIME
312 s = getenv ("bootretry");
313 if (s != NULL)
314 retry_time = (int)simple_strtoul(s, NULL, 10);
315 else
316 retry_time = CONFIG_BOOT_RETRY_TIME;
317 if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
318 retry_time = CONFIG_BOOT_RETRY_MIN;
319# endif /* CONFIG_BOOT_RETRY_TIME */
320
321 s = getenv ("bootcmd");
wdenka6c7ad22002-12-03 21:28:10 +0000322
323 debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
324
wdenkc6097192002-11-03 00:24:07 +0000325 if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
326# ifdef CONFIG_AUTOBOOT_KEYED
327 int prev = disable_ctrlc(1); /* disable Control C checking */
328# endif
329
330# ifndef CFG_HUSH_PARSER
331 run_command (s, 0);
332# else
333 parse_string_outer(s, FLAG_PARSE_SEMICOLON |
334 FLAG_EXIT_FROM_LOOP);
335# endif
336
337# ifdef CONFIG_AUTOBOOT_KEYED
338 disable_ctrlc(prev); /* restore Control C checking */
339# endif
340 }
wdenkc7de8292002-11-19 11:04:11 +0000341
342# ifdef CONFIG_MENUKEY
wdenka6c7ad22002-12-03 21:28:10 +0000343 if (menukey == CONFIG_MENUKEY) {
wdenkc7de8292002-11-19 11:04:11 +0000344 s = getenv("menucmd");
wdenka6c7ad22002-12-03 21:28:10 +0000345 if (s) {
wdenkc7de8292002-11-19 11:04:11 +0000346# ifndef CFG_HUSH_PARSER
347 run_command (s, bd, 0);
348# else
349 parse_string_outer(s, FLAG_PARSE_SEMICOLON |
350 FLAG_EXIT_FROM_LOOP);
351# endif
352 }
353 }
354#endif /* CONFIG_MENUKEY */
wdenkc6097192002-11-03 00:24:07 +0000355#endif /* CONFIG_BOOTDELAY */
356
wdenkc7de8292002-11-19 11:04:11 +0000357#ifdef CONFIG_AMIGAONEG3SE
358 {
359 extern void video_banner(void);
360 video_banner();
361 }
362#endif
363
wdenkc6097192002-11-03 00:24:07 +0000364 /*
365 * Main Loop for Monitor Command Processing
366 */
367#ifdef CFG_HUSH_PARSER
368 parse_file_outer();
369 /* This point is never reached */
370 for (;;);
371#else
372 for (;;) {
373#ifdef CONFIG_BOOT_RETRY_TIME
374 if (rc >= 0) {
375 /* Saw enough of a valid command to
376 * restart the timeout.
377 */
378 reset_cmd_timeout();
379 }
380#endif
381 len = readline (CFG_PROMPT);
382
383 flag = 0; /* assume no special flags for now */
384 if (len > 0)
385 strcpy (lastcommand, console_buffer);
386 else if (len == 0)
387 flag |= CMD_FLAG_REPEAT;
388#ifdef CONFIG_BOOT_RETRY_TIME
389 else if (len == -2) {
390 /* -2 means timed out, retry autoboot
391 */
392 printf("\nTimed out waiting for command\n");
393# ifdef CONFIG_RESET_TO_RETRY
394 /* Reinit board to run initialization code again */
395 do_reset (NULL, 0, 0, NULL);
396# else
397 return; /* retry autoboot */
398# endif
399 }
400#endif
401
402 if (len == -1)
403 printf ("<INTERRUPT>\n");
404 else
405 rc = run_command (lastcommand, flag);
406
407 if (rc <= 0) {
408 /* invalid command or not repeatable, forget it */
409 lastcommand[0] = 0;
410 }
411 }
412#endif /*CFG_HUSH_PARSER*/
413}
414
415/***************************************************************************
416 * reset command line timeout to retry_time seconds
417 */
418#ifdef CONFIG_BOOT_RETRY_TIME
419void reset_cmd_timeout(void)
420{
421 endtime = endtick(retry_time);
422}
423#endif
424
425/****************************************************************************/
426
427/*
428 * Prompt for input and read a line.
429 * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
430 * time out when time goes past endtime (timebase time in ticks).
431 * Return: number of read characters
432 * -1 if break
433 * -2 if timed out
434 */
435int readline (const char *const prompt)
436{
437 char *p = console_buffer;
438 int n = 0; /* buffer index */
439 int plen = 0; /* prompt length */
440 int col; /* output column cnt */
441 char c;
442
443 /* print prompt */
444 if (prompt) {
445 plen = strlen (prompt);
446 puts (prompt);
447 }
448 col = plen;
449
450 for (;;) {
451#ifdef CONFIG_BOOT_RETRY_TIME
452 while (!tstc()) { /* while no incoming data */
453 if (retry_time >= 0 && get_ticks() > endtime)
454 return (-2); /* timed out */
455 }
456#endif
457 WATCHDOG_RESET(); /* Trigger watchdog, if needed */
458
459#ifdef CONFIG_SHOW_ACTIVITY
460 while (!tstc()) {
461 extern void show_activity(int arg);
462 show_activity(0);
463 }
464#endif
465 c = getc();
466
467 /*
468 * Special character handling
469 */
470 switch (c) {
471 case '\r': /* Enter */
472 case '\n':
473 *p = '\0';
474 puts ("\r\n");
475 return (p - console_buffer);
476
477 case 0x03: /* ^C - break */
478 console_buffer[0] = '\0'; /* discard input */
479 return (-1);
480
481 case 0x15: /* ^U - erase line */
482 while (col > plen) {
483 puts (erase_seq);
484 --col;
485 }
486 p = console_buffer;
487 n = 0;
488 continue;
489
490 case 0x17: /* ^W - erase word */
491 p=delete_char(console_buffer, p, &col, &n, plen);
492 while ((n > 0) && (*p != ' ')) {
493 p=delete_char(console_buffer, p, &col, &n, plen);
494 }
495 continue;
496
497 case 0x08: /* ^H - backspace */
498 case 0x7F: /* DEL - backspace */
499 p=delete_char(console_buffer, p, &col, &n, plen);
500 continue;
501
502 default:
503 /*
504 * Must be a normal character then
505 */
506 if (n < CFG_CBSIZE-2) {
507 if (c == '\t') { /* expand TABs */
508 puts (tab_seq+(col&07));
509 col += 8 - (col&07);
510 } else {
511 ++col; /* echo input */
512 putc (c);
513 }
514 *p++ = c;
515 ++n;
516 } else { /* Buffer full */
517 putc ('\a');
518 }
519 }
520 }
521}
522
523/****************************************************************************/
524
525static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
526{
527 char *s;
528
529 if (*np == 0) {
530 return (p);
531 }
532
533 if (*(--p) == '\t') { /* will retype the whole line */
534 while (*colp > plen) {
535 puts (erase_seq);
536 (*colp)--;
537 }
538 for (s=buffer; s<p; ++s) {
539 if (*s == '\t') {
540 puts (tab_seq+((*colp) & 07));
541 *colp += 8 - ((*colp) & 07);
542 } else {
543 ++(*colp);
544 putc (*s);
545 }
546 }
547 } else {
548 puts (erase_seq);
549 (*colp)--;
550 }
551 (*np)--;
552 return (p);
553}
554
555/****************************************************************************/
556
557int parse_line (char *line, char *argv[])
558{
559 int nargs = 0;
560
561#ifdef DEBUG_PARSER
562 printf ("parse_line: \"%s\"\n", line);
563#endif
564 while (nargs < CFG_MAXARGS) {
565
566 /* skip any white space */
567 while ((*line == ' ') || (*line == '\t')) {
568 ++line;
569 }
570
571 if (*line == '\0') { /* end of line, no more args */
572 argv[nargs] = NULL;
573#ifdef DEBUG_PARSER
574 printf ("parse_line: nargs=%d\n", nargs);
575#endif
576 return (nargs);
577 }
578
579 argv[nargs++] = line; /* begin of argument string */
580
581 /* find end of string */
582 while (*line && (*line != ' ') && (*line != '\t')) {
583 ++line;
584 }
585
586 if (*line == '\0') { /* end of line, no more args */
587 argv[nargs] = NULL;
588#ifdef DEBUG_PARSER
589 printf ("parse_line: nargs=%d\n", nargs);
590#endif
591 return (nargs);
592 }
593
594 *line++ = '\0'; /* terminate current arg */
595 }
596
597 printf ("** Too many args (max. %d) **\n", CFG_MAXARGS);
598
599#ifdef DEBUG_PARSER
600 printf ("parse_line: nargs=%d\n", nargs);
601#endif
602 return (nargs);
603}
604
605/****************************************************************************/
606
607static void process_macros (const char *input, char *output)
608{
609 char c, prev;
610 const char *varname_start = NULL;
611 int inputcnt = strlen (input);
612 int outputcnt = CFG_CBSIZE;
613 int state = 0; /* 0 = waiting for '$' */
614 /* 1 = waiting for '(' */
615 /* 2 = waiting for ')' */
wdenka25f8622003-01-02 23:57:29 +0000616 /* 3 = waiting for ''' */
wdenkc6097192002-11-03 00:24:07 +0000617#ifdef DEBUG_PARSER
618 char *output_start = output;
619
620 printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input), input);
621#endif
622
623 prev = '\0'; /* previous character */
624
625 while (inputcnt && outputcnt) {
626 c = *input++;
627 inputcnt--;
628
wdenka25f8622003-01-02 23:57:29 +0000629 if (state!=3) {
wdenkc6097192002-11-03 00:24:07 +0000630 /* remove one level of escape characters */
631 if ((c == '\\') && (prev != '\\')) {
632 if (inputcnt-- == 0)
633 break;
634 prev = c;
635 c = *input++;
636 }
wdenka25f8622003-01-02 23:57:29 +0000637 }
wdenkc6097192002-11-03 00:24:07 +0000638
639 switch (state) {
640 case 0: /* Waiting for (unescaped) $ */
wdenka25f8622003-01-02 23:57:29 +0000641 if ((c == '\'') && (prev != '\\')) {
642 state = 3;
wdenka25f8622003-01-02 23:57:29 +0000643 break;
644 }
wdenkc6097192002-11-03 00:24:07 +0000645 if ((c == '$') && (prev != '\\')) {
646 state++;
647 } else {
648 *(output++) = c;
649 outputcnt--;
650 }
651 break;
652 case 1: /* Waiting for ( */
653 if (c == '(') {
654 state++;
655 varname_start = input;
656 } else {
657 state = 0;
658 *(output++) = '$';
659 outputcnt--;
660
661 if (outputcnt) {
662 *(output++) = c;
663 outputcnt--;
664 }
665 }
666 break;
667 case 2: /* Waiting for ) */
668 if (c == ')') {
669 int i;
670 char envname[CFG_CBSIZE], *envval;
671 int envcnt = input-varname_start-1; /* Varname # of chars */
672
673 /* Get the varname */
674 for (i = 0; i < envcnt; i++) {
675 envname[i] = varname_start[i];
676 }
677 envname[i] = 0;
678
679 /* Get its value */
680 envval = getenv (envname);
681
682 /* Copy into the line if it exists */
683 if (envval != NULL)
684 while ((*envval) && outputcnt) {
685 *(output++) = *(envval++);
686 outputcnt--;
687 }
688 /* Look for another '$' */
689 state = 0;
690 }
691 break;
wdenka25f8622003-01-02 23:57:29 +0000692 case 3: /* Waiting for ' */
693 if ((c == '\'') && (prev != '\\')) {
694 state = 0;
wdenka25f8622003-01-02 23:57:29 +0000695 } else {
696 *(output++) = c;
697 outputcnt--;
698 }
699 break;
wdenkc6097192002-11-03 00:24:07 +0000700 }
wdenkc6097192002-11-03 00:24:07 +0000701 prev = c;
702 }
703
704 if (outputcnt)
705 *output = 0;
706
707#ifdef DEBUG_PARSER
708 printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
709 strlen(output_start), output_start);
710#endif
711}
712
713/****************************************************************************
714 * returns:
715 * 1 - command executed, repeatable
716 * 0 - command executed but not repeatable, interrupted commands are
717 * always considered not repeatable
718 * -1 - not executed (unrecognized, bootd recursion or too many args)
719 * (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
720 * considered unrecognized)
721 *
722 * WARNING:
723 *
724 * We must create a temporary copy of the command since the command we get
725 * may be the result from getenv(), which returns a pointer directly to
726 * the environment data, which may change magicly when the command we run
727 * creates or modifies environment variables (like "bootp" does).
728 */
729
730int run_command (const char *cmd, int flag)
731{
732 cmd_tbl_t *cmdtp;
733 char cmdbuf[CFG_CBSIZE]; /* working copy of cmd */
734 char *token; /* start of token in cmdbuf */
735 char *sep; /* end of token (separator) in cmdbuf */
736 char finaltoken[CFG_CBSIZE];
737 char *str = cmdbuf;
738 char *argv[CFG_MAXARGS + 1]; /* NULL terminated */
739 int argc;
740 int repeatable = 1;
wdenka25f8622003-01-02 23:57:29 +0000741 int inquotes;
wdenkc6097192002-11-03 00:24:07 +0000742
743#ifdef DEBUG_PARSER
744 printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
745 puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
746 puts ("\"\n");
747#endif
748
749 clear_ctrlc(); /* forget any previous Control C */
750
751 if (!cmd || !*cmd) {
752 return -1; /* empty command */
753 }
754
755 if (strlen(cmd) >= CFG_CBSIZE) {
756 puts ("## Command too long!\n");
757 return -1;
758 }
759
760 strcpy (cmdbuf, cmd);
761
762 /* Process separators and check for invalid
763 * repeatable commands
764 */
765
766#ifdef DEBUG_PARSER
767 printf ("[PROCESS_SEPARATORS] %s\n", cmd);
768#endif
769 while (*str) {
770
771 /*
772 * Find separator, or string end
773 * Allow simple escape of ';' by writing "\;"
774 */
wdenka25f8622003-01-02 23:57:29 +0000775 for (inquotes = 0, sep = str; *sep; sep++) {
776 if ((*sep=='\'') &&
777 (*(sep-1) != '\\'))
778 inquotes=!inquotes;
779
780 if (!inquotes &&
781 (*sep == ';') && /* separator */
wdenkc6097192002-11-03 00:24:07 +0000782 ( sep != str) && /* past string start */
783 (*(sep-1) != '\\')) /* and NOT escaped */
784 break;
785 }
786
787 /*
788 * Limit the token to data between separators
789 */
790 token = str;
791 if (*sep) {
792 str = sep + 1; /* start of command for next pass */
793 *sep = '\0';
794 }
795 else
796 str = sep; /* no more commands for next pass */
797#ifdef DEBUG_PARSER
798 printf ("token: \"%s\"\n", token);
799#endif
800
801 /* find macros in this token and replace them */
802 process_macros (token, finaltoken);
803
804 /* Extract arguments */
805 argc = parse_line (finaltoken, argv);
806
807 /* Look up command in command table */
808 if ((cmdtp = find_cmd(argv[0])) == NULL) {
809 printf ("Unknown command '%s' - try 'help'\n", argv[0]);
810 return -1; /* give up after bad command */
811 }
812
813 /* found - check max args */
814 if (argc > cmdtp->maxargs) {
815 printf ("Usage:\n%s\n", cmdtp->usage);
816 return -1;
817 }
818
819#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
820 /* avoid "bootd" recursion */
821 if (cmdtp->cmd == do_bootd) {
822#ifdef DEBUG_PARSER
823 printf ("[%s]\n", finaltoken);
824#endif
825 if (flag & CMD_FLAG_BOOTD) {
826 printf ("'bootd' recursion detected\n");
827 return -1;
828 }
829 else
830 flag |= CMD_FLAG_BOOTD;
831 }
832#endif /* CFG_CMD_BOOTD */
833
834 /* OK - call function to do the command */
835 if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
836 return (-1);
837 }
838
839 repeatable &= cmdtp->repeatable;
840
841 /* Did the user stop this? */
842 if (had_ctrlc ())
843 return 0; /* if stopped then not repeatable */
844 }
845
846 return repeatable;
847}
848
849/****************************************************************************/
850
851#if (CONFIG_COMMANDS & CFG_CMD_RUN)
852int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
853{
854 int i;
855 int rcode = 1;
856
857 if (argc < 2) {
858 printf ("Usage:\n%s\n", cmdtp->usage);
859 return 1;
860 }
861
862 for (i=1; i<argc; ++i) {
863#ifndef CFG_HUSH_PARSER
864 if (run_command (getenv (argv[i]), flag) != -1) ++rcode;
865#else
866 if (parse_string_outer(getenv (argv[i]),
867 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) == 0) ++rcode;
868#endif
869 }
870 return ((rcode == i) ? 0 : 1);
871}
872#endif