xref: /openbmc/u-boot/common/main.c (revision 4e109ae9)
1 /*
2  * (C) Copyright 2000
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * Add to readline cmdline-editing by
6  * (C) Copyright 2005
7  * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
8  *
9  * See file CREDITS for list of people who contributed to this
10  * project.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation; either version 2 of
15  * the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25  * MA 02111-1307 USA
26  */
27 
28 /* #define	DEBUG	*/
29 
30 #include <common.h>
31 #include <watchdog.h>
32 #include <command.h>
33 #ifdef CONFIG_MODEM_SUPPORT
34 #include <malloc.h>		/* for free() prototype */
35 #endif
36 
37 #ifdef CFG_HUSH_PARSER
38 #include <hush.h>
39 #endif
40 
41 #include <post.h>
42 
43 #ifdef CONFIG_SILENT_CONSOLE
44 DECLARE_GLOBAL_DATA_PTR;
45 #endif
46 
47 #if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY)
48 extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);		/* for do_reset() prototype */
49 #endif
50 
51 extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
52 
53 
54 #define MAX_DELAY_STOP_STR 32
55 
56 static int parse_line (char *, char *[]);
57 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
58 static int abortboot(int);
59 #endif
60 
61 #undef DEBUG_PARSER
62 
63 char        console_buffer[CFG_CBSIZE];		/* console I/O buffer	*/
64 
65 #ifndef CONFIG_CMDLINE_EDITING
66 static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
67 static char erase_seq[] = "\b \b";		/* erase sequence	*/
68 static char   tab_seq[] = "        ";		/* used to expand TABs	*/
69 #endif /* CONFIG_CMDLINE_EDITING */
70 
71 #ifdef CONFIG_BOOT_RETRY_TIME
72 static uint64_t endtime = 0;  /* must be set, default is instant timeout */
73 static int      retry_time = -1; /* -1 so can call readline before main_loop */
74 #endif
75 
76 #define	endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
77 
78 #ifndef CONFIG_BOOT_RETRY_MIN
79 #define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
80 #endif
81 
82 #ifdef CONFIG_MODEM_SUPPORT
83 int do_mdm_init = 0;
84 extern void mdm_init(void); /* defined in board.c */
85 #endif
86 
87 /***************************************************************************
88  * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
89  * returns: 0 -  no key string, allow autoboot
90  *          1 - got key string, abort
91  */
92 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
93 # if defined(CONFIG_AUTOBOOT_KEYED)
94 static __inline__ int abortboot(int bootdelay)
95 {
96 	int abort = 0;
97 	uint64_t etime = endtick(bootdelay);
98 	struct {
99 		char* str;
100 		u_int len;
101 		int retry;
102 	}
103 	delaykey [] = {
104 		{ str: getenv ("bootdelaykey"),  retry: 1 },
105 		{ str: getenv ("bootdelaykey2"), retry: 1 },
106 		{ str: getenv ("bootstopkey"),   retry: 0 },
107 		{ str: getenv ("bootstopkey2"),  retry: 0 },
108 	};
109 
110 	char presskey [MAX_DELAY_STOP_STR];
111 	u_int presskey_len = 0;
112 	u_int presskey_max = 0;
113 	u_int i;
114 
115 #  ifdef CONFIG_AUTOBOOT_PROMPT
116 	printf(CONFIG_AUTOBOOT_PROMPT, bootdelay);
117 #  endif
118 
119 #  ifdef CONFIG_AUTOBOOT_DELAY_STR
120 	if (delaykey[0].str == NULL)
121 		delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
122 #  endif
123 #  ifdef CONFIG_AUTOBOOT_DELAY_STR2
124 	if (delaykey[1].str == NULL)
125 		delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
126 #  endif
127 #  ifdef CONFIG_AUTOBOOT_STOP_STR
128 	if (delaykey[2].str == NULL)
129 		delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
130 #  endif
131 #  ifdef CONFIG_AUTOBOOT_STOP_STR2
132 	if (delaykey[3].str == NULL)
133 		delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
134 #  endif
135 
136 	for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
137 		delaykey[i].len = delaykey[i].str == NULL ?
138 				    0 : strlen (delaykey[i].str);
139 		delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
140 				    MAX_DELAY_STOP_STR : delaykey[i].len;
141 
142 		presskey_max = presskey_max > delaykey[i].len ?
143 				    presskey_max : delaykey[i].len;
144 
145 #  if DEBUG_BOOTKEYS
146 		printf("%s key:<%s>\n",
147 		       delaykey[i].retry ? "delay" : "stop",
148 		       delaykey[i].str ? delaykey[i].str : "NULL");
149 #  endif
150 	}
151 
152 	/* In order to keep up with incoming data, check timeout only
153 	 * when catch up.
154 	 */
155 	while (!abort && get_ticks() <= etime) {
156 		for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
157 			if (delaykey[i].len > 0 &&
158 			    presskey_len >= delaykey[i].len &&
159 			    memcmp (presskey + presskey_len - delaykey[i].len,
160 				    delaykey[i].str,
161 				    delaykey[i].len) == 0) {
162 #  if DEBUG_BOOTKEYS
163 				printf("got %skey\n",
164 				       delaykey[i].retry ? "delay" : "stop");
165 #  endif
166 
167 #  ifdef CONFIG_BOOT_RETRY_TIME
168 				/* don't retry auto boot */
169 				if (! delaykey[i].retry)
170 					retry_time = -1;
171 #  endif
172 				abort = 1;
173 			}
174 		}
175 
176 		if (tstc()) {
177 			if (presskey_len < presskey_max) {
178 				presskey [presskey_len ++] = getc();
179 			}
180 			else {
181 				for (i = 0; i < presskey_max - 1; i ++)
182 					presskey [i] = presskey [i + 1];
183 
184 				presskey [i] = getc();
185 			}
186 		}
187 	}
188 #  if DEBUG_BOOTKEYS
189 	if (!abort)
190 		puts("key timeout\n");
191 #  endif
192 
193 #ifdef CONFIG_SILENT_CONSOLE
194 	if (abort)
195 		gd->flags &= ~GD_FLG_SILENT;
196 #endif
197 
198 	return abort;
199 }
200 
201 # else	/* !defined(CONFIG_AUTOBOOT_KEYED) */
202 
203 #ifdef CONFIG_MENUKEY
204 static int menukey = 0;
205 #endif
206 
207 static __inline__ int abortboot(int bootdelay)
208 {
209 	int abort = 0;
210 
211 #ifdef CONFIG_MENUPROMPT
212 	printf(CONFIG_MENUPROMPT, bootdelay);
213 #else
214 	printf("Hit any key to stop autoboot: %2d ", bootdelay);
215 #endif
216 
217 #if defined CONFIG_ZERO_BOOTDELAY_CHECK
218 	/*
219 	 * Check if key already pressed
220 	 * Don't check if bootdelay < 0
221 	 */
222 	if (bootdelay >= 0) {
223 		if (tstc()) {	/* we got a key press	*/
224 			(void) getc();  /* consume input	*/
225 			puts ("\b\b\b 0");
226 			abort = 1;	/* don't auto boot	*/
227 		}
228 	}
229 #endif
230 
231 	while ((bootdelay > 0) && (!abort)) {
232 		int i;
233 
234 		--bootdelay;
235 		/* delay 100 * 10ms */
236 		for (i=0; !abort && i<100; ++i) {
237 			if (tstc()) {	/* we got a key press	*/
238 				abort  = 1;	/* don't auto boot	*/
239 				bootdelay = 0;	/* no more delay	*/
240 # ifdef CONFIG_MENUKEY
241 				menukey = getc();
242 # else
243 				(void) getc();  /* consume input	*/
244 # endif
245 				break;
246 			}
247 			udelay(10000);
248 		}
249 
250 		printf("\b\b\b%2d ", bootdelay);
251 	}
252 
253 	putc('\n');
254 
255 #ifdef CONFIG_SILENT_CONSOLE
256 	if (abort)
257 		gd->flags &= ~GD_FLG_SILENT;
258 #endif
259 
260 	return abort;
261 }
262 # endif	/* CONFIG_AUTOBOOT_KEYED */
263 #endif	/* CONFIG_BOOTDELAY >= 0  */
264 
265 /****************************************************************************/
266 
267 void main_loop (void)
268 {
269 #ifndef CFG_HUSH_PARSER
270 	static char lastcommand[CFG_CBSIZE] = { 0, };
271 	int len;
272 	int rc = 1;
273 	int flag;
274 #endif
275 
276 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
277 	char *s;
278 	int bootdelay;
279 #endif
280 #ifdef CONFIG_PREBOOT
281 	char *p;
282 #endif
283 #ifdef CONFIG_BOOTCOUNT_LIMIT
284 	unsigned long bootcount = 0;
285 	unsigned long bootlimit = 0;
286 	char *bcs;
287 	char bcs_set[16];
288 #endif /* CONFIG_BOOTCOUNT_LIMIT */
289 
290 #if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
291 	ulong bmp = 0;		/* default bitmap */
292 	extern int trab_vfd (ulong bitmap);
293 
294 #ifdef CONFIG_MODEM_SUPPORT
295 	if (do_mdm_init)
296 		bmp = 1;	/* alternate bitmap */
297 #endif
298 	trab_vfd (bmp);
299 #endif	/* CONFIG_VFD && VFD_TEST_LOGO */
300 
301 #ifdef CONFIG_BOOTCOUNT_LIMIT
302 	bootcount = bootcount_load();
303 	bootcount++;
304 	bootcount_store (bootcount);
305 	sprintf (bcs_set, "%lu", bootcount);
306 	setenv ("bootcount", bcs_set);
307 	bcs = getenv ("bootlimit");
308 	bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
309 #endif /* CONFIG_BOOTCOUNT_LIMIT */
310 
311 #ifdef CONFIG_MODEM_SUPPORT
312 	debug ("DEBUG: main_loop:   do_mdm_init=%d\n", do_mdm_init);
313 	if (do_mdm_init) {
314 		char *str = strdup(getenv("mdm_cmd"));
315 		setenv ("preboot", str);  /* set or delete definition */
316 		if (str != NULL)
317 			free (str);
318 		mdm_init(); /* wait for modem connection */
319 	}
320 #endif  /* CONFIG_MODEM_SUPPORT */
321 
322 #ifdef CONFIG_VERSION_VARIABLE
323 	{
324 		extern char version_string[];
325 
326 		setenv ("ver", version_string);  /* set version variable */
327 	}
328 #endif /* CONFIG_VERSION_VARIABLE */
329 
330 #ifdef CFG_HUSH_PARSER
331 	u_boot_hush_start ();
332 #endif
333 
334 #ifdef CONFIG_AUTO_COMPLETE
335 	install_auto_complete();
336 #endif
337 
338 #ifdef CONFIG_PREBOOT
339 	if ((p = getenv ("preboot")) != NULL) {
340 # ifdef CONFIG_AUTOBOOT_KEYED
341 		int prev = disable_ctrlc(1);	/* disable Control C checking */
342 # endif
343 
344 # ifndef CFG_HUSH_PARSER
345 		run_command (p, 0);
346 # else
347 		parse_string_outer(p, FLAG_PARSE_SEMICOLON |
348 				    FLAG_EXIT_FROM_LOOP);
349 # endif
350 
351 # ifdef CONFIG_AUTOBOOT_KEYED
352 		disable_ctrlc(prev);	/* restore Control C checking */
353 # endif
354 	}
355 #endif /* CONFIG_PREBOOT */
356 
357 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
358 	s = getenv ("bootdelay");
359 	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
360 
361 	debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
362 
363 # ifdef CONFIG_BOOT_RETRY_TIME
364 	init_cmd_timeout ();
365 # endif	/* CONFIG_BOOT_RETRY_TIME */
366 
367 #ifdef CONFIG_BOOTCOUNT_LIMIT
368 	if (bootlimit && (bootcount > bootlimit)) {
369 		printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
370 		        (unsigned)bootlimit);
371 		s = getenv ("altbootcmd");
372 	}
373 	else
374 #endif /* CONFIG_BOOTCOUNT_LIMIT */
375 		s = getenv ("bootcmd");
376 
377 	debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
378 
379 	if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
380 # ifdef CONFIG_AUTOBOOT_KEYED
381 		int prev = disable_ctrlc(1);	/* disable Control C checking */
382 # endif
383 
384 # ifndef CFG_HUSH_PARSER
385 		run_command (s, 0);
386 # else
387 		parse_string_outer(s, FLAG_PARSE_SEMICOLON |
388 				    FLAG_EXIT_FROM_LOOP);
389 # endif
390 
391 # ifdef CONFIG_AUTOBOOT_KEYED
392 		disable_ctrlc(prev);	/* restore Control C checking */
393 # endif
394 	}
395 
396 # ifdef CONFIG_MENUKEY
397 	if (menukey == CONFIG_MENUKEY) {
398 	    s = getenv("menucmd");
399 	    if (s) {
400 # ifndef CFG_HUSH_PARSER
401 		run_command (s, 0);
402 # else
403 		parse_string_outer(s, FLAG_PARSE_SEMICOLON |
404 				    FLAG_EXIT_FROM_LOOP);
405 # endif
406 	    }
407 	}
408 #endif /* CONFIG_MENUKEY */
409 #endif	/* CONFIG_BOOTDELAY */
410 
411 #ifdef CONFIG_AMIGAONEG3SE
412 	{
413 	    extern void video_banner(void);
414 	    video_banner();
415 	}
416 #endif
417 
418 	/*
419 	 * Main Loop for Monitor Command Processing
420 	 */
421 #ifdef CFG_HUSH_PARSER
422 	parse_file_outer();
423 	/* This point is never reached */
424 	for (;;);
425 #else
426 	for (;;) {
427 #ifdef CONFIG_BOOT_RETRY_TIME
428 		if (rc >= 0) {
429 			/* Saw enough of a valid command to
430 			 * restart the timeout.
431 			 */
432 			reset_cmd_timeout();
433 		}
434 #endif
435 		len = readline (CFG_PROMPT);
436 
437 		flag = 0;	/* assume no special flags for now */
438 		if (len > 0)
439 			strcpy (lastcommand, console_buffer);
440 		else if (len == 0)
441 			flag |= CMD_FLAG_REPEAT;
442 #ifdef CONFIG_BOOT_RETRY_TIME
443 		else if (len == -2) {
444 			/* -2 means timed out, retry autoboot
445 			 */
446 			puts ("\nTimed out waiting for command\n");
447 # ifdef CONFIG_RESET_TO_RETRY
448 			/* Reinit board to run initialization code again */
449 			do_reset (NULL, 0, 0, NULL);
450 # else
451 			return;		/* retry autoboot */
452 # endif
453 		}
454 #endif
455 
456 		if (len == -1)
457 			puts ("<INTERRUPT>\n");
458 		else
459 			rc = run_command (lastcommand, flag);
460 
461 		if (rc <= 0) {
462 			/* invalid command or not repeatable, forget it */
463 			lastcommand[0] = 0;
464 		}
465 	}
466 #endif /*CFG_HUSH_PARSER*/
467 }
468 
469 #ifdef CONFIG_BOOT_RETRY_TIME
470 /***************************************************************************
471  * initialize command line timeout
472  */
473 void init_cmd_timeout(void)
474 {
475 	char *s = getenv ("bootretry");
476 
477 	if (s != NULL)
478 		retry_time = (int)simple_strtol(s, NULL, 10);
479 	else
480 		retry_time =  CONFIG_BOOT_RETRY_TIME;
481 
482 	if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
483 		retry_time = CONFIG_BOOT_RETRY_MIN;
484 }
485 
486 /***************************************************************************
487  * reset command line timeout to retry_time seconds
488  */
489 void reset_cmd_timeout(void)
490 {
491 	endtime = endtick(retry_time);
492 }
493 #endif
494 
495 #ifdef CONFIG_CMDLINE_EDITING
496 
497 /*
498  * cmdline-editing related codes from vivi.
499  * Author: Janghoon Lyu <nandy@mizi.com>
500  */
501 
502 #define putnstr(str,n)	do {			\
503 		printf ("%.*s", n, str);	\
504 	} while (0)
505 
506 #define CTL_CH(c)		((c) - 'a' + 1)
507 
508 #define MAX_CMDBUF_SIZE		256
509 
510 #define CTL_BACKSPACE		('\b')
511 #define DEL			((char)255)
512 #define DEL7			((char)127)
513 #define CREAD_HIST_CHAR		('!')
514 
515 #define getcmd_putch(ch)	putc(ch)
516 #define getcmd_getch()		getc()
517 #define getcmd_cbeep()		getcmd_putch('\a')
518 
519 #define HIST_MAX		20
520 #define HIST_SIZE		MAX_CMDBUF_SIZE
521 
522 static int hist_max = 0;
523 static int hist_add_idx = 0;
524 static int hist_cur = -1;
525 unsigned hist_num = 0;
526 
527 char* hist_list[HIST_MAX];
528 char hist_lines[HIST_MAX][HIST_SIZE];
529 
530 #define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
531 
532 static void hist_init(void)
533 {
534 	int i;
535 
536 	hist_max = 0;
537 	hist_add_idx = 0;
538 	hist_cur = -1;
539 	hist_num = 0;
540 
541 	for (i = 0; i < HIST_MAX; i++) {
542 		hist_list[i] = hist_lines[i];
543 		hist_list[i][0] = '\0';
544 	}
545 }
546 
547 static void cread_add_to_hist(char *line)
548 {
549 	strcpy(hist_list[hist_add_idx], line);
550 
551 	if (++hist_add_idx >= HIST_MAX)
552 		hist_add_idx = 0;
553 
554 	if (hist_add_idx > hist_max)
555 		hist_max = hist_add_idx;
556 
557 	hist_num++;
558 }
559 
560 static char* hist_prev(void)
561 {
562 	char *ret;
563 	int old_cur;
564 
565 	if (hist_cur < 0)
566 		return NULL;
567 
568 	old_cur = hist_cur;
569 	if (--hist_cur < 0)
570 		hist_cur = hist_max;
571 
572 	if (hist_cur == hist_add_idx) {
573 		hist_cur = old_cur;
574 		ret = NULL;
575 	} else
576 		ret = hist_list[hist_cur];
577 
578 	return (ret);
579 }
580 
581 static char* hist_next(void)
582 {
583 	char *ret;
584 
585 	if (hist_cur < 0)
586 		return NULL;
587 
588 	if (hist_cur == hist_add_idx)
589 		return NULL;
590 
591 	if (++hist_cur > hist_max)
592 		hist_cur = 0;
593 
594 	if (hist_cur == hist_add_idx) {
595 		ret = "";
596 	} else
597 		ret = hist_list[hist_cur];
598 
599 	return (ret);
600 }
601 
602 #ifndef CONFIG_CMDLINE_EDITING
603 static void cread_print_hist_list(void)
604 {
605 	int i;
606 	unsigned long n;
607 
608 	n = hist_num - hist_max;
609 
610 	i = hist_add_idx + 1;
611 	while (1) {
612 		if (i > hist_max)
613 			i = 0;
614 		if (i == hist_add_idx)
615 			break;
616 		printf("%s\n", hist_list[i]);
617 		n++;
618 		i++;
619 	}
620 }
621 #endif /* CONFIG_CMDLINE_EDITING */
622 
623 #define BEGINNING_OF_LINE() {			\
624 	while (num) {				\
625 		getcmd_putch(CTL_BACKSPACE);	\
626 		num--;				\
627 	}					\
628 }
629 
630 #define ERASE_TO_EOL() {				\
631 	if (num < eol_num) {				\
632 		int tmp;				\
633 		for (tmp = num; tmp < eol_num; tmp++)	\
634 			getcmd_putch(' ');		\
635 		while (tmp-- > num)			\
636 			getcmd_putch(CTL_BACKSPACE);	\
637 		eol_num = num;				\
638 	}						\
639 }
640 
641 #define REFRESH_TO_EOL() {			\
642 	if (num < eol_num) {			\
643 		wlen = eol_num - num;		\
644 		putnstr(buf + num, wlen);	\
645 		num = eol_num;			\
646 	}					\
647 }
648 
649 static void cread_add_char(char ichar, int insert, unsigned long *num,
650 	       unsigned long *eol_num, char *buf, unsigned long len)
651 {
652 	unsigned long wlen;
653 
654 	/* room ??? */
655 	if (insert || *num == *eol_num) {
656 		if (*eol_num > len - 1) {
657 			getcmd_cbeep();
658 			return;
659 		}
660 		(*eol_num)++;
661 	}
662 
663 	if (insert) {
664 		wlen = *eol_num - *num;
665 		if (wlen > 1) {
666 			memmove(&buf[*num+1], &buf[*num], wlen-1);
667 		}
668 
669 		buf[*num] = ichar;
670 		putnstr(buf + *num, wlen);
671 		(*num)++;
672 		while (--wlen) {
673 			getcmd_putch(CTL_BACKSPACE);
674 		}
675 	} else {
676 		/* echo the character */
677 		wlen = 1;
678 		buf[*num] = ichar;
679 		putnstr(buf + *num, wlen);
680 		(*num)++;
681 	}
682 }
683 
684 static void cread_add_str(char *str, int strsize, int insert, unsigned long *num,
685 	      unsigned long *eol_num, char *buf, unsigned long len)
686 {
687 	while (strsize--) {
688 		cread_add_char(*str, insert, num, eol_num, buf, len);
689 		str++;
690 	}
691 }
692 
693 static int cread_line(char *buf, unsigned int *len)
694 {
695 	unsigned long num = 0;
696 	unsigned long eol_num = 0;
697 	unsigned long rlen;
698 	unsigned long wlen;
699 	char ichar;
700 	int insert = 1;
701 	int esc_len = 0;
702 	int rc = 0;
703 	char esc_save[8];
704 
705 	while (1) {
706 		rlen = 1;
707 		ichar = getcmd_getch();
708 
709 		if ((ichar == '\n') || (ichar == '\r')) {
710 			putc('\n');
711 			break;
712 		}
713 
714 		/*
715 		 * handle standard linux xterm esc sequences for arrow key, etc.
716 		 */
717 		if (esc_len != 0) {
718 			if (esc_len == 1) {
719 				if (ichar == '[') {
720 					esc_save[esc_len] = ichar;
721 					esc_len = 2;
722 				} else {
723 					cread_add_str(esc_save, esc_len, insert,
724 						      &num, &eol_num, buf, *len);
725 					esc_len = 0;
726 				}
727 				continue;
728 			}
729 
730 			switch (ichar) {
731 
732 			case 'D':	/* <- key */
733 				ichar = CTL_CH('b');
734 				esc_len = 0;
735 				break;
736 			case 'C':	/* -> key */
737 				ichar = CTL_CH('f');
738 				esc_len = 0;
739 				break;	/* pass off to ^F handler */
740 			case 'H':	/* Home key */
741 				ichar = CTL_CH('a');
742 				esc_len = 0;
743 				break;	/* pass off to ^A handler */
744 			case 'A':	/* up arrow */
745 				ichar = CTL_CH('p');
746 				esc_len = 0;
747 				break;	/* pass off to ^P handler */
748 			case 'B':	/* down arrow */
749 				ichar = CTL_CH('n');
750 				esc_len = 0;
751 				break;	/* pass off to ^N handler */
752 			default:
753 				esc_save[esc_len++] = ichar;
754 				cread_add_str(esc_save, esc_len, insert,
755 					      &num, &eol_num, buf, *len);
756 				esc_len = 0;
757 				continue;
758 			}
759 		}
760 
761 		switch (ichar) {
762 		case 0x1b:
763 			if (esc_len == 0) {
764 				esc_save[esc_len] = ichar;
765 				esc_len = 1;
766 			} else {
767 				puts("impossible condition #876\n");
768 				esc_len = 0;
769 			}
770 			break;
771 
772 		case CTL_CH('a'):
773 			BEGINNING_OF_LINE();
774 			break;
775 		case CTL_CH('c'):	/* ^C - break */
776 			*buf = '\0';	/* discard input */
777 			return (-1);
778 		case CTL_CH('f'):
779 			if (num < eol_num) {
780 				getcmd_putch(buf[num]);
781 				num++;
782 			}
783 			break;
784 		case CTL_CH('b'):
785 			if (num) {
786 				getcmd_putch(CTL_BACKSPACE);
787 				num--;
788 			}
789 			break;
790 		case CTL_CH('d'):
791 			if (num < eol_num) {
792 				wlen = eol_num - num - 1;
793 				if (wlen) {
794 					memmove(&buf[num], &buf[num+1], wlen);
795 					putnstr(buf + num, wlen);
796 				}
797 
798 				getcmd_putch(' ');
799 				do {
800 					getcmd_putch(CTL_BACKSPACE);
801 				} while (wlen--);
802 				eol_num--;
803 			}
804 			break;
805 		case CTL_CH('k'):
806 			ERASE_TO_EOL();
807 			break;
808 		case CTL_CH('e'):
809 			REFRESH_TO_EOL();
810 			break;
811 		case CTL_CH('o'):
812 			insert = !insert;
813 			break;
814 		case CTL_CH('x'):
815 			BEGINNING_OF_LINE();
816 			ERASE_TO_EOL();
817 			break;
818 		case DEL:
819 		case DEL7:
820 		case 8:
821 			if (num) {
822 				wlen = eol_num - num;
823 				num--;
824 				memmove(&buf[num], &buf[num+1], wlen);
825 				getcmd_putch(CTL_BACKSPACE);
826 				putnstr(buf + num, wlen);
827 				getcmd_putch(' ');
828 				do {
829 					getcmd_putch(CTL_BACKSPACE);
830 				} while (wlen--);
831 				eol_num--;
832 			}
833 			break;
834 		case CTL_CH('p'):
835 		case CTL_CH('n'):
836 		{
837 			char * hline;
838 
839 			esc_len = 0;
840 
841 			if (ichar == CTL_CH('p'))
842 				hline = hist_prev();
843 			else
844 				hline = hist_next();
845 
846 			if (!hline) {
847 				getcmd_cbeep();
848 				continue;
849 			}
850 
851 			/* nuke the current line */
852 			/* first, go home */
853 			BEGINNING_OF_LINE();
854 
855 			/* erase to end of line */
856 			ERASE_TO_EOL();
857 
858 			/* copy new line into place and display */
859 			strcpy(buf, hline);
860 			eol_num = strlen(buf);
861 			REFRESH_TO_EOL();
862 			continue;
863 		}
864 		default:
865 			cread_add_char(ichar, insert, &num, &eol_num, buf, *len);
866 			break;
867 		}
868 	}
869 	*len = eol_num;
870 	buf[eol_num] = '\0';	/* lose the newline */
871 
872 	if (buf[0] && buf[0] != CREAD_HIST_CHAR)
873 		cread_add_to_hist(buf);
874 	hist_cur = hist_add_idx;
875 
876 	return (rc);
877 }
878 
879 #endif /* CONFIG_CMDLINE_EDITING */
880 
881 /****************************************************************************/
882 
883 /*
884  * Prompt for input and read a line.
885  * If  CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
886  * time out when time goes past endtime (timebase time in ticks).
887  * Return:	number of read characters
888  *		-1 if break
889  *		-2 if timed out
890  */
891 int readline (const char *const prompt)
892 {
893 #ifdef CONFIG_CMDLINE_EDITING
894 	char *p = console_buffer;
895 	unsigned int len=MAX_CMDBUF_SIZE;
896 	int rc;
897 	static int initted = 0;
898 
899 	if (!initted) {
900 		hist_init();
901 		initted = 1;
902 	}
903 
904 	puts (prompt);
905 
906 	rc = cread_line(p, &len);
907 	return rc < 0 ? rc : len;
908 #else
909 	char   *p = console_buffer;
910 	int	n = 0;				/* buffer index		*/
911 	int	plen = 0;			/* prompt length	*/
912 	int	col;				/* output column cnt	*/
913 	char	c;
914 
915 	/* print prompt */
916 	if (prompt) {
917 		plen = strlen (prompt);
918 		puts (prompt);
919 	}
920 	col = plen;
921 
922 	for (;;) {
923 #ifdef CONFIG_BOOT_RETRY_TIME
924 		while (!tstc()) {	/* while no incoming data */
925 			if (retry_time >= 0 && get_ticks() > endtime)
926 				return (-2);	/* timed out */
927 		}
928 #endif
929 		WATCHDOG_RESET();		/* Trigger watchdog, if needed */
930 
931 #ifdef CONFIG_SHOW_ACTIVITY
932 		while (!tstc()) {
933 			extern void show_activity(int arg);
934 			show_activity(0);
935 		}
936 #endif
937 		c = getc();
938 
939 		/*
940 		 * Special character handling
941 		 */
942 		switch (c) {
943 		case '\r':				/* Enter		*/
944 		case '\n':
945 			*p = '\0';
946 			puts ("\r\n");
947 			return (p - console_buffer);
948 
949 		case '\0':				/* nul			*/
950 			continue;
951 
952 		case 0x03:				/* ^C - break		*/
953 			console_buffer[0] = '\0';	/* discard input */
954 			return (-1);
955 
956 		case 0x15:				/* ^U - erase line	*/
957 			while (col > plen) {
958 				puts (erase_seq);
959 				--col;
960 			}
961 			p = console_buffer;
962 			n = 0;
963 			continue;
964 
965 		case 0x17:				/* ^W - erase word	*/
966 			p=delete_char(console_buffer, p, &col, &n, plen);
967 			while ((n > 0) && (*p != ' ')) {
968 				p=delete_char(console_buffer, p, &col, &n, plen);
969 			}
970 			continue;
971 
972 		case 0x08:				/* ^H  - backspace	*/
973 		case 0x7F:				/* DEL - backspace	*/
974 			p=delete_char(console_buffer, p, &col, &n, plen);
975 			continue;
976 
977 		default:
978 			/*
979 			 * Must be a normal character then
980 			 */
981 			if (n < CFG_CBSIZE-2) {
982 				if (c == '\t') {	/* expand TABs		*/
983 #ifdef CONFIG_AUTO_COMPLETE
984 					/* if auto completion triggered just continue */
985 					*p = '\0';
986 					if (cmd_auto_complete(prompt, console_buffer, &n, &col)) {
987 						p = console_buffer + n;	/* reset */
988 						continue;
989 					}
990 #endif
991 					puts (tab_seq+(col&07));
992 					col += 8 - (col&07);
993 				} else {
994 					++col;		/* echo input		*/
995 					putc (c);
996 				}
997 				*p++ = c;
998 				++n;
999 			} else {			/* Buffer full		*/
1000 				putc ('\a');
1001 			}
1002 		}
1003 	}
1004 #endif /* CONFIG_CMDLINE_EDITING */
1005 }
1006 
1007 /****************************************************************************/
1008 
1009 #ifndef CONFIG_CMDLINE_EDITING
1010 static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
1011 {
1012 	char *s;
1013 
1014 	if (*np == 0) {
1015 		return (p);
1016 	}
1017 
1018 	if (*(--p) == '\t') {			/* will retype the whole line	*/
1019 		while (*colp > plen) {
1020 			puts (erase_seq);
1021 			(*colp)--;
1022 		}
1023 		for (s=buffer; s<p; ++s) {
1024 			if (*s == '\t') {
1025 				puts (tab_seq+((*colp) & 07));
1026 				*colp += 8 - ((*colp) & 07);
1027 			} else {
1028 				++(*colp);
1029 				putc (*s);
1030 			}
1031 		}
1032 	} else {
1033 		puts (erase_seq);
1034 		(*colp)--;
1035 	}
1036 	(*np)--;
1037 	return (p);
1038 }
1039 #endif /* CONFIG_CMDLINE_EDITING */
1040 
1041 /****************************************************************************/
1042 
1043 int parse_line (char *line, char *argv[])
1044 {
1045 	int nargs = 0;
1046 
1047 #ifdef DEBUG_PARSER
1048 	printf ("parse_line: \"%s\"\n", line);
1049 #endif
1050 	while (nargs < CFG_MAXARGS) {
1051 
1052 		/* skip any white space */
1053 		while ((*line == ' ') || (*line == '\t')) {
1054 			++line;
1055 		}
1056 
1057 		if (*line == '\0') {	/* end of line, no more args	*/
1058 			argv[nargs] = NULL;
1059 #ifdef DEBUG_PARSER
1060 		printf ("parse_line: nargs=%d\n", nargs);
1061 #endif
1062 			return (nargs);
1063 		}
1064 
1065 		argv[nargs++] = line;	/* begin of argument string	*/
1066 
1067 		/* find end of string */
1068 		while (*line && (*line != ' ') && (*line != '\t')) {
1069 			++line;
1070 		}
1071 
1072 		if (*line == '\0') {	/* end of line, no more args	*/
1073 			argv[nargs] = NULL;
1074 #ifdef DEBUG_PARSER
1075 		printf ("parse_line: nargs=%d\n", nargs);
1076 #endif
1077 			return (nargs);
1078 		}
1079 
1080 		*line++ = '\0';		/* terminate current arg	 */
1081 	}
1082 
1083 	printf ("** Too many args (max. %d) **\n", CFG_MAXARGS);
1084 
1085 #ifdef DEBUG_PARSER
1086 	printf ("parse_line: nargs=%d\n", nargs);
1087 #endif
1088 	return (nargs);
1089 }
1090 
1091 /****************************************************************************/
1092 
1093 static void process_macros (const char *input, char *output)
1094 {
1095 	char c, prev;
1096 	const char *varname_start = NULL;
1097 	int inputcnt = strlen (input);
1098 	int outputcnt = CFG_CBSIZE;
1099 	int state = 0;		/* 0 = waiting for '$'  */
1100 
1101 	/* 1 = waiting for '(' or '{' */
1102 	/* 2 = waiting for ')' or '}' */
1103 	/* 3 = waiting for '''  */
1104 #ifdef DEBUG_PARSER
1105 	char *output_start = output;
1106 
1107 	printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen (input),
1108 		input);
1109 #endif
1110 
1111 	prev = '\0';		/* previous character   */
1112 
1113 	while (inputcnt && outputcnt) {
1114 		c = *input++;
1115 		inputcnt--;
1116 
1117 		if (state != 3) {
1118 			/* remove one level of escape characters */
1119 			if ((c == '\\') && (prev != '\\')) {
1120 				if (inputcnt-- == 0)
1121 					break;
1122 				prev = c;
1123 				c = *input++;
1124 			}
1125 		}
1126 
1127 		switch (state) {
1128 		case 0:	/* Waiting for (unescaped) $    */
1129 			if ((c == '\'') && (prev != '\\')) {
1130 				state = 3;
1131 				break;
1132 			}
1133 			if ((c == '$') && (prev != '\\')) {
1134 				state++;
1135 			} else {
1136 				*(output++) = c;
1137 				outputcnt--;
1138 			}
1139 			break;
1140 		case 1:	/* Waiting for (        */
1141 			if (c == '(' || c == '{') {
1142 				state++;
1143 				varname_start = input;
1144 			} else {
1145 				state = 0;
1146 				*(output++) = '$';
1147 				outputcnt--;
1148 
1149 				if (outputcnt) {
1150 					*(output++) = c;
1151 					outputcnt--;
1152 				}
1153 			}
1154 			break;
1155 		case 2:	/* Waiting for )        */
1156 			if (c == ')' || c == '}') {
1157 				int i;
1158 				char envname[CFG_CBSIZE], *envval;
1159 				int envcnt = input - varname_start - 1;	/* Varname # of chars */
1160 
1161 				/* Get the varname */
1162 				for (i = 0; i < envcnt; i++) {
1163 					envname[i] = varname_start[i];
1164 				}
1165 				envname[i] = 0;
1166 
1167 				/* Get its value */
1168 				envval = getenv (envname);
1169 
1170 				/* Copy into the line if it exists */
1171 				if (envval != NULL)
1172 					while ((*envval) && outputcnt) {
1173 						*(output++) = *(envval++);
1174 						outputcnt--;
1175 					}
1176 				/* Look for another '$' */
1177 				state = 0;
1178 			}
1179 			break;
1180 		case 3:	/* Waiting for '        */
1181 			if ((c == '\'') && (prev != '\\')) {
1182 				state = 0;
1183 			} else {
1184 				*(output++) = c;
1185 				outputcnt--;
1186 			}
1187 			break;
1188 		}
1189 		prev = c;
1190 	}
1191 
1192 	if (outputcnt)
1193 		*output = 0;
1194 	else
1195 		*(output - 1) = 0;
1196 
1197 #ifdef DEBUG_PARSER
1198 	printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
1199 		strlen (output_start), output_start);
1200 #endif
1201 }
1202 
1203 /****************************************************************************
1204  * returns:
1205  *	1  - command executed, repeatable
1206  *	0  - command executed but not repeatable, interrupted commands are
1207  *	     always considered not repeatable
1208  *	-1 - not executed (unrecognized, bootd recursion or too many args)
1209  *           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
1210  *           considered unrecognized)
1211  *
1212  * WARNING:
1213  *
1214  * We must create a temporary copy of the command since the command we get
1215  * may be the result from getenv(), which returns a pointer directly to
1216  * the environment data, which may change magicly when the command we run
1217  * creates or modifies environment variables (like "bootp" does).
1218  */
1219 
1220 int run_command (const char *cmd, int flag)
1221 {
1222 	cmd_tbl_t *cmdtp;
1223 	char cmdbuf[CFG_CBSIZE];	/* working copy of cmd		*/
1224 	char *token;			/* start of token in cmdbuf	*/
1225 	char *sep;			/* end of token (separator) in cmdbuf */
1226 	char finaltoken[CFG_CBSIZE];
1227 	char *str = cmdbuf;
1228 	char *argv[CFG_MAXARGS + 1];	/* NULL terminated	*/
1229 	int argc, inquotes;
1230 	int repeatable = 1;
1231 	int rc = 0;
1232 
1233 #ifdef DEBUG_PARSER
1234 	printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
1235 	puts (cmd ? cmd : "NULL");	/* use puts - string may be loooong */
1236 	puts ("\"\n");
1237 #endif
1238 
1239 	clear_ctrlc();		/* forget any previous Control C */
1240 
1241 	if (!cmd || !*cmd) {
1242 		return -1;	/* empty command */
1243 	}
1244 
1245 	if (strlen(cmd) >= CFG_CBSIZE) {
1246 		puts ("## Command too long!\n");
1247 		return -1;
1248 	}
1249 
1250 	strcpy (cmdbuf, cmd);
1251 
1252 	/* Process separators and check for invalid
1253 	 * repeatable commands
1254 	 */
1255 
1256 #ifdef DEBUG_PARSER
1257 	printf ("[PROCESS_SEPARATORS] %s\n", cmd);
1258 #endif
1259 	while (*str) {
1260 
1261 		/*
1262 		 * Find separator, or string end
1263 		 * Allow simple escape of ';' by writing "\;"
1264 		 */
1265 		for (inquotes = 0, sep = str; *sep; sep++) {
1266 			if ((*sep=='\'') &&
1267 			    (*(sep-1) != '\\'))
1268 				inquotes=!inquotes;
1269 
1270 			if (!inquotes &&
1271 			    (*sep == ';') &&	/* separator		*/
1272 			    ( sep != str) &&	/* past string start	*/
1273 			    (*(sep-1) != '\\'))	/* and NOT escaped	*/
1274 				break;
1275 		}
1276 
1277 		/*
1278 		 * Limit the token to data between separators
1279 		 */
1280 		token = str;
1281 		if (*sep) {
1282 			str = sep + 1;	/* start of command for next pass */
1283 			*sep = '\0';
1284 		}
1285 		else
1286 			str = sep;	/* no more commands for next pass */
1287 #ifdef DEBUG_PARSER
1288 		printf ("token: \"%s\"\n", token);
1289 #endif
1290 
1291 		/* find macros in this token and replace them */
1292 		process_macros (token, finaltoken);
1293 
1294 		/* Extract arguments */
1295 		if ((argc = parse_line (finaltoken, argv)) == 0) {
1296 			rc = -1;	/* no command at all */
1297 			continue;
1298 		}
1299 
1300 		/* Look up command in command table */
1301 		if ((cmdtp = find_cmd(argv[0])) == NULL) {
1302 			printf ("Unknown command '%s' - try 'help'\n", argv[0]);
1303 			rc = -1;	/* give up after bad command */
1304 			continue;
1305 		}
1306 
1307 		/* found - check max args */
1308 		if (argc > cmdtp->maxargs) {
1309 			printf ("Usage:\n%s\n", cmdtp->usage);
1310 			rc = -1;
1311 			continue;
1312 		}
1313 
1314 #if (CONFIG_COMMANDS & CFG_CMD_BOOTD) || defined(CONFIG_CMD_BOOTD)
1315 		/* avoid "bootd" recursion */
1316 		if (cmdtp->cmd == do_bootd) {
1317 #ifdef DEBUG_PARSER
1318 			printf ("[%s]\n", finaltoken);
1319 #endif
1320 			if (flag & CMD_FLAG_BOOTD) {
1321 				puts ("'bootd' recursion detected\n");
1322 				rc = -1;
1323 				continue;
1324 			} else {
1325 				flag |= CMD_FLAG_BOOTD;
1326 			}
1327 		}
1328 #endif	/* CFG_CMD_BOOTD */
1329 
1330 		/* OK - call function to do the command */
1331 		if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
1332 			rc = -1;
1333 		}
1334 
1335 		repeatable &= cmdtp->repeatable;
1336 
1337 		/* Did the user stop this? */
1338 		if (had_ctrlc ())
1339 			return -1;	/* if stopped then not repeatable */
1340 	}
1341 
1342 	return rc ? rc : repeatable;
1343 }
1344 
1345 /****************************************************************************/
1346 
1347 #if (CONFIG_COMMANDS & CFG_CMD_RUN) || defined(CONFIG_CMD_RUN)
1348 int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
1349 {
1350 	int i;
1351 
1352 	if (argc < 2) {
1353 		printf ("Usage:\n%s\n", cmdtp->usage);
1354 		return 1;
1355 	}
1356 
1357 	for (i=1; i<argc; ++i) {
1358 		char *arg;
1359 
1360 		if ((arg = getenv (argv[i])) == NULL) {
1361 			printf ("## Error: \"%s\" not defined\n", argv[i]);
1362 			return 1;
1363 		}
1364 #ifndef CFG_HUSH_PARSER
1365 		if (run_command (arg, flag) == -1)
1366 			return 1;
1367 #else
1368 		if (parse_string_outer(arg,
1369 		    FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
1370 			return 1;
1371 #endif
1372 	}
1373 	return 0;
1374 }
1375 #endif	/* CFG_CMD_RUN */
1376