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