]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/main.c
Patches by Murray Jensen, 17 Jun 2003:
[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 CONFIG_VERSION_VARIABLE
283         {
284                 extern char version_string[];
285                 char *str = getenv("ver");
286
287                 if (!str)
288                         setenv ("ver", version_string);  /* set version variable */
289         }
290 #endif /* CONFIG_VERSION_VARIABLE */
291
292 #ifdef CFG_HUSH_PARSER
293         u_boot_hush_start ();
294 #endif
295
296 #ifdef CONFIG_PREBOOT
297         if ((p = getenv ("preboot")) != NULL) {
298 # ifdef CONFIG_AUTOBOOT_KEYED
299                 int prev = disable_ctrlc(1);    /* disable Control C checking */
300 # endif
301
302 # ifndef CFG_HUSH_PARSER
303                 run_command (p, 0);
304 # else
305                 parse_string_outer(p, FLAG_PARSE_SEMICOLON |
306                                     FLAG_EXIT_FROM_LOOP);
307 # endif
308
309 # ifdef CONFIG_AUTOBOOT_KEYED
310                 disable_ctrlc(prev);    /* restore Control C checking */
311 # endif
312         }
313 #endif /* CONFIG_PREBOOT */
314
315 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
316         s = getenv ("bootdelay");
317         bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
318
319         debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
320
321 # ifdef CONFIG_BOOT_RETRY_TIME
322         init_cmd_timeout ();
323 # endif /* CONFIG_BOOT_RETRY_TIME */
324
325         s = getenv ("bootcmd");
326
327         debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
328
329         if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
330 # ifdef CONFIG_AUTOBOOT_KEYED
331                 int prev = disable_ctrlc(1);    /* disable Control C checking */
332 # endif
333
334 # ifndef CFG_HUSH_PARSER
335                 run_command (s, 0);
336 # else
337                 parse_string_outer(s, FLAG_PARSE_SEMICOLON |
338                                     FLAG_EXIT_FROM_LOOP);
339 # endif
340
341 # ifdef CONFIG_AUTOBOOT_KEYED
342                 disable_ctrlc(prev);    /* restore Control C checking */
343 # endif
344         }
345
346 # ifdef CONFIG_MENUKEY
347         if (menukey == CONFIG_MENUKEY) {
348             s = getenv("menucmd");
349             if (s) {
350 # ifndef CFG_HUSH_PARSER
351                 run_command (s, bd, 0);
352 # else
353                 parse_string_outer(s, FLAG_PARSE_SEMICOLON |
354                                     FLAG_EXIT_FROM_LOOP);
355 # endif
356             }
357         }
358 #endif /* CONFIG_MENUKEY */
359 #endif  /* CONFIG_BOOTDELAY */
360
361 #ifdef CONFIG_AMIGAONEG3SE
362         {
363             extern void video_banner(void);
364             video_banner();
365         }
366 #endif
367
368         /*
369          * Main Loop for Monitor Command Processing
370          */
371 #ifdef CFG_HUSH_PARSER
372         parse_file_outer();
373         /* This point is never reached */
374         for (;;);
375 #else
376         for (;;) {
377 #ifdef CONFIG_BOOT_RETRY_TIME
378                 if (rc >= 0) {
379                         /* Saw enough of a valid command to
380                          * restart the timeout.
381                          */
382                         reset_cmd_timeout();
383                 }
384 #endif
385                 len = readline (CFG_PROMPT);
386
387                 flag = 0;       /* assume no special flags for now */
388                 if (len > 0)
389                         strcpy (lastcommand, console_buffer);
390                 else if (len == 0)
391                         flag |= CMD_FLAG_REPEAT;
392 #ifdef CONFIG_BOOT_RETRY_TIME
393                 else if (len == -2) {
394                         /* -2 means timed out, retry autoboot
395                          */
396                         printf("\nTimed out waiting for command\n");
397 # ifdef CONFIG_RESET_TO_RETRY
398                         /* Reinit board to run initialization code again */
399                         do_reset (NULL, 0, 0, NULL);
400 # else
401                         return;         /* retry autoboot */
402 # endif
403                 }
404 #endif
405
406                 if (len == -1)
407                         printf ("<INTERRUPT>\n");
408                 else
409                         rc = run_command (lastcommand, flag);
410
411                 if (rc <= 0) {
412                         /* invalid command or not repeatable, forget it */
413                         lastcommand[0] = 0;
414                 }
415         }
416 #endif /*CFG_HUSH_PARSER*/
417 }
418
419 #ifdef CONFIG_BOOT_RETRY_TIME
420 /***************************************************************************
421  * initialise command line timeout
422  */
423 void init_cmd_timeout(void)
424 {
425         char *s = getenv ("bootretry");
426
427         if (s != NULL)
428                 retry_time = (int)simple_strtoul(s, NULL, 10);
429         else
430                 retry_time =  CONFIG_BOOT_RETRY_TIME;
431
432         if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
433                 retry_time = CONFIG_BOOT_RETRY_MIN;
434 }
435
436 /***************************************************************************
437  * reset command line timeout to retry_time seconds
438  */
439 void reset_cmd_timeout(void)
440 {
441         endtime = endtick(retry_time);
442 }
443 #endif
444
445 /****************************************************************************/
446
447 /*
448  * Prompt for input and read a line.
449  * If  CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
450  * time out when time goes past endtime (timebase time in ticks).
451  * Return:      number of read characters
452  *              -1 if break
453  *              -2 if timed out
454  */
455 int readline (const char *const prompt)
456 {
457         char   *p = console_buffer;
458         int     n = 0;                          /* buffer index         */
459         int     plen = 0;                       /* prompt length        */
460         int     col;                            /* output column cnt    */
461         char    c;
462
463         /* print prompt */
464         if (prompt) {
465                 plen = strlen (prompt);
466                 puts (prompt);
467         }
468         col = plen;
469
470         for (;;) {
471 #ifdef CONFIG_BOOT_RETRY_TIME
472                 while (!tstc()) {       /* while no incoming data */
473                         if (retry_time >= 0 && get_ticks() > endtime)
474                                 return (-2);    /* timed out */
475                 }
476 #endif
477                 WATCHDOG_RESET();               /* Trigger watchdog, if needed */
478
479 #ifdef CONFIG_SHOW_ACTIVITY
480                 while (!tstc()) {
481                         extern void show_activity(int arg);
482                         show_activity(0);
483                 }
484 #endif
485                 c = getc();
486
487                 /*
488                  * Special character handling
489                  */
490                 switch (c) {
491                 case '\r':                              /* Enter                */
492                 case '\n':
493                         *p = '\0';
494                         puts ("\r\n");
495                         return (p - console_buffer);
496
497                 case 0x03:                              /* ^C - break           */
498                         console_buffer[0] = '\0';       /* discard input */
499                         return (-1);
500
501                 case 0x15:                              /* ^U - erase line      */
502                         while (col > plen) {
503                                 puts (erase_seq);
504                                 --col;
505                         }
506                         p = console_buffer;
507                         n = 0;
508                         continue;
509
510                 case 0x17:                              /* ^W - erase word      */
511                         p=delete_char(console_buffer, p, &col, &n, plen);
512                         while ((n > 0) && (*p != ' ')) {
513                                 p=delete_char(console_buffer, p, &col, &n, plen);
514                         }
515                         continue;
516
517                 case 0x08:                              /* ^H  - backspace      */
518                 case 0x7F:                              /* DEL - backspace      */
519                         p=delete_char(console_buffer, p, &col, &n, plen);
520                         continue;
521
522                 default:
523                         /*
524                          * Must be a normal character then
525                          */
526                         if (n < CFG_CBSIZE-2) {
527                                 if (c == '\t') {        /* expand TABs          */
528                                         puts (tab_seq+(col&07));
529                                         col += 8 - (col&07);
530                                 } else {
531                                         ++col;          /* echo input           */
532                                         putc (c);
533                                 }
534                                 *p++ = c;
535                                 ++n;
536                         } else {                        /* Buffer full          */
537                                 putc ('\a');
538                         }
539                 }
540         }
541 }
542
543 /****************************************************************************/
544
545 static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
546 {
547         char *s;
548
549         if (*np == 0) {
550                 return (p);
551         }
552
553         if (*(--p) == '\t') {                   /* will retype the whole line   */
554                 while (*colp > plen) {
555                         puts (erase_seq);
556                         (*colp)--;
557                 }
558                 for (s=buffer; s<p; ++s) {
559                         if (*s == '\t') {
560                                 puts (tab_seq+((*colp) & 07));
561                                 *colp += 8 - ((*colp) & 07);
562                         } else {
563                                 ++(*colp);
564                                 putc (*s);
565                         }
566                 }
567         } else {
568                 puts (erase_seq);
569                 (*colp)--;
570         }
571         (*np)--;
572         return (p);
573 }
574
575 /****************************************************************************/
576
577 int parse_line (char *line, char *argv[])
578 {
579         int nargs = 0;
580
581 #ifdef DEBUG_PARSER
582         printf ("parse_line: \"%s\"\n", line);
583 #endif
584         while (nargs < CFG_MAXARGS) {
585
586                 /* skip any white space */
587                 while ((*line == ' ') || (*line == '\t')) {
588                         ++line;
589                 }
590
591                 if (*line == '\0') {    /* end of line, no more args    */
592                         argv[nargs] = NULL;
593 #ifdef DEBUG_PARSER
594                 printf ("parse_line: nargs=%d\n", nargs);
595 #endif
596                         return (nargs);
597                 }
598
599                 argv[nargs++] = line;   /* begin of argument string     */
600
601                 /* find end of string */
602                 while (*line && (*line != ' ') && (*line != '\t')) {
603                         ++line;
604                 }
605
606                 if (*line == '\0') {    /* end of line, no more args    */
607                         argv[nargs] = NULL;
608 #ifdef DEBUG_PARSER
609                 printf ("parse_line: nargs=%d\n", nargs);
610 #endif
611                         return (nargs);
612                 }
613
614                 *line++ = '\0';         /* terminate current arg         */
615         }
616
617         printf ("** Too many args (max. %d) **\n", CFG_MAXARGS);
618
619 #ifdef DEBUG_PARSER
620         printf ("parse_line: nargs=%d\n", nargs);
621 #endif
622         return (nargs);
623 }
624
625 /****************************************************************************/
626
627 static void process_macros (const char *input, char *output)
628 {
629         char c, prev;
630         const char *varname_start = NULL;
631         int inputcnt  = strlen (input);
632         int outputcnt = CFG_CBSIZE;
633         int state = 0;  /* 0 = waiting for '$'  */
634                         /* 1 = waiting for '('  */
635                         /* 2 = waiting for ')'  */
636                         /* 3 = waiting for '''  */
637 #ifdef DEBUG_PARSER
638         char *output_start = output;
639
640         printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input), input);
641 #endif
642
643         prev = '\0';                    /* previous character   */
644
645         while (inputcnt && outputcnt) {
646             c = *input++;
647             inputcnt--;
648
649             if (state!=3) {
650             /* remove one level of escape characters */
651             if ((c == '\\') && (prev != '\\')) {
652                 if (inputcnt-- == 0)
653                         break;
654                 prev = c;
655                 c = *input++;
656             }
657             }
658
659             switch (state) {
660             case 0:                     /* Waiting for (unescaped) $    */
661                 if ((c == '\'') && (prev != '\\')) {
662                         state = 3;
663                         break;
664                 }
665                 if ((c == '$') && (prev != '\\')) {
666                         state++;
667                 } else {
668                         *(output++) = c;
669                         outputcnt--;
670                 }
671                 break;
672             case 1:                     /* Waiting for (        */
673                 if (c == '(') {
674                         state++;
675                         varname_start = input;
676                 } else {
677                         state = 0;
678                         *(output++) = '$';
679                         outputcnt--;
680
681                         if (outputcnt) {
682                                 *(output++) = c;
683                                 outputcnt--;
684                         }
685                 }
686                 break;
687             case 2:                     /* Waiting for )        */
688                 if (c == ')') {
689                         int i;
690                         char envname[CFG_CBSIZE], *envval;
691                         int envcnt = input-varname_start-1; /* Varname # of chars */
692
693                         /* Get the varname */
694                         for (i = 0; i < envcnt; i++) {
695                                 envname[i] = varname_start[i];
696                         }
697                         envname[i] = 0;
698
699                         /* Get its value */
700                         envval = getenv (envname);
701
702                         /* Copy into the line if it exists */
703                         if (envval != NULL)
704                                 while ((*envval) && outputcnt) {
705                                         *(output++) = *(envval++);
706                                         outputcnt--;
707                                 }
708                         /* Look for another '$' */
709                         state = 0;
710                 }
711                 break;
712             case 3:                     /* Waiting for '        */
713                 if ((c == '\'') && (prev != '\\')) {
714                         state = 0;
715                 } else {
716                         *(output++) = c;
717                         outputcnt--;
718                 }
719                 break;
720             }
721             prev = c;
722         }
723
724         if (outputcnt)
725                 *output = 0;
726
727 #ifdef DEBUG_PARSER
728         printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
729                 strlen(output_start), output_start);
730 #endif
731 }
732
733 /****************************************************************************
734  * returns:
735  *      1  - command executed, repeatable
736  *      0  - command executed but not repeatable, interrupted commands are
737  *           always considered not repeatable
738  *      -1 - not executed (unrecognized, bootd recursion or too many args)
739  *           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
740  *           considered unrecognized)
741  *
742  * WARNING:
743  *
744  * We must create a temporary copy of the command since the command we get
745  * may be the result from getenv(), which returns a pointer directly to
746  * the environment data, which may change magicly when the command we run
747  * creates or modifies environment variables (like "bootp" does).
748  */
749
750 int run_command (const char *cmd, int flag)
751 {
752         cmd_tbl_t *cmdtp;
753         char cmdbuf[CFG_CBSIZE];        /* working copy of cmd          */
754         char *token;                    /* start of token in cmdbuf     */
755         char *sep;                      /* end of token (separator) in cmdbuf */
756         char finaltoken[CFG_CBSIZE];
757         char *str = cmdbuf;
758         char *argv[CFG_MAXARGS + 1];    /* NULL terminated      */
759         int argc, inquotes;
760         int repeatable = 1;
761         int rc = 0;
762
763 #ifdef DEBUG_PARSER
764         printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
765         puts (cmd ? cmd : "NULL");      /* use puts - string may be loooong */
766         puts ("\"\n");
767 #endif
768
769         clear_ctrlc();          /* forget any previous Control C */
770
771         if (!cmd || !*cmd) {
772                 return -1;      /* empty command */
773         }
774
775         if (strlen(cmd) >= CFG_CBSIZE) {
776                 puts ("## Command too long!\n");
777                 return -1;
778         }
779
780         strcpy (cmdbuf, cmd);
781
782         /* Process separators and check for invalid
783          * repeatable commands
784          */
785
786 #ifdef DEBUG_PARSER
787         printf ("[PROCESS_SEPARATORS] %s\n", cmd);
788 #endif
789         while (*str) {
790
791                 /*
792                  * Find separator, or string end
793                  * Allow simple escape of ';' by writing "\;"
794                  */
795                 for (inquotes = 0, sep = str; *sep; sep++) {
796                         if ((*sep=='\'') &&
797                             (*(sep-1) != '\\'))
798                                 inquotes=!inquotes;
799
800                         if (!inquotes &&
801                             (*sep == ';') &&    /* separator            */
802                             ( sep != str) &&    /* past string start    */
803                             (*(sep-1) != '\\')) /* and NOT escaped      */
804                                 break;
805                 }
806
807                 /*
808                  * Limit the token to data between separators
809                  */
810                 token = str;
811                 if (*sep) {
812                         str = sep + 1;  /* start of command for next pass */
813                         *sep = '\0';
814                 }
815                 else
816                         str = sep;      /* no more commands for next pass */
817 #ifdef DEBUG_PARSER
818                 printf ("token: \"%s\"\n", token);
819 #endif
820
821                 /* find macros in this token and replace them */
822                 process_macros (token, finaltoken);
823
824                 /* Extract arguments */
825                 argc = parse_line (finaltoken, argv);
826
827                 /* Look up command in command table */
828                 if ((cmdtp = find_cmd(argv[0])) == NULL) {
829                         printf ("Unknown command '%s' - try 'help'\n", argv[0]);
830                         rc = -1;        /* give up after bad command */
831                         continue;
832                 }
833
834                 /* found - check max args */
835                 if (argc > cmdtp->maxargs) {
836                         printf ("Usage:\n%s\n", cmdtp->usage);
837                         rc = -1;
838                         continue;
839                 }
840
841 #if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
842                 /* avoid "bootd" recursion */
843                 if (cmdtp->cmd == do_bootd) {
844 #ifdef DEBUG_PARSER
845                         printf ("[%s]\n", finaltoken);
846 #endif
847                         if (flag & CMD_FLAG_BOOTD) {
848                                 printf ("'bootd' recursion detected\n");
849                                 rc = -1;
850                                 continue;
851                         }
852                         else
853                                 flag |= CMD_FLAG_BOOTD;
854                 }
855 #endif  /* CFG_CMD_BOOTD */
856
857                 /* OK - call function to do the command */
858                 if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
859                         rc = -1;
860                 }
861
862                 repeatable &= cmdtp->repeatable;
863
864                 /* Did the user stop this? */
865                 if (had_ctrlc ())
866                         return 0;       /* if stopped then not repeatable */
867         }
868
869         return rc ? rc : repeatable;
870 }
871
872 /****************************************************************************/
873
874 #if (CONFIG_COMMANDS & CFG_CMD_RUN)
875 int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
876 {
877         int i;
878
879         if (argc < 2) {
880                 printf ("Usage:\n%s\n", cmdtp->usage);
881                 return 1;
882         }
883
884         for (i=1; i<argc; ++i) {
885                 char *arg;
886
887                 if ((arg = getenv (argv[i])) == NULL) {
888                         printf ("## Error: \"%s\" not defined\n", argv[i]);
889                         return 1;
890                 }
891 #ifndef CFG_HUSH_PARSER
892                 if (run_command (arg, flag) == -1)
893                         return 1;
894 #else
895                 if (parse_string_outer(arg,
896                     FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
897                         return 1;
898 #endif
899         }
900         return 0;
901 }
902 #endif  /* CFG_CMD_RUN */