]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/main.c
401efcf854636ae53bff86c2a50e92a61af4bef2
[karo-tx-uboot.git] / common / main.c
1 /*
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
24 /* #define      DEBUG   */
25
26 #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
42 static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
43 static int parse_line (char *, char *[]);
44 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
45 static int abortboot(int);
46 #endif
47
48 #undef DEBUG_PARSER
49
50 char        console_buffer[CFG_CBSIZE];         /* console I/O buffer   */
51
52 static char erase_seq[] = "\b \b";              /* erase sequence       */
53 static char   tab_seq[] = "        ";           /* used to expand TABs  */
54
55 #ifdef CONFIG_BOOT_RETRY_TIME
56 static uint64_t endtime = 0;  /* must be set, default is instant timeout */
57 static 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
67 int do_mdm_init = 0;
68 extern 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)
78 static __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
184 #ifdef CONFIG_MENUKEY
185 static int menukey = 0;
186 #endif
187
188 static __inline__ int abortboot(int bootdelay)
189 {
190         int abort = 0;
191
192 #ifdef CONFIG_MENUPROMPT
193         printf(CONFIG_MENUPROMPT, bootdelay);
194 #else
195         printf("Hit any key to stop autoboot: %2d ", bootdelay);
196 #endif
197
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        */
221 # ifdef CONFIG_MENUKEY
222                                 menukey = getc();
223 # else
224                                 (void) getc();  /* consume input        */
225 # endif
226                                 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
243 void 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
309         debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
310
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");
322
323         debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
324
325         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         }
341
342 # ifdef CONFIG_MENUKEY
343         if (menukey == CONFIG_MENUKEY) {
344             s = getenv("menucmd");
345             if (s) {
346 # 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 */
355 #endif  /* CONFIG_BOOTDELAY */
356
357 #ifdef CONFIG_AMIGAONEG3SE
358         {
359             extern void video_banner(void);
360             video_banner();
361         }
362 #endif
363
364         /*
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
419 void 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  */
435 int 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
525 static 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
557 int 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
607 static 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 ')'  */
616                         /* 3 = waiting for '''  */
617 #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
629             if (state!=3) {
630             /* remove one level of escape characters */
631             if ((c == '\\') && (prev != '\\')) {
632                 if (inputcnt-- == 0)
633                         break;
634                 prev = c;
635                 c = *input++;
636             }
637             }
638
639             switch (state) {
640             case 0:                     /* Waiting for (unescaped) $    */
641                 if ((c == '\'') && (prev != '\\')) {
642                         state = 3;
643                         if (inputcnt)
644                                 inputcnt--;
645                         break;
646                 }
647                 if ((c == '$') && (prev != '\\')) {
648                         state++;
649                 } else {
650                         *(output++) = c;
651                         outputcnt--;
652                 }
653                 break;
654             case 1:                     /* Waiting for (        */
655                 if (c == '(') {
656                         state++;
657                         varname_start = input;
658                 } else {
659                         state = 0;
660                         *(output++) = '$';
661                         outputcnt--;
662
663                         if (outputcnt) {
664                                 *(output++) = c;
665                                 outputcnt--;
666                         }
667                 }
668                 break;
669             case 2:                     /* Waiting for )        */
670                 if (c == ')') {
671                         int i;
672                         char envname[CFG_CBSIZE], *envval;
673                         int envcnt = input-varname_start-1; /* Varname # of chars */
674
675                         /* Get the varname */
676                         for (i = 0; i < envcnt; i++) {
677                                 envname[i] = varname_start[i];
678                         }
679                         envname[i] = 0;
680
681                         /* Get its value */
682                         envval = getenv (envname);
683
684                         /* Copy into the line if it exists */
685                         if (envval != NULL)
686                                 while ((*envval) && outputcnt) {
687                                         *(output++) = *(envval++);
688                                         outputcnt--;
689                                 }
690                         /* Look for another '$' */
691                         state = 0;
692                 }
693                 break;
694             case 3:                     /* Waiting for '        */
695                 if ((c == '\'') && (prev != '\\')) {
696                         state = 0;
697                         if (inputcnt)
698                                 inputcnt--;
699                 } else {
700                         *(output++) = c;
701                         outputcnt--;
702                 }
703                 break;
704             }
705             prev = c;
706         }
707
708         if (outputcnt)
709                 *output = 0;
710
711 #ifdef DEBUG_PARSER
712         printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
713                 strlen(output_start), output_start);
714 #endif
715 }
716
717 /****************************************************************************
718  * returns:
719  *      1  - command executed, repeatable
720  *      0  - command executed but not repeatable, interrupted commands are
721  *           always considered not repeatable
722  *      -1 - not executed (unrecognized, bootd recursion or too many args)
723  *           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
724  *           considered unrecognized)
725  *
726  * WARNING:
727  *
728  * We must create a temporary copy of the command since the command we get
729  * may be the result from getenv(), which returns a pointer directly to
730  * the environment data, which may change magicly when the command we run
731  * creates or modifies environment variables (like "bootp" does).
732  */
733
734 int run_command (const char *cmd, int flag)
735 {
736         cmd_tbl_t *cmdtp;
737         char cmdbuf[CFG_CBSIZE];        /* working copy of cmd          */
738         char *token;                    /* start of token in cmdbuf     */
739         char *sep;                      /* end of token (separator) in cmdbuf */
740         char finaltoken[CFG_CBSIZE];
741         char *str = cmdbuf;
742         char *argv[CFG_MAXARGS + 1];    /* NULL terminated      */
743         int argc;
744         int repeatable = 1;
745         int inquotes;
746
747 #ifdef DEBUG_PARSER
748         printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
749         puts (cmd ? cmd : "NULL");      /* use puts - string may be loooong */
750         puts ("\"\n");
751 #endif
752
753         clear_ctrlc();          /* forget any previous Control C */
754
755         if (!cmd || !*cmd) {
756                 return -1;      /* empty command */
757         }
758
759         if (strlen(cmd) >= CFG_CBSIZE) {
760                 puts ("## Command too long!\n");
761                 return -1;
762         }
763
764         strcpy (cmdbuf, cmd);
765
766         /* Process separators and check for invalid
767          * repeatable commands
768          */
769
770 #ifdef DEBUG_PARSER
771         printf ("[PROCESS_SEPARATORS] %s\n", cmd);
772 #endif
773         while (*str) {
774
775                 /*
776                  * Find separator, or string end
777                  * Allow simple escape of ';' by writing "\;"
778                  */
779                 for (inquotes = 0, sep = str; *sep; sep++) {
780                         if ((*sep=='\'') &&
781                             (*(sep-1) != '\\'))
782                                 inquotes=!inquotes;
783
784                         if (!inquotes &&
785                             (*sep == ';') &&    /* separator            */
786                             ( sep != str) &&    /* past string start    */
787                             (*(sep-1) != '\\')) /* and NOT escaped      */
788                                 break;
789                 }
790
791                 /*
792                  * Limit the token to data between separators
793                  */
794                 token = str;
795                 if (*sep) {
796                         str = sep + 1;  /* start of command for next pass */
797                         *sep = '\0';
798                 }
799                 else
800                         str = sep;      /* no more commands for next pass */
801 #ifdef DEBUG_PARSER
802                 printf ("token: \"%s\"\n", token);
803 #endif
804
805                 /* find macros in this token and replace them */
806                 process_macros (token, finaltoken);
807
808                 /* Extract arguments */
809                 argc = parse_line (finaltoken, argv);
810
811                 /* Look up command in command table */
812                 if ((cmdtp = find_cmd(argv[0])) == NULL) {
813                         printf ("Unknown command '%s' - try 'help'\n", argv[0]);
814                         return -1;      /* give up after bad command */
815                 }
816
817                 /* found - check max args */
818                 if (argc > cmdtp->maxargs) {
819                         printf ("Usage:\n%s\n", cmdtp->usage);
820                         return -1;
821                 }
822
823 #if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
824                 /* avoid "bootd" recursion */
825                 if (cmdtp->cmd == do_bootd) {
826 #ifdef DEBUG_PARSER
827                         printf ("[%s]\n", finaltoken);
828 #endif
829                         if (flag & CMD_FLAG_BOOTD) {
830                                 printf ("'bootd' recursion detected\n");
831                                 return -1;
832                         }
833                         else
834                                 flag |= CMD_FLAG_BOOTD;
835                 }
836 #endif  /* CFG_CMD_BOOTD */
837
838                 /* OK - call function to do the command */
839                 if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
840                         return (-1);
841                 }
842
843                 repeatable &= cmdtp->repeatable;
844
845                 /* Did the user stop this? */
846                 if (had_ctrlc ())
847                         return 0;       /* if stopped then not repeatable */
848         }
849
850         return repeatable;
851 }
852
853 /****************************************************************************/
854
855 #if (CONFIG_COMMANDS & CFG_CMD_RUN)
856 int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
857 {
858         int i;
859         int rcode = 1;
860
861         if (argc < 2) {
862                 printf ("Usage:\n%s\n", cmdtp->usage);
863                 return 1;
864         }
865
866         for (i=1; i<argc; ++i) {
867 #ifndef CFG_HUSH_PARSER
868             if (run_command (getenv (argv[i]), flag) != -1) ++rcode;
869 #else
870             if (parse_string_outer(getenv (argv[i]),
871                     FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) == 0) ++rcode;
872 #endif
873         }
874         return ((rcode == i) ? 0 : 1);
875 }
876 #endif