blob: 29226244a1af4afa4af92ade7ce5a3a2446719a2 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
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
wdenka6c7ad22002-12-03 21:28:10 +000024/* #define DEBUG */
25
wdenkc6097192002-11-03 00:24:07 +000026#include <common.h>
27#include <watchdog.h>
28#include <command.h>
wdenkc6097192002-11-03 00:24:07 +000029
30#ifdef CFG_HUSH_PARSER
31#include <hush.h>
32#endif
33
wdenkbdccc4f2003-08-05 17:43:17 +000034#include <post.h>
35
wdenk8bde7f72003-06-27 21:31:46 +000036#if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY)
37extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); /* for do_reset() prototype */
38#endif
39
40extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
41
42
wdenkc6097192002-11-03 00:24:07 +000043#define MAX_DELAY_STOP_STR 32
44
45static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
46static int parse_line (char *, char *[]);
47#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
48static int abortboot(int);
49#endif
50
51#undef DEBUG_PARSER
52
53char console_buffer[CFG_CBSIZE]; /* console I/O buffer */
54
55static char erase_seq[] = "\b \b"; /* erase sequence */
56static char tab_seq[] = " "; /* used to expand TABs */
57
58#ifdef CONFIG_BOOT_RETRY_TIME
59static uint64_t endtime = 0; /* must be set, default is instant timeout */
60static int retry_time = -1; /* -1 so can call readline before main_loop */
61#endif
62
63#define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
64
65#ifndef CONFIG_BOOT_RETRY_MIN
66#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
67#endif
68
69#ifdef CONFIG_MODEM_SUPPORT
70int do_mdm_init = 0;
71extern void mdm_init(void); /* defined in board.c */
72#endif
73
74/***************************************************************************
75 * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
76 * returns: 0 - no key string, allow autoboot
77 * 1 - got key string, abort
78 */
79#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
80# if defined(CONFIG_AUTOBOOT_KEYED)
81static __inline__ int abortboot(int bootdelay)
82{
83 int abort = 0;
84 uint64_t etime = endtick(bootdelay);
85 struct
86 {
87 char* str;
88 u_int len;
89 int retry;
90 }
91 delaykey [] =
92 {
93 { str: getenv ("bootdelaykey"), retry: 1 },
94 { str: getenv ("bootdelaykey2"), retry: 1 },
95 { str: getenv ("bootstopkey"), retry: 0 },
96 { str: getenv ("bootstopkey2"), retry: 0 },
97 };
98
99 char presskey [MAX_DELAY_STOP_STR];
100 u_int presskey_len = 0;
101 u_int presskey_max = 0;
102 u_int i;
103
dzu8cb81432003-10-24 13:14:45 +0000104#ifdef CONFIG_SILENT_CONSOLE
105 {
106 DECLARE_GLOBAL_DATA_PTR;
107
108 if (gd->flags & GD_FLG_SILENT) {
109 /* Restore serial console */
110 console_assign (stdout, "serial");
111 console_assign (stderr, "serial");
112 }
113 }
114#endif
115
wdenkc6097192002-11-03 00:24:07 +0000116# ifdef CONFIG_AUTOBOOT_PROMPT
117 printf (CONFIG_AUTOBOOT_PROMPT, bootdelay);
118# endif
119
120# ifdef CONFIG_AUTOBOOT_DELAY_STR
121 if (delaykey[0].str == NULL)
122 delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
123# endif
124# ifdef CONFIG_AUTOBOOT_DELAY_STR2
125 if (delaykey[1].str == NULL)
126 delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
127# endif
128# ifdef CONFIG_AUTOBOOT_STOP_STR
129 if (delaykey[2].str == NULL)
130 delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
131# endif
132# ifdef CONFIG_AUTOBOOT_STOP_STR2
133 if (delaykey[3].str == NULL)
134 delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
135# endif
136
137 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
138 delaykey[i].len = delaykey[i].str == NULL ?
139 0 : strlen (delaykey[i].str);
140 delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
141 MAX_DELAY_STOP_STR : delaykey[i].len;
142
143 presskey_max = presskey_max > delaykey[i].len ?
144 presskey_max : delaykey[i].len;
145
146# if DEBUG_BOOTKEYS
147 printf("%s key:<%s>\n",
148 delaykey[i].retry ? "delay" : "stop",
149 delaykey[i].str ? delaykey[i].str : "NULL");
150# endif
151 }
152
153 /* In order to keep up with incoming data, check timeout only
154 * when catch up.
155 */
156 while (!abort && get_ticks() <= etime) {
157 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
158 if (delaykey[i].len > 0 &&
159 presskey_len >= delaykey[i].len &&
160 memcmp (presskey + presskey_len - delaykey[i].len,
wdenk8bde7f72003-06-27 21:31:46 +0000161 delaykey[i].str,
wdenkc6097192002-11-03 00:24:07 +0000162 delaykey[i].len) == 0) {
163# if DEBUG_BOOTKEYS
164 printf("got %skey\n",
165 delaykey[i].retry ? "delay" : "stop");
166# endif
167
168# ifdef CONFIG_BOOT_RETRY_TIME
169 /* don't retry auto boot */
170 if (! delaykey[i].retry)
171 retry_time = -1;
172# endif
173 abort = 1;
174 }
175 }
176
177 if (tstc()) {
178 if (presskey_len < presskey_max) {
179 presskey [presskey_len ++] = getc();
180 }
181 else {
182 for (i = 0; i < presskey_max - 1; i ++)
183 presskey [i] = presskey [i + 1];
184
185 presskey [i] = getc();
186 }
187 }
188 }
189# if DEBUG_BOOTKEYS
190 if (!abort)
wdenk4b9206e2004-03-23 22:14:11 +0000191 puts ("key timeout\n");
wdenkc6097192002-11-03 00:24:07 +0000192# endif
193
dzu8cb81432003-10-24 13:14:45 +0000194#ifdef CONFIG_SILENT_CONSOLE
195 {
196 DECLARE_GLOBAL_DATA_PTR;
197
198 if (abort) {
199 /* permanently enable normal console output */
200 gd->flags &= ~(GD_FLG_SILENT);
201 } else if (gd->flags & GD_FLG_SILENT) {
202 /* Restore silent console */
203 console_assign (stdout, "nulldev");
204 console_assign (stderr, "nulldev");
205 }
206 }
207#endif
208
wdenkc6097192002-11-03 00:24:07 +0000209 return abort;
210}
211
212# else /* !defined(CONFIG_AUTOBOOT_KEYED) */
213
wdenkc7de8292002-11-19 11:04:11 +0000214#ifdef CONFIG_MENUKEY
215static int menukey = 0;
216#endif
217
wdenkc6097192002-11-03 00:24:07 +0000218static __inline__ int abortboot(int bootdelay)
219{
220 int abort = 0;
221
wdenkf72da342003-10-10 10:05:42 +0000222#ifdef CONFIG_SILENT_CONSOLE
223 {
224 DECLARE_GLOBAL_DATA_PTR;
225
226 if (gd->flags & GD_FLG_SILENT) {
227 /* Restore serial console */
228 console_assign (stdout, "serial");
229 console_assign (stderr, "serial");
230 }
231 }
232#endif
233
wdenkc7de8292002-11-19 11:04:11 +0000234#ifdef CONFIG_MENUPROMPT
235 printf(CONFIG_MENUPROMPT, bootdelay);
236#else
wdenkc6097192002-11-03 00:24:07 +0000237 printf("Hit any key to stop autoboot: %2d ", bootdelay);
wdenkc7de8292002-11-19 11:04:11 +0000238#endif
wdenkc6097192002-11-03 00:24:07 +0000239
240#if defined CONFIG_ZERO_BOOTDELAY_CHECK
wdenk8bde7f72003-06-27 21:31:46 +0000241 /*
242 * Check if key already pressed
243 * Don't check if bootdelay < 0
244 */
wdenkc6097192002-11-03 00:24:07 +0000245 if (bootdelay >= 0) {
246 if (tstc()) { /* we got a key press */
247 (void) getc(); /* consume input */
wdenk4b9206e2004-03-23 22:14:11 +0000248 puts ("\b\b\b 0");
wdenkf72da342003-10-10 10:05:42 +0000249 abort = 1; /* don't auto boot */
wdenkc6097192002-11-03 00:24:07 +0000250 }
wdenk8bde7f72003-06-27 21:31:46 +0000251 }
wdenkc6097192002-11-03 00:24:07 +0000252#endif
253
wdenkf72da342003-10-10 10:05:42 +0000254 while ((bootdelay > 0) && (!abort)) {
wdenkc6097192002-11-03 00:24:07 +0000255 int i;
256
257 --bootdelay;
258 /* delay 100 * 10ms */
259 for (i=0; !abort && i<100; ++i) {
260 if (tstc()) { /* we got a key press */
261 abort = 1; /* don't auto boot */
262 bootdelay = 0; /* no more delay */
wdenkc7de8292002-11-19 11:04:11 +0000263# ifdef CONFIG_MENUKEY
264 menukey = getc();
265# else
wdenkc6097192002-11-03 00:24:07 +0000266 (void) getc(); /* consume input */
wdenkc7de8292002-11-19 11:04:11 +0000267# endif
wdenkc6097192002-11-03 00:24:07 +0000268 break;
269 }
270 udelay (10000);
271 }
272
273 printf ("\b\b\b%2d ", bootdelay);
274 }
275
276 putc ('\n');
277
wdenkf72da342003-10-10 10:05:42 +0000278#ifdef CONFIG_SILENT_CONSOLE
279 {
280 DECLARE_GLOBAL_DATA_PTR;
281
282 if (abort) {
283 /* permanently enable normal console output */
284 gd->flags &= ~(GD_FLG_SILENT);
285 } else if (gd->flags & GD_FLG_SILENT) {
286 /* Restore silent console */
287 console_assign (stdout, "nulldev");
288 console_assign (stderr, "nulldev");
289 }
290 }
291#endif
292
wdenkc6097192002-11-03 00:24:07 +0000293 return abort;
294}
295# endif /* CONFIG_AUTOBOOT_KEYED */
296#endif /* CONFIG_BOOTDELAY >= 0 */
297
298/****************************************************************************/
299
300void main_loop (void)
301{
302#ifndef CFG_HUSH_PARSER
303 static char lastcommand[CFG_CBSIZE] = { 0, };
304 int len;
305 int rc = 1;
306 int flag;
307#endif
308
309#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
310 char *s;
311 int bootdelay;
312#endif
313#ifdef CONFIG_PREBOOT
314 char *p;
315#endif
wdenkbdccc4f2003-08-05 17:43:17 +0000316#ifdef CONFIG_BOOTCOUNT_LIMIT
317 unsigned long bootcount = 0;
318 unsigned long bootlimit = 0;
319 char *bcs;
320 char bcs_set[16];
321#endif /* CONFIG_BOOTCOUNT_LIMIT */
wdenkc6097192002-11-03 00:24:07 +0000322
323#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
324 ulong bmp = 0; /* default bitmap */
325 extern int trab_vfd (ulong bitmap);
326
327#ifdef CONFIG_MODEM_SUPPORT
328 if (do_mdm_init)
329 bmp = 1; /* alternate bitmap */
330#endif
331 trab_vfd (bmp);
332#endif /* CONFIG_VFD && VFD_TEST_LOGO */
333
wdenkbdccc4f2003-08-05 17:43:17 +0000334#ifdef CONFIG_BOOTCOUNT_LIMIT
335 bootcount = bootcount_load();
336 bootcount++;
337 bootcount_store (bootcount);
338 sprintf (bcs_set, "%lu", bootcount);
339 setenv ("bootcount", bcs_set);
340 bcs = getenv ("bootlimit");
341 bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
342#endif /* CONFIG_BOOTCOUNT_LIMIT */
343
wdenkc6097192002-11-03 00:24:07 +0000344#ifdef CONFIG_MODEM_SUPPORT
345 debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
346 if (do_mdm_init) {
347 uchar *str = strdup(getenv("mdm_cmd"));
348 setenv ("preboot", str); /* set or delete definition */
349 if (str != NULL)
350 free (str);
351 mdm_init(); /* wait for modem connection */
352 }
353#endif /* CONFIG_MODEM_SUPPORT */
354
stroese05875972003-04-04 15:44:49 +0000355#ifdef CONFIG_VERSION_VARIABLE
356 {
357 extern char version_string[];
stroese05875972003-04-04 15:44:49 +0000358
stroese155cb012003-07-11 08:00:33 +0000359 setenv ("ver", version_string); /* set version variable */
stroese05875972003-04-04 15:44:49 +0000360 }
361#endif /* CONFIG_VERSION_VARIABLE */
362
wdenkc6097192002-11-03 00:24:07 +0000363#ifdef CFG_HUSH_PARSER
364 u_boot_hush_start ();
365#endif
366
wdenk04a85b32004-04-15 18:22:41 +0000367#ifdef CONFIG_AUTO_COMPLETE
368 install_auto_complete();
369#endif
370
wdenkc6097192002-11-03 00:24:07 +0000371#ifdef CONFIG_PREBOOT
372 if ((p = getenv ("preboot")) != NULL) {
373# ifdef CONFIG_AUTOBOOT_KEYED
374 int prev = disable_ctrlc(1); /* disable Control C checking */
375# endif
376
377# ifndef CFG_HUSH_PARSER
378 run_command (p, 0);
379# else
380 parse_string_outer(p, FLAG_PARSE_SEMICOLON |
381 FLAG_EXIT_FROM_LOOP);
382# endif
383
384# ifdef CONFIG_AUTOBOOT_KEYED
385 disable_ctrlc(prev); /* restore Control C checking */
386# endif
387 }
388#endif /* CONFIG_PREBOOT */
389
390#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
391 s = getenv ("bootdelay");
392 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
393
wdenka6c7ad22002-12-03 21:28:10 +0000394 debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
wdenkc6097192002-11-03 00:24:07 +0000395
396# ifdef CONFIG_BOOT_RETRY_TIME
wdenk6dd652f2003-06-19 23:40:20 +0000397 init_cmd_timeout ();
wdenkc6097192002-11-03 00:24:07 +0000398# endif /* CONFIG_BOOT_RETRY_TIME */
399
wdenkbdccc4f2003-08-05 17:43:17 +0000400#ifdef CONFIG_BOOTCOUNT_LIMIT
401 if (bootlimit && (bootcount > bootlimit)) {
402 printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
403 (unsigned)bootlimit);
404 s = getenv ("altbootcmd");
405 }
406 else
407#endif /* CONFIG_BOOTCOUNT_LIMIT */
408 s = getenv ("bootcmd");
wdenka6c7ad22002-12-03 21:28:10 +0000409
410 debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
411
wdenkc6097192002-11-03 00:24:07 +0000412 if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
413# ifdef CONFIG_AUTOBOOT_KEYED
414 int prev = disable_ctrlc(1); /* disable Control C checking */
415# endif
416
417# ifndef CFG_HUSH_PARSER
418 run_command (s, 0);
419# else
420 parse_string_outer(s, FLAG_PARSE_SEMICOLON |
421 FLAG_EXIT_FROM_LOOP);
422# endif
423
424# ifdef CONFIG_AUTOBOOT_KEYED
425 disable_ctrlc(prev); /* restore Control C checking */
426# endif
427 }
wdenkc7de8292002-11-19 11:04:11 +0000428
429# ifdef CONFIG_MENUKEY
wdenka6c7ad22002-12-03 21:28:10 +0000430 if (menukey == CONFIG_MENUKEY) {
wdenkc7de8292002-11-19 11:04:11 +0000431 s = getenv("menucmd");
wdenka6c7ad22002-12-03 21:28:10 +0000432 if (s) {
wdenkc7de8292002-11-19 11:04:11 +0000433# ifndef CFG_HUSH_PARSER
wdenk6225c5d2005-01-09 23:33:49 +0000434 run_command (s, 0);
wdenkc7de8292002-11-19 11:04:11 +0000435# else
436 parse_string_outer(s, FLAG_PARSE_SEMICOLON |
437 FLAG_EXIT_FROM_LOOP);
438# endif
439 }
440 }
441#endif /* CONFIG_MENUKEY */
wdenkc6097192002-11-03 00:24:07 +0000442#endif /* CONFIG_BOOTDELAY */
443
wdenkc7de8292002-11-19 11:04:11 +0000444#ifdef CONFIG_AMIGAONEG3SE
445 {
446 extern void video_banner(void);
447 video_banner();
448 }
449#endif
450
wdenkc6097192002-11-03 00:24:07 +0000451 /*
452 * Main Loop for Monitor Command Processing
453 */
454#ifdef CFG_HUSH_PARSER
455 parse_file_outer();
456 /* This point is never reached */
457 for (;;);
458#else
459 for (;;) {
460#ifdef CONFIG_BOOT_RETRY_TIME
461 if (rc >= 0) {
462 /* Saw enough of a valid command to
463 * restart the timeout.
464 */
465 reset_cmd_timeout();
466 }
467#endif
468 len = readline (CFG_PROMPT);
469
470 flag = 0; /* assume no special flags for now */
471 if (len > 0)
472 strcpy (lastcommand, console_buffer);
473 else if (len == 0)
474 flag |= CMD_FLAG_REPEAT;
475#ifdef CONFIG_BOOT_RETRY_TIME
476 else if (len == -2) {
477 /* -2 means timed out, retry autoboot
478 */
wdenk4b9206e2004-03-23 22:14:11 +0000479 puts ("\nTimed out waiting for command\n");
wdenkc6097192002-11-03 00:24:07 +0000480# ifdef CONFIG_RESET_TO_RETRY
481 /* Reinit board to run initialization code again */
482 do_reset (NULL, 0, 0, NULL);
483# else
484 return; /* retry autoboot */
485# endif
486 }
487#endif
488
489 if (len == -1)
wdenk4b9206e2004-03-23 22:14:11 +0000490 puts ("<INTERRUPT>\n");
wdenkc6097192002-11-03 00:24:07 +0000491 else
492 rc = run_command (lastcommand, flag);
493
494 if (rc <= 0) {
495 /* invalid command or not repeatable, forget it */
496 lastcommand[0] = 0;
497 }
498 }
499#endif /*CFG_HUSH_PARSER*/
500}
501
wdenk6dd652f2003-06-19 23:40:20 +0000502#ifdef CONFIG_BOOT_RETRY_TIME
503/***************************************************************************
504 * initialise command line timeout
505 */
506void init_cmd_timeout(void)
507{
508 char *s = getenv ("bootretry");
509
510 if (s != NULL)
wdenkb028f712003-12-07 21:39:28 +0000511 retry_time = (int)simple_strtol(s, NULL, 10);
wdenk6dd652f2003-06-19 23:40:20 +0000512 else
513 retry_time = CONFIG_BOOT_RETRY_TIME;
514
515 if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
516 retry_time = CONFIG_BOOT_RETRY_MIN;
517}
518
wdenkc6097192002-11-03 00:24:07 +0000519/***************************************************************************
520 * reset command line timeout to retry_time seconds
521 */
wdenkc6097192002-11-03 00:24:07 +0000522void reset_cmd_timeout(void)
523{
524 endtime = endtick(retry_time);
525}
526#endif
527
528/****************************************************************************/
529
530/*
531 * Prompt for input and read a line.
532 * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
533 * time out when time goes past endtime (timebase time in ticks).
534 * Return: number of read characters
535 * -1 if break
536 * -2 if timed out
537 */
538int readline (const char *const prompt)
539{
540 char *p = console_buffer;
541 int n = 0; /* buffer index */
542 int plen = 0; /* prompt length */
543 int col; /* output column cnt */
544 char c;
545
546 /* print prompt */
547 if (prompt) {
548 plen = strlen (prompt);
549 puts (prompt);
550 }
551 col = plen;
552
553 for (;;) {
554#ifdef CONFIG_BOOT_RETRY_TIME
555 while (!tstc()) { /* while no incoming data */
556 if (retry_time >= 0 && get_ticks() > endtime)
557 return (-2); /* timed out */
558 }
559#endif
560 WATCHDOG_RESET(); /* Trigger watchdog, if needed */
561
562#ifdef CONFIG_SHOW_ACTIVITY
563 while (!tstc()) {
564 extern void show_activity(int arg);
565 show_activity(0);
566 }
567#endif
568 c = getc();
569
570 /*
571 * Special character handling
572 */
573 switch (c) {
574 case '\r': /* Enter */
575 case '\n':
576 *p = '\0';
577 puts ("\r\n");
578 return (p - console_buffer);
579
wdenk27aa8182004-03-23 22:37:33 +0000580 case '\0': /* nul */
581 continue;
582
wdenkc6097192002-11-03 00:24:07 +0000583 case 0x03: /* ^C - break */
584 console_buffer[0] = '\0'; /* discard input */
585 return (-1);
586
587 case 0x15: /* ^U - erase line */
588 while (col > plen) {
589 puts (erase_seq);
590 --col;
591 }
592 p = console_buffer;
593 n = 0;
594 continue;
595
596 case 0x17: /* ^W - erase word */
597 p=delete_char(console_buffer, p, &col, &n, plen);
598 while ((n > 0) && (*p != ' ')) {
599 p=delete_char(console_buffer, p, &col, &n, plen);
600 }
601 continue;
602
603 case 0x08: /* ^H - backspace */
604 case 0x7F: /* DEL - backspace */
605 p=delete_char(console_buffer, p, &col, &n, plen);
606 continue;
607
608 default:
609 /*
610 * Must be a normal character then
611 */
612 if (n < CFG_CBSIZE-2) {
613 if (c == '\t') { /* expand TABs */
wdenk04a85b32004-04-15 18:22:41 +0000614#ifdef CONFIG_AUTO_COMPLETE
615 /* if auto completion triggered just continue */
616 *p = '\0';
617 if (cmd_auto_complete(prompt, console_buffer, &n, &col)) {
618 p = console_buffer + n; /* reset */
619 continue;
620 }
621#endif
wdenkc6097192002-11-03 00:24:07 +0000622 puts (tab_seq+(col&07));
623 col += 8 - (col&07);
624 } else {
625 ++col; /* echo input */
626 putc (c);
627 }
628 *p++ = c;
629 ++n;
630 } else { /* Buffer full */
631 putc ('\a');
632 }
633 }
634 }
635}
636
637/****************************************************************************/
638
639static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
640{
641 char *s;
642
643 if (*np == 0) {
644 return (p);
645 }
646
647 if (*(--p) == '\t') { /* will retype the whole line */
648 while (*colp > plen) {
649 puts (erase_seq);
650 (*colp)--;
651 }
652 for (s=buffer; s<p; ++s) {
653 if (*s == '\t') {
654 puts (tab_seq+((*colp) & 07));
655 *colp += 8 - ((*colp) & 07);
656 } else {
657 ++(*colp);
658 putc (*s);
659 }
660 }
661 } else {
662 puts (erase_seq);
663 (*colp)--;
664 }
665 (*np)--;
666 return (p);
667}
668
669/****************************************************************************/
670
671int parse_line (char *line, char *argv[])
672{
673 int nargs = 0;
674
675#ifdef DEBUG_PARSER
676 printf ("parse_line: \"%s\"\n", line);
677#endif
678 while (nargs < CFG_MAXARGS) {
679
680 /* skip any white space */
681 while ((*line == ' ') || (*line == '\t')) {
682 ++line;
683 }
684
685 if (*line == '\0') { /* end of line, no more args */
686 argv[nargs] = NULL;
687#ifdef DEBUG_PARSER
688 printf ("parse_line: nargs=%d\n", nargs);
689#endif
690 return (nargs);
691 }
692
693 argv[nargs++] = line; /* begin of argument string */
694
695 /* find end of string */
696 while (*line && (*line != ' ') && (*line != '\t')) {
697 ++line;
698 }
699
700 if (*line == '\0') { /* end of line, no more args */
701 argv[nargs] = NULL;
702#ifdef DEBUG_PARSER
703 printf ("parse_line: nargs=%d\n", nargs);
704#endif
705 return (nargs);
706 }
707
708 *line++ = '\0'; /* terminate current arg */
709 }
710
711 printf ("** Too many args (max. %d) **\n", CFG_MAXARGS);
712
713#ifdef DEBUG_PARSER
714 printf ("parse_line: nargs=%d\n", nargs);
715#endif
716 return (nargs);
717}
718
719/****************************************************************************/
720
721static void process_macros (const char *input, char *output)
722{
723 char c, prev;
724 const char *varname_start = NULL;
725 int inputcnt = strlen (input);
726 int outputcnt = CFG_CBSIZE;
727 int state = 0; /* 0 = waiting for '$' */
wdenk5cf91d62004-04-23 20:32:05 +0000728 /* 1 = waiting for '(' or '{' */
729 /* 2 = waiting for ')' or '}' */
wdenk8bde7f72003-06-27 21:31:46 +0000730 /* 3 = waiting for ''' */
wdenkc6097192002-11-03 00:24:07 +0000731#ifdef DEBUG_PARSER
732 char *output_start = output;
733
734 printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input), input);
735#endif
736
737 prev = '\0'; /* previous character */
738
739 while (inputcnt && outputcnt) {
740 c = *input++;
741 inputcnt--;
742
wdenka25f8622003-01-02 23:57:29 +0000743 if (state!=3) {
wdenkc6097192002-11-03 00:24:07 +0000744 /* remove one level of escape characters */
745 if ((c == '\\') && (prev != '\\')) {
746 if (inputcnt-- == 0)
747 break;
748 prev = c;
wdenk8bde7f72003-06-27 21:31:46 +0000749 c = *input++;
wdenkc6097192002-11-03 00:24:07 +0000750 }
wdenka25f8622003-01-02 23:57:29 +0000751 }
wdenkc6097192002-11-03 00:24:07 +0000752
753 switch (state) {
754 case 0: /* Waiting for (unescaped) $ */
wdenka25f8622003-01-02 23:57:29 +0000755 if ((c == '\'') && (prev != '\\')) {
756 state = 3;
wdenka25f8622003-01-02 23:57:29 +0000757 break;
758 }
wdenkc6097192002-11-03 00:24:07 +0000759 if ((c == '$') && (prev != '\\')) {
760 state++;
761 } else {
762 *(output++) = c;
763 outputcnt--;
764 }
765 break;
766 case 1: /* Waiting for ( */
wdenk5cf91d62004-04-23 20:32:05 +0000767 if (c == '(' || c == '{') {
wdenkc6097192002-11-03 00:24:07 +0000768 state++;
769 varname_start = input;
770 } else {
771 state = 0;
772 *(output++) = '$';
773 outputcnt--;
774
775 if (outputcnt) {
776 *(output++) = c;
777 outputcnt--;
778 }
779 }
780 break;
781 case 2: /* Waiting for ) */
wdenk5cf91d62004-04-23 20:32:05 +0000782 if (c == ')' || c == '}') {
wdenkc6097192002-11-03 00:24:07 +0000783 int i;
784 char envname[CFG_CBSIZE], *envval;
785 int envcnt = input-varname_start-1; /* Varname # of chars */
786
787 /* Get the varname */
788 for (i = 0; i < envcnt; i++) {
789 envname[i] = varname_start[i];
790 }
791 envname[i] = 0;
792
793 /* Get its value */
794 envval = getenv (envname);
795
796 /* Copy into the line if it exists */
797 if (envval != NULL)
798 while ((*envval) && outputcnt) {
799 *(output++) = *(envval++);
800 outputcnt--;
801 }
802 /* Look for another '$' */
803 state = 0;
804 }
805 break;
wdenka25f8622003-01-02 23:57:29 +0000806 case 3: /* Waiting for ' */
807 if ((c == '\'') && (prev != '\\')) {
808 state = 0;
wdenka25f8622003-01-02 23:57:29 +0000809 } else {
810 *(output++) = c;
811 outputcnt--;
812 }
813 break;
wdenkc6097192002-11-03 00:24:07 +0000814 }
wdenkc6097192002-11-03 00:24:07 +0000815 prev = c;
816 }
817
818 if (outputcnt)
819 *output = 0;
820
821#ifdef DEBUG_PARSER
822 printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
823 strlen(output_start), output_start);
824#endif
825}
826
827/****************************************************************************
828 * returns:
829 * 1 - command executed, repeatable
830 * 0 - command executed but not repeatable, interrupted commands are
831 * always considered not repeatable
832 * -1 - not executed (unrecognized, bootd recursion or too many args)
833 * (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
834 * considered unrecognized)
835 *
836 * WARNING:
837 *
838 * We must create a temporary copy of the command since the command we get
839 * may be the result from getenv(), which returns a pointer directly to
840 * the environment data, which may change magicly when the command we run
841 * creates or modifies environment variables (like "bootp" does).
842 */
843
844int run_command (const char *cmd, int flag)
845{
846 cmd_tbl_t *cmdtp;
847 char cmdbuf[CFG_CBSIZE]; /* working copy of cmd */
848 char *token; /* start of token in cmdbuf */
849 char *sep; /* end of token (separator) in cmdbuf */
850 char finaltoken[CFG_CBSIZE];
851 char *str = cmdbuf;
852 char *argv[CFG_MAXARGS + 1]; /* NULL terminated */
wdenkf07771c2003-05-28 08:06:31 +0000853 int argc, inquotes;
wdenkc6097192002-11-03 00:24:07 +0000854 int repeatable = 1;
wdenkf07771c2003-05-28 08:06:31 +0000855 int rc = 0;
wdenkc6097192002-11-03 00:24:07 +0000856
857#ifdef DEBUG_PARSER
858 printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
859 puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
860 puts ("\"\n");
861#endif
862
863 clear_ctrlc(); /* forget any previous Control C */
864
865 if (!cmd || !*cmd) {
866 return -1; /* empty command */
867 }
868
869 if (strlen(cmd) >= CFG_CBSIZE) {
870 puts ("## Command too long!\n");
871 return -1;
872 }
873
874 strcpy (cmdbuf, cmd);
875
876 /* Process separators and check for invalid
877 * repeatable commands
878 */
879
880#ifdef DEBUG_PARSER
881 printf ("[PROCESS_SEPARATORS] %s\n", cmd);
882#endif
883 while (*str) {
884
885 /*
886 * Find separator, or string end
887 * Allow simple escape of ';' by writing "\;"
888 */
wdenka25f8622003-01-02 23:57:29 +0000889 for (inquotes = 0, sep = str; *sep; sep++) {
890 if ((*sep=='\'') &&
891 (*(sep-1) != '\\'))
892 inquotes=!inquotes;
893
894 if (!inquotes &&
895 (*sep == ';') && /* separator */
wdenkc6097192002-11-03 00:24:07 +0000896 ( sep != str) && /* past string start */
897 (*(sep-1) != '\\')) /* and NOT escaped */
898 break;
899 }
900
901 /*
902 * Limit the token to data between separators
903 */
904 token = str;
905 if (*sep) {
906 str = sep + 1; /* start of command for next pass */
907 *sep = '\0';
908 }
909 else
910 str = sep; /* no more commands for next pass */
911#ifdef DEBUG_PARSER
912 printf ("token: \"%s\"\n", token);
913#endif
914
915 /* find macros in this token and replace them */
916 process_macros (token, finaltoken);
917
918 /* Extract arguments */
919 argc = parse_line (finaltoken, argv);
920
921 /* Look up command in command table */
922 if ((cmdtp = find_cmd(argv[0])) == NULL) {
923 printf ("Unknown command '%s' - try 'help'\n", argv[0]);
wdenkf07771c2003-05-28 08:06:31 +0000924 rc = -1; /* give up after bad command */
925 continue;
wdenkc6097192002-11-03 00:24:07 +0000926 }
927
928 /* found - check max args */
929 if (argc > cmdtp->maxargs) {
930 printf ("Usage:\n%s\n", cmdtp->usage);
wdenkf07771c2003-05-28 08:06:31 +0000931 rc = -1;
932 continue;
wdenkc6097192002-11-03 00:24:07 +0000933 }
934
935#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
936 /* avoid "bootd" recursion */
937 if (cmdtp->cmd == do_bootd) {
938#ifdef DEBUG_PARSER
939 printf ("[%s]\n", finaltoken);
940#endif
941 if (flag & CMD_FLAG_BOOTD) {
wdenk4b9206e2004-03-23 22:14:11 +0000942 puts ("'bootd' recursion detected\n");
wdenkf07771c2003-05-28 08:06:31 +0000943 rc = -1;
944 continue;
wdenkc6097192002-11-03 00:24:07 +0000945 }
946 else
947 flag |= CMD_FLAG_BOOTD;
948 }
949#endif /* CFG_CMD_BOOTD */
950
951 /* OK - call function to do the command */
952 if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
wdenkf07771c2003-05-28 08:06:31 +0000953 rc = -1;
wdenkc6097192002-11-03 00:24:07 +0000954 }
955
956 repeatable &= cmdtp->repeatable;
957
958 /* Did the user stop this? */
959 if (had_ctrlc ())
960 return 0; /* if stopped then not repeatable */
961 }
962
wdenkf07771c2003-05-28 08:06:31 +0000963 return rc ? rc : repeatable;
wdenkc6097192002-11-03 00:24:07 +0000964}
965
966/****************************************************************************/
967
968#if (CONFIG_COMMANDS & CFG_CMD_RUN)
969int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
970{
971 int i;
wdenkc6097192002-11-03 00:24:07 +0000972
973 if (argc < 2) {
974 printf ("Usage:\n%s\n", cmdtp->usage);
975 return 1;
976 }
977
978 for (i=1; i<argc; ++i) {
wdenk3e386912003-04-05 00:53:31 +0000979 char *arg;
980
981 if ((arg = getenv (argv[i])) == NULL) {
982 printf ("## Error: \"%s\" not defined\n", argv[i]);
983 return 1;
984 }
wdenkc6097192002-11-03 00:24:07 +0000985#ifndef CFG_HUSH_PARSER
wdenk3e386912003-04-05 00:53:31 +0000986 if (run_command (arg, flag) == -1)
987 return 1;
wdenkc6097192002-11-03 00:24:07 +0000988#else
wdenk3e386912003-04-05 00:53:31 +0000989 if (parse_string_outer(arg,
wdenk7aa78612003-05-03 15:50:43 +0000990 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
wdenk3e386912003-04-05 00:53:31 +0000991 return 1;
wdenkc6097192002-11-03 00:24:07 +0000992#endif
993 }
wdenk3e386912003-04-05 00:53:31 +0000994 return 0;
wdenkc6097192002-11-03 00:24:07 +0000995}
wdenk3e386912003-04-05 00:53:31 +0000996#endif /* CFG_CMD_RUN */