xref: /rk3399_rockchip-uboot/common/main.c (revision c29fdfc1d8cbefd2d85a354b95486a6d2b3f4a88)
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 */
929