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