42f3d57d2d37e859b37aa0bb1cfb8cb153063058
[oweals/u-boot_mod.git] / u-boot / common / main.c
1 /*
2  * (C) Copyright 2000
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /* #define      DEBUG   */
25
26 #include <common.h>
27 #include <command.h>
28
29 #ifdef CFG_HUSH_PARSER
30 #include <hush.h>
31 #endif
32
33 #ifdef CONFIG_SILENT_CONSOLE
34 DECLARE_GLOBAL_DATA_PTR;
35 #endif
36
37 extern int reset_button_status(void);
38 extern void all_led_on(void);
39 extern void all_led_off(void);
40 extern int NetLoopHttpd(void);
41
42 #define MAX_DELAY_STOP_STR 32
43
44 static char *delete_char(char *buffer, char *p, int *colp, int *np, int plen);
45 static int parse_line(char *, char *[]);
46 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
47 static int abortboot(int);
48 #endif
49
50 char console_buffer[CFG_CBSIZE]; /* console I/O buffer  */
51 static char erase_seq[] = "\b \b"; /* erase sequence    */
52 static char tab_seq[] = "        "; /* used to expand TABs      */
53
54 /***************************************************************************
55  * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
56  * returns: 0 -  no key string, allow autoboot
57  *          1 - got key string, abort
58  */
59 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
60 static __inline__ int abortboot(int bootdelay){
61 #ifdef CONFIG_AUTOBOOT_STOP_CHAR
62         char stopc;
63 #endif
64         int abort = 0;
65
66 #ifdef CONFIG_SILENT_CONSOLE
67         if(gd->flags & GD_FLG_SILENT){
68                 /* Restore serial console */
69                 console_assign(stdout, "serial");
70                 console_assign(stderr, "serial");
71         }
72 #endif
73
74         if(bootdelay > 0){
75 #ifdef CONFIG_MENUPROMPT
76                 printf(CONFIG_MENUPROMPT, bootdelay);
77 #else
78                 printf("Hit any key to stop autoboot: %d ", bootdelay);
79 #endif
80
81                 while((bootdelay > 0) && (!abort)){
82                         int i;
83
84                         --bootdelay;
85
86                         /* delay 100 * 10ms */
87                         for(i = 0; !abort && i < 100; ++i){
88
89                                 /* we got a key press   */
90                                 if(tstc()){
91 #ifdef CONFIG_AUTOBOOT_STOP_CHAR
92                                         stopc = getc();
93                                         if (stopc == CONFIG_AUTOBOOT_STOP_CHAR) {
94                                                 abort = 1;
95                                                 bootdelay = 0;
96
97                                                 break;
98                                         }
99 #else
100                                         /* don't auto boot      */
101                                         abort = 1;
102                                         /* no more delay        */
103                                         bootdelay = 0;
104                                         /* consume input        */
105                                         (void) getc();
106                                         break;
107 #endif /* CONFIG_AUTOBOOT_STOP_CHAR */
108                                 }
109                                 udelay(10000);
110                         }
111
112                         printf("\b\b%d ", bootdelay);
113                 }
114
115                 printf("\n\n");
116         }
117
118 #ifdef CONFIG_SILENT_CONSOLE
119         if(abort){
120                 /* permanently enable normal console output */
121                 gd->flags &= ~(GD_FLG_SILENT);
122         } else if(gd->flags & GD_FLG_SILENT){
123                 /* Restore silent console */
124                 console_assign(stdout, "nulldev");
125                 console_assign(stderr, "nulldev");
126         }
127 #endif
128
129         return(abort);
130 }
131 #endif  /* CONFIG_BOOTDELAY >= 0  */
132
133 /****************************************************************************/
134
135 void main_loop(void){
136 #ifndef CFG_HUSH_PARSER
137         static char lastcommand[CFG_CBSIZE] = { 0, };
138         int len;
139         int rc = 1;
140         int flag;
141 #endif
142         int counter = 0;
143
144 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
145         char *s;
146         int bootdelay;
147 #endif /* defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) */
148
149 #ifdef CFG_HUSH_PARSER
150         u_boot_hush_start();
151 #endif
152
153 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
154         // get boot delay (seconds)
155         s = getenv("bootdelay");
156         bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
157
158         // get boot command
159         s = getenv("bootcmd");
160
161 #if !defined(CONFIG_BOOTCOMMAND)
162 #error "CONFIG_BOOTCOMMAND not defined!"
163 #endif
164
165         if(!s){
166                 setenv("bootcmd", CONFIG_BOOTCOMMAND);
167         }
168
169         s = getenv("bootcmd");
170
171         // are we going to run web failsafe mode, U-Boot console, U-Boot netconsole or just boot command?
172         if(reset_button_status()){
173
174 #ifdef CONFIG_SILENT_CONSOLE
175                 if(gd->flags & GD_FLG_SILENT){
176                         /* Restore serial console */
177                         console_assign(stdout, "serial");
178                         console_assign(stderr, "serial");
179                 }
180
181                 /* enable normal console output */
182                 gd->flags &= ~(GD_FLG_SILENT);
183 #endif
184
185                 // wait 0,5s
186                 milisecdelay(500);
187
188                 printf("Press reset button for at least:\n- %d sec. to run web failsafe mode\n- %d sec. to run U-Boot console\n- %d sec. to run U-Boot netconsole\n\n",
189                                 CONFIG_DELAY_TO_AUTORUN_HTTPD,
190                                 CONFIG_DELAY_TO_AUTORUN_CONSOLE,
191                                 CONFIG_DELAY_TO_AUTORUN_NETCONSOLE);
192
193                 printf("Reset button is pressed for: %2d ", counter);
194
195                 while(reset_button_status()){
196
197                         // LED ON and wait 0,15s
198                         all_led_on();
199                         milisecdelay(150);
200
201                         // LED OFF and wait 0,85s
202                         all_led_off();
203                         milisecdelay(850);
204
205                         counter++;
206
207                         // how long the button is pressed?
208                         printf("\b\b\b%2d ", counter);
209
210                         if(!reset_button_status()){
211                                 break;
212                         }
213
214                         if(counter >= CONFIG_MAX_BUTTON_PRESSING){
215                                 break;
216                         }
217                 }
218
219                 all_led_off();
220
221                 if(counter > 0){
222
223                         // run web failsafe mode
224                         if(counter >= CONFIG_DELAY_TO_AUTORUN_HTTPD && counter < CONFIG_DELAY_TO_AUTORUN_CONSOLE){
225                                 printf("\n\nButton was pressed for %d sec...\nHTTP server is starting for firmware update...\n\n", counter);
226                                 NetLoopHttpd();
227                                 bootdelay = -1;
228                         } else if(counter >= CONFIG_DELAY_TO_AUTORUN_CONSOLE && counter < CONFIG_DELAY_TO_AUTORUN_NETCONSOLE){
229                                 printf("\n\nButton was pressed for %d sec...\nStarting U-Boot console...\n\n", counter);
230                                 bootdelay = -1;
231                         } else if(counter >= CONFIG_DELAY_TO_AUTORUN_NETCONSOLE){
232                                 printf("\n\nButton was pressed for %d sec...\nStarting U-Boot netconsole...\n\n", counter);
233                                 bootdelay = -1;
234                                 run_command("startnc", 0);
235                         } else {
236                                 printf("\n\n## Error: button wasn't pressed long enough!\nContinuing normal boot...\n\n");
237                         }
238
239                 } else {
240                         printf("\n\n## Error: button wasn't pressed long enough!\nContinuing normal boot...\n\n");
241                 }
242
243         }
244
245         if(bootdelay >= 0 && s && !abortboot(bootdelay)){
246
247                 // try to boot
248 #ifndef CFG_HUSH_PARSER
249                         run_command(s, 0);
250 #else
251                         parse_string_outer(s, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);
252 #endif
253
254                 // something goes wrong!
255                 printf("\n## Error: failed to execute 'bootcmd'!\nHTTP server is starting for firmware update...\n\n");
256                 NetLoopHttpd();
257         }
258 #endif  /* CONFIG_BOOTDELAY */
259
260         /*
261          * Main Loop for Monitor Command Processing
262          */
263 #ifdef CFG_HUSH_PARSER
264         parse_file_outer();
265         /* This point is never reached */
266         for (;;);
267 #else
268         for(;;){
269                 len = readline(CFG_PROMPT);
270
271                 flag = 0; /* assume no special flags for now */
272                 if(len > 0){
273                         strcpy(lastcommand, console_buffer);
274                 } else if(len == 0){
275                         flag |= CMD_FLAG_REPEAT;
276                 }
277
278                 if(len == -1){
279                         puts("<INTERRUPT>\n");
280                 } else {
281                         rc = run_command(lastcommand, flag);
282                 }
283
284                 if(rc <= 0){
285                         /* invalid command or not repeatable, forget it */
286                         lastcommand[0] = 0;
287                 }
288         }
289 #endif /* CFG_HUSH_PARSER */
290 }
291
292 /****************************************************************************/
293
294 /*
295  * Prompt for input and read a line.
296  * If  CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
297  * time out when time goes past endtime (timebase time in ticks).
298  * Return:      number of read characters
299  *              -1 if break
300  *              -2 if timed out
301  */
302 int readline(const char * const prompt){
303         char *p = console_buffer;
304         int n = 0; /* buffer index              */
305         int plen = 0; /* prompt length  */
306         int col; /* output column cnt   */
307         char c;
308
309         /* print prompt */
310         if(prompt){
311                 plen = strlen(prompt);
312                 puts(prompt);
313         }
314         col = plen;
315
316         for(;;){
317                 c = getc();
318
319                 /*
320                  * Special character handling
321                  */
322                 switch(c){
323                         case '\r': /* Enter             */
324                         case '\n':
325                                 *p = '\0';
326                                 puts("\r\n");
327                                 return(p - console_buffer);
328
329                         case '\0': /* nul                       */
330                                 continue;
331
332                         case 0x03: /* ^C - break                */
333                                 console_buffer[0] = '\0'; /* discard input */
334                                 return(-1);
335
336                         case 0x15: /* ^U - erase line   */
337                                 while(col > plen){
338                                         puts(erase_seq);
339                                         --col;
340                                 }
341                                 p = console_buffer;
342                                 n = 0;
343                                 continue;
344
345                         case 0x17: /* ^W - erase word   */
346                                 p = delete_char(console_buffer, p, &col, &n, plen);
347                                 while((n > 0) && (*p != ' ')){
348                                         p = delete_char(console_buffer, p, &col, &n, plen);
349                                 }
350                                 continue;
351
352                         case 0x08: /* ^H  - backspace   */
353                         case 0x7F: /* DEL - backspace   */
354                                 p = delete_char(console_buffer, p, &col, &n, plen);
355                                 continue;
356
357                         default:
358                                 /*
359                                  * Must be a normal character then
360                                  */
361                                 if(n < CFG_CBSIZE - 2){
362                                         if(c == '\t'){ /* expand TABs           */
363                                                 puts(tab_seq + (col & 07));
364                                                 col += 8 - (col & 07);
365                                         } else {
366                                                 ++col; /* echo input            */
367                                                 putc(c);
368                                         }
369                                         *p++ = c;
370                                         ++n;
371                                 } else { /* Buffer full         */
372                                         putc('\a');
373                                 }
374                 }
375         }
376 }
377
378 /****************************************************************************/
379
380 static char * delete_char(char *buffer, char *p, int *colp, int *np, int plen){
381         char *s;
382
383         if(*np == 0){
384                 return(p);
385         }
386
387         if(*(--p) == '\t'){ /* will retype the whole line       */
388                 while(*colp > plen){
389                         puts(erase_seq);
390                         (*colp)--;
391                 }
392                 for(s = buffer; s < p; ++s){
393                         if(*s == '\t'){
394                                 puts(tab_seq + ((*colp) & 07));
395                                 *colp += 8 - ((*colp) & 07);
396                         } else {
397                                 ++(*colp);
398                                 putc(*s);
399                         }
400                 }
401         } else {
402                 puts(erase_seq);
403                 (*colp)--;
404         }
405         (*np)--;
406         return(p);
407 }
408
409 /****************************************************************************/
410
411 int parse_line(char *line, char *argv[]){
412         int nargs = 0;
413
414         while(nargs < CFG_MAXARGS){
415
416                 /* skip any white space */
417                 while((*line == ' ') || (*line == '\t')){
418                         ++line;
419                 }
420
421                 if(*line == '\0'){ /* end of line, no more args */
422                         argv[nargs] = NULL;
423                         return(nargs);
424                 }
425
426                 argv[nargs++] = line; /* begin of argument string       */
427
428                 /* find end of string */
429                 while(*line && (*line != ' ') && (*line != '\t')){
430                         ++line;
431                 }
432
433                 if(*line == '\0'){ /* end of line, no more args */
434                         argv[nargs] = NULL;
435                         return(nargs);
436                 }
437
438                 *line++ = '\0'; /* terminate current arg         */
439         }
440
441         printf("## Error: too many args (max. %d)\n", CFG_MAXARGS);
442
443         return(nargs);
444 }
445
446 /****************************************************************************/
447
448 static void process_macros(const char *input, char *output){
449         char c, prev;
450         const char *varname_start = NULL;
451         int inputcnt = strlen(input);
452         int outputcnt = CFG_CBSIZE;
453         int state = 0; /* 0 = waiting for '$'   */
454         /* 1 = waiting for '(' or '{' */
455         /* 2 = waiting for ')' or '}' */
456         /* 3 = waiting for '''  */
457
458         prev = '\0'; /* previous character      */
459
460         while(inputcnt && outputcnt){
461                 c = *input++;
462                 inputcnt--;
463
464                 if(state != 3){
465                         /* remove one level of escape characters */
466                         if((c == '\\') && (prev != '\\')){
467                                 if(inputcnt-- == 0){
468                                         break;
469                                 }
470
471                                 prev = c;
472                                 c = *input++;
473                         }
474                 }
475
476                 switch(state){
477                         case 0: /* Waiting for (unescaped) $    */
478                                 if((c == '\'') && (prev != '\\')){
479                                         state = 3;
480                                         break;
481                                 }
482                                 if((c == '$') && (prev != '\\')){
483                                         state++;
484                                 } else {
485                                         *(output++) = c;
486                                         outputcnt--;
487                                 }
488                                 break;
489                         case 1: /* Waiting for (        */
490                                 if(c == '(' || c == '{'){
491                                         state++;
492                                         varname_start = input;
493                                 } else {
494                                         state = 0;
495                                         *(output++) = '$';
496                                         outputcnt--;
497
498                                         if(outputcnt){
499                                                 *(output++) = c;
500                                                 outputcnt--;
501                                         }
502                                 }
503                                 break;
504                         case 2: /* Waiting for )        */
505                                 if(c == ')' || c == '}'){
506                                         int i;
507                                         char envname[CFG_CBSIZE], *envval;
508                                         int envcnt = input - varname_start - 1; /* Varname # of chars */
509
510                                         /* Get the varname */
511                                         for(i = 0; i < envcnt; i++){
512                                                 envname[i] = varname_start[i];
513                                         }
514                                         envname[i] = 0;
515
516                                         /* Get its value */
517                                         envval = getenv(envname);
518
519                                         /* Copy into the line if it exists */
520                                         if(envval != NULL){
521                                                 while((*envval) && outputcnt){
522                                                         *(output++) = *(envval++);
523                                                         outputcnt--;
524                                                 }
525                                         }
526                                         /* Look for another '$' */
527                                         state = 0;
528                                 }
529                                 break;
530                         case 3: /* Waiting for '        */
531                                 if((c == '\'') && (prev != '\\')){
532                                         state = 0;
533                                 } else {
534                                         *(output++) = c;
535                                         outputcnt--;
536                                 }
537                                 break;
538                 }
539                 prev = c;
540         }
541
542         if(outputcnt){
543                 *output = 0;
544         }
545 }
546
547 /****************************************************************************
548  * returns:
549  *      1  - command executed, repeatable
550  *      0  - command executed but not repeatable, interrupted commands are
551  *           always considered not repeatable
552  *      -1 - not executed (unrecognized, bootd recursion or too many args)
553  *           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
554  *           considered unrecognized)
555  *
556  * WARNING:
557  *
558  * We must create a temporary copy of the command since the command we get
559  * may be the result from getenv(), which returns a pointer directly to
560  * the environment data, which may change magicly when the command we run
561  * creates or modifies environment variables (like "bootp" does).
562  */
563
564 int run_command(const char *cmd, int flag){
565         cmd_tbl_t *cmdtp;
566         char cmdbuf[CFG_CBSIZE]; /* working copy of cmd         */
567         char *token; /* start of token in cmdbuf        */
568         char *sep; /* end of token (separator) in cmdbuf */
569         char finaltoken[CFG_CBSIZE];
570         char *str = cmdbuf;
571         char *argv[CFG_MAXARGS + 1]; /* NULL terminated */
572         int argc, inquotes;
573         int repeatable = 1;
574         int rc = 0;
575
576         clear_ctrlc(); /* forget any previous Control C */
577
578         if(!cmd || !*cmd){
579                 return(-1); /* empty command */
580         }
581
582         if(strlen(cmd) >= CFG_CBSIZE){
583                 puts("## Error: command too long!\n");
584                 return(-1);
585         }
586
587         strcpy(cmdbuf, cmd);
588
589         /* Process separators and check for invalid
590          * repeatable commands
591          */
592         while(*str){
593
594                 /*
595                  * Find separator, or string end
596                  * Allow simple escape of ';' by writing "\;"
597                  */
598                 for(inquotes = 0, sep = str; *sep; sep++){
599                         if((*sep == '\'') && (*(sep - 1) != '\\')){
600                                 inquotes = !inquotes;
601                         }
602
603                         if(!inquotes && (*sep == ';') && (sep != str) && (*(sep - 1) != '\\')){
604                                 break;
605                         }
606                 }
607
608                 /*
609                  * Limit the token to data between separators
610                  */
611                 token = str;
612                 if(*sep){
613                         str = sep + 1; /* start of command for next pass */
614                         *sep = '\0';
615                 } else {
616                         str = sep; /* no more commands for next pass */
617                 }
618
619                 /* find macros in this token and replace them */
620                 process_macros(token, finaltoken);
621
622                 /* Extract arguments */
623                 if((argc = parse_line(finaltoken, argv)) == 0){
624                         rc = -1; /* no command at all */
625                         continue;
626                 }
627
628                 /* Look up command in command table */
629                 if((cmdtp = find_cmd(argv[0])) == NULL){
630                         printf("## Error: unknown command '%s' - try 'help'\n\n", argv[0]);
631                         rc = -1; /* give up after bad command */
632                         continue;
633                 }
634
635                 /* found - check max args */
636                 if(argc > cmdtp->maxargs){
637 #ifdef CFG_LONGHELP
638                         if(cmdtp->help != NULL){
639                                 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
640                         } else {
641                                 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
642                         }
643 #else
644                         printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
645 #endif
646                         rc = -1;
647                         continue;
648                 }
649
650                 /* OK - call function to do the command */
651                 if((cmdtp->cmd)(cmdtp, flag, argc, argv) != 0){
652                         rc = -1;
653                 }
654
655                 repeatable &= cmdtp->repeatable;
656
657                 /* Did the user stop this? */
658                 if(had_ctrlc()){ /* if stopped then not repeatable */
659                         return(0);
660                 }
661         }
662
663         return(rc ? rc : repeatable);
664 }
665
666 /****************************************************************************/
667
668 #if (CONFIG_COMMANDS & CFG_CMD_RUN)
669 int do_run(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){
670         int i;
671
672         if(argc < 2){
673 #ifdef CFG_LONGHELP
674                 if(cmdtp->help != NULL){
675                         printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
676                 } else {
677                         printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
678                 }
679 #else
680                 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
681 #endif
682                 return(1);
683         }
684
685         for(i=1; i<argc; ++i){
686                 char *arg;
687
688                 if((arg = getenv(argv[i])) == NULL){
689                         printf("## Error: \"%s\" not defined\n", argv[i]);
690                         return(1);
691                 }
692 #ifndef CFG_HUSH_PARSER
693                 if(run_command(arg, flag) == -1){
694                         return(1);
695                 }
696 #else
697                 if (parse_string_outer(arg, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0){
698                         return(1);
699                 }
700 #endif /* CFG_HUSH_PARSER */
701         }
702
703         return(0);
704 }
705 #endif  /* CFG_CMD_RUN */