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