1*c609719bSwdenk /* 2*c609719bSwdenk * (C) Copyright 2000 3*c609719bSwdenk * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4*c609719bSwdenk * 5*c609719bSwdenk * See file CREDITS for list of people who contributed to this 6*c609719bSwdenk * project. 7*c609719bSwdenk * 8*c609719bSwdenk * This program is free software; you can redistribute it and/or 9*c609719bSwdenk * modify it under the terms of the GNU General Public License as 10*c609719bSwdenk * published by the Free Software Foundation; either version 2 of 11*c609719bSwdenk * the License, or (at your option) any later version. 12*c609719bSwdenk * 13*c609719bSwdenk * This program is distributed in the hope that it will be useful, 14*c609719bSwdenk * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*c609719bSwdenk * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*c609719bSwdenk * GNU General Public License for more details. 17*c609719bSwdenk * 18*c609719bSwdenk * You should have received a copy of the GNU General Public License 19*c609719bSwdenk * along with this program; if not, write to the Free Software 20*c609719bSwdenk * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21*c609719bSwdenk * MA 02111-1307 USA 22*c609719bSwdenk */ 23*c609719bSwdenk 24*c609719bSwdenk #include <common.h> 25*c609719bSwdenk #include <watchdog.h> 26*c609719bSwdenk #include <command.h> 27*c609719bSwdenk #include <cmd_nvedit.h> 28*c609719bSwdenk #include <cmd_bootm.h> 29*c609719bSwdenk #include <malloc.h> 30*c609719bSwdenk #if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY) 31*c609719bSwdenk #include <cmd_boot.h> /* for do_reset() prototype */ 32*c609719bSwdenk #endif 33*c609719bSwdenk 34*c609719bSwdenk #ifdef CFG_HUSH_PARSER 35*c609719bSwdenk #include <hush.h> 36*c609719bSwdenk #endif 37*c609719bSwdenk 38*c609719bSwdenk #define MAX_DELAY_STOP_STR 32 39*c609719bSwdenk 40*c609719bSwdenk static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen); 41*c609719bSwdenk static int parse_line (char *, char *[]); 42*c609719bSwdenk #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 43*c609719bSwdenk static int abortboot(int); 44*c609719bSwdenk #endif 45*c609719bSwdenk 46*c609719bSwdenk #undef DEBUG_PARSER 47*c609719bSwdenk 48*c609719bSwdenk char console_buffer[CFG_CBSIZE]; /* console I/O buffer */ 49*c609719bSwdenk 50*c609719bSwdenk static char erase_seq[] = "\b \b"; /* erase sequence */ 51*c609719bSwdenk static char tab_seq[] = " "; /* used to expand TABs */ 52*c609719bSwdenk 53*c609719bSwdenk #ifdef CONFIG_BOOT_RETRY_TIME 54*c609719bSwdenk static uint64_t endtime = 0; /* must be set, default is instant timeout */ 55*c609719bSwdenk static int retry_time = -1; /* -1 so can call readline before main_loop */ 56*c609719bSwdenk #endif 57*c609719bSwdenk 58*c609719bSwdenk #define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk()) 59*c609719bSwdenk 60*c609719bSwdenk #ifndef CONFIG_BOOT_RETRY_MIN 61*c609719bSwdenk #define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME 62*c609719bSwdenk #endif 63*c609719bSwdenk 64*c609719bSwdenk #ifdef CONFIG_MODEM_SUPPORT 65*c609719bSwdenk int do_mdm_init = 0; 66*c609719bSwdenk extern void mdm_init(void); /* defined in board.c */ 67*c609719bSwdenk #endif 68*c609719bSwdenk 69*c609719bSwdenk /*************************************************************************** 70*c609719bSwdenk * Watch for 'delay' seconds for autoboot stop or autoboot delay string. 71*c609719bSwdenk * returns: 0 - no key string, allow autoboot 72*c609719bSwdenk * 1 - got key string, abort 73*c609719bSwdenk */ 74*c609719bSwdenk #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 75*c609719bSwdenk # if defined(CONFIG_AUTOBOOT_KEYED) 76*c609719bSwdenk static __inline__ int abortboot(int bootdelay) 77*c609719bSwdenk { 78*c609719bSwdenk int abort = 0; 79*c609719bSwdenk uint64_t etime = endtick(bootdelay); 80*c609719bSwdenk struct 81*c609719bSwdenk { 82*c609719bSwdenk char* str; 83*c609719bSwdenk u_int len; 84*c609719bSwdenk int retry; 85*c609719bSwdenk } 86*c609719bSwdenk delaykey [] = 87*c609719bSwdenk { 88*c609719bSwdenk { str: getenv ("bootdelaykey"), retry: 1 }, 89*c609719bSwdenk { str: getenv ("bootdelaykey2"), retry: 1 }, 90*c609719bSwdenk { str: getenv ("bootstopkey"), retry: 0 }, 91*c609719bSwdenk { str: getenv ("bootstopkey2"), retry: 0 }, 92*c609719bSwdenk }; 93*c609719bSwdenk 94*c609719bSwdenk char presskey [MAX_DELAY_STOP_STR]; 95*c609719bSwdenk u_int presskey_len = 0; 96*c609719bSwdenk u_int presskey_max = 0; 97*c609719bSwdenk u_int i; 98*c609719bSwdenk 99*c609719bSwdenk # ifdef CONFIG_AUTOBOOT_PROMPT 100*c609719bSwdenk printf (CONFIG_AUTOBOOT_PROMPT, bootdelay); 101*c609719bSwdenk # endif 102*c609719bSwdenk 103*c609719bSwdenk # ifdef CONFIG_AUTOBOOT_DELAY_STR 104*c609719bSwdenk if (delaykey[0].str == NULL) 105*c609719bSwdenk delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR; 106*c609719bSwdenk # endif 107*c609719bSwdenk # ifdef CONFIG_AUTOBOOT_DELAY_STR2 108*c609719bSwdenk if (delaykey[1].str == NULL) 109*c609719bSwdenk delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2; 110*c609719bSwdenk # endif 111*c609719bSwdenk # ifdef CONFIG_AUTOBOOT_STOP_STR 112*c609719bSwdenk if (delaykey[2].str == NULL) 113*c609719bSwdenk delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR; 114*c609719bSwdenk # endif 115*c609719bSwdenk # ifdef CONFIG_AUTOBOOT_STOP_STR2 116*c609719bSwdenk if (delaykey[3].str == NULL) 117*c609719bSwdenk delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2; 118*c609719bSwdenk # endif 119*c609719bSwdenk 120*c609719bSwdenk for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) { 121*c609719bSwdenk delaykey[i].len = delaykey[i].str == NULL ? 122*c609719bSwdenk 0 : strlen (delaykey[i].str); 123*c609719bSwdenk delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ? 124*c609719bSwdenk MAX_DELAY_STOP_STR : delaykey[i].len; 125*c609719bSwdenk 126*c609719bSwdenk presskey_max = presskey_max > delaykey[i].len ? 127*c609719bSwdenk presskey_max : delaykey[i].len; 128*c609719bSwdenk 129*c609719bSwdenk # if DEBUG_BOOTKEYS 130*c609719bSwdenk printf("%s key:<%s>\n", 131*c609719bSwdenk delaykey[i].retry ? "delay" : "stop", 132*c609719bSwdenk delaykey[i].str ? delaykey[i].str : "NULL"); 133*c609719bSwdenk # endif 134*c609719bSwdenk } 135*c609719bSwdenk 136*c609719bSwdenk /* In order to keep up with incoming data, check timeout only 137*c609719bSwdenk * when catch up. 138*c609719bSwdenk */ 139*c609719bSwdenk while (!abort && get_ticks() <= etime) { 140*c609719bSwdenk for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) { 141*c609719bSwdenk if (delaykey[i].len > 0 && 142*c609719bSwdenk presskey_len >= delaykey[i].len && 143*c609719bSwdenk memcmp (presskey + presskey_len - delaykey[i].len, 144*c609719bSwdenk delaykey[i].str, 145*c609719bSwdenk delaykey[i].len) == 0) { 146*c609719bSwdenk # if DEBUG_BOOTKEYS 147*c609719bSwdenk printf("got %skey\n", 148*c609719bSwdenk delaykey[i].retry ? "delay" : "stop"); 149*c609719bSwdenk # endif 150*c609719bSwdenk 151*c609719bSwdenk # ifdef CONFIG_BOOT_RETRY_TIME 152*c609719bSwdenk /* don't retry auto boot */ 153*c609719bSwdenk if (! delaykey[i].retry) 154*c609719bSwdenk retry_time = -1; 155*c609719bSwdenk # endif 156*c609719bSwdenk abort = 1; 157*c609719bSwdenk } 158*c609719bSwdenk } 159*c609719bSwdenk 160*c609719bSwdenk if (tstc()) { 161*c609719bSwdenk if (presskey_len < presskey_max) { 162*c609719bSwdenk presskey [presskey_len ++] = getc(); 163*c609719bSwdenk } 164*c609719bSwdenk else { 165*c609719bSwdenk for (i = 0; i < presskey_max - 1; i ++) 166*c609719bSwdenk presskey [i] = presskey [i + 1]; 167*c609719bSwdenk 168*c609719bSwdenk presskey [i] = getc(); 169*c609719bSwdenk } 170*c609719bSwdenk } 171*c609719bSwdenk } 172*c609719bSwdenk # if DEBUG_BOOTKEYS 173*c609719bSwdenk if (!abort) 174*c609719bSwdenk printf("key timeout\n"); 175*c609719bSwdenk # endif 176*c609719bSwdenk 177*c609719bSwdenk return abort; 178*c609719bSwdenk } 179*c609719bSwdenk 180*c609719bSwdenk # else /* !defined(CONFIG_AUTOBOOT_KEYED) */ 181*c609719bSwdenk 182*c609719bSwdenk static __inline__ int abortboot(int bootdelay) 183*c609719bSwdenk { 184*c609719bSwdenk int abort = 0; 185*c609719bSwdenk 186*c609719bSwdenk printf("Hit any key to stop autoboot: %2d ", bootdelay); 187*c609719bSwdenk 188*c609719bSwdenk #if defined CONFIG_ZERO_BOOTDELAY_CHECK 189*c609719bSwdenk /* 190*c609719bSwdenk * Check if key already pressed 191*c609719bSwdenk * Don't check if bootdelay < 0 192*c609719bSwdenk */ 193*c609719bSwdenk if (bootdelay >= 0) { 194*c609719bSwdenk if (tstc()) { /* we got a key press */ 195*c609719bSwdenk (void) getc(); /* consume input */ 196*c609719bSwdenk printf ("\b\b\b 0\n"); 197*c609719bSwdenk return 1; /* don't auto boot */ 198*c609719bSwdenk } 199*c609719bSwdenk } 200*c609719bSwdenk #endif 201*c609719bSwdenk 202*c609719bSwdenk while (bootdelay > 0) { 203*c609719bSwdenk int i; 204*c609719bSwdenk 205*c609719bSwdenk --bootdelay; 206*c609719bSwdenk /* delay 100 * 10ms */ 207*c609719bSwdenk for (i=0; !abort && i<100; ++i) { 208*c609719bSwdenk if (tstc()) { /* we got a key press */ 209*c609719bSwdenk abort = 1; /* don't auto boot */ 210*c609719bSwdenk bootdelay = 0; /* no more delay */ 211*c609719bSwdenk (void) getc(); /* consume input */ 212*c609719bSwdenk break; 213*c609719bSwdenk } 214*c609719bSwdenk udelay (10000); 215*c609719bSwdenk } 216*c609719bSwdenk 217*c609719bSwdenk printf ("\b\b\b%2d ", bootdelay); 218*c609719bSwdenk } 219*c609719bSwdenk 220*c609719bSwdenk putc ('\n'); 221*c609719bSwdenk 222*c609719bSwdenk return abort; 223*c609719bSwdenk } 224*c609719bSwdenk # endif /* CONFIG_AUTOBOOT_KEYED */ 225*c609719bSwdenk #endif /* CONFIG_BOOTDELAY >= 0 */ 226*c609719bSwdenk 227*c609719bSwdenk /****************************************************************************/ 228*c609719bSwdenk 229*c609719bSwdenk void main_loop (void) 230*c609719bSwdenk { 231*c609719bSwdenk #ifndef CFG_HUSH_PARSER 232*c609719bSwdenk static char lastcommand[CFG_CBSIZE] = { 0, }; 233*c609719bSwdenk int len; 234*c609719bSwdenk int rc = 1; 235*c609719bSwdenk int flag; 236*c609719bSwdenk #endif 237*c609719bSwdenk 238*c609719bSwdenk #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 239*c609719bSwdenk char *s; 240*c609719bSwdenk int bootdelay; 241*c609719bSwdenk #endif 242*c609719bSwdenk #ifdef CONFIG_PREBOOT 243*c609719bSwdenk char *p; 244*c609719bSwdenk #endif 245*c609719bSwdenk 246*c609719bSwdenk #if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO) 247*c609719bSwdenk ulong bmp = 0; /* default bitmap */ 248*c609719bSwdenk extern int trab_vfd (ulong bitmap); 249*c609719bSwdenk 250*c609719bSwdenk #ifdef CONFIG_MODEM_SUPPORT 251*c609719bSwdenk if (do_mdm_init) 252*c609719bSwdenk bmp = 1; /* alternate bitmap */ 253*c609719bSwdenk #endif 254*c609719bSwdenk trab_vfd (bmp); 255*c609719bSwdenk #endif /* CONFIG_VFD && VFD_TEST_LOGO */ 256*c609719bSwdenk 257*c609719bSwdenk #ifdef CONFIG_MODEM_SUPPORT 258*c609719bSwdenk debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init); 259*c609719bSwdenk if (do_mdm_init) { 260*c609719bSwdenk uchar *str = strdup(getenv("mdm_cmd")); 261*c609719bSwdenk setenv ("preboot", str); /* set or delete definition */ 262*c609719bSwdenk if (str != NULL) 263*c609719bSwdenk free (str); 264*c609719bSwdenk mdm_init(); /* wait for modem connection */ 265*c609719bSwdenk } 266*c609719bSwdenk #endif /* CONFIG_MODEM_SUPPORT */ 267*c609719bSwdenk 268*c609719bSwdenk #ifdef CFG_HUSH_PARSER 269*c609719bSwdenk u_boot_hush_start (); 270*c609719bSwdenk #endif 271*c609719bSwdenk 272*c609719bSwdenk #ifdef CONFIG_PREBOOT 273*c609719bSwdenk if ((p = getenv ("preboot")) != NULL) { 274*c609719bSwdenk # ifdef CONFIG_AUTOBOOT_KEYED 275*c609719bSwdenk int prev = disable_ctrlc(1); /* disable Control C checking */ 276*c609719bSwdenk # endif 277*c609719bSwdenk 278*c609719bSwdenk # ifndef CFG_HUSH_PARSER 279*c609719bSwdenk run_command (p, 0); 280*c609719bSwdenk # else 281*c609719bSwdenk parse_string_outer(p, FLAG_PARSE_SEMICOLON | 282*c609719bSwdenk FLAG_EXIT_FROM_LOOP); 283*c609719bSwdenk # endif 284*c609719bSwdenk 285*c609719bSwdenk # ifdef CONFIG_AUTOBOOT_KEYED 286*c609719bSwdenk disable_ctrlc(prev); /* restore Control C checking */ 287*c609719bSwdenk # endif 288*c609719bSwdenk } 289*c609719bSwdenk #endif /* CONFIG_PREBOOT */ 290*c609719bSwdenk 291*c609719bSwdenk #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 292*c609719bSwdenk s = getenv ("bootdelay"); 293*c609719bSwdenk bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; 294*c609719bSwdenk 295*c609719bSwdenk #if 0 296*c609719bSwdenk printf ("### main_loop entered:\n\n"); 297*c609719bSwdenk #endif 298*c609719bSwdenk 299*c609719bSwdenk # ifdef CONFIG_BOOT_RETRY_TIME 300*c609719bSwdenk s = getenv ("bootretry"); 301*c609719bSwdenk if (s != NULL) 302*c609719bSwdenk retry_time = (int)simple_strtoul(s, NULL, 10); 303*c609719bSwdenk else 304*c609719bSwdenk retry_time = CONFIG_BOOT_RETRY_TIME; 305*c609719bSwdenk if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN) 306*c609719bSwdenk retry_time = CONFIG_BOOT_RETRY_MIN; 307*c609719bSwdenk # endif /* CONFIG_BOOT_RETRY_TIME */ 308*c609719bSwdenk 309*c609719bSwdenk s = getenv ("bootcmd"); 310*c609719bSwdenk if (bootdelay >= 0 && s && !abortboot (bootdelay)) { 311*c609719bSwdenk # ifdef CONFIG_AUTOBOOT_KEYED 312*c609719bSwdenk int prev = disable_ctrlc(1); /* disable Control C checking */ 313*c609719bSwdenk # endif 314*c609719bSwdenk 315*c609719bSwdenk # ifndef CFG_HUSH_PARSER 316*c609719bSwdenk run_command (s, 0); 317*c609719bSwdenk # else 318*c609719bSwdenk parse_string_outer(s, FLAG_PARSE_SEMICOLON | 319*c609719bSwdenk FLAG_EXIT_FROM_LOOP); 320*c609719bSwdenk # endif 321*c609719bSwdenk 322*c609719bSwdenk # ifdef CONFIG_AUTOBOOT_KEYED 323*c609719bSwdenk disable_ctrlc(prev); /* restore Control C checking */ 324*c609719bSwdenk # endif 325*c609719bSwdenk } 326*c609719bSwdenk #endif /* CONFIG_BOOTDELAY */ 327*c609719bSwdenk 328*c609719bSwdenk /* 329*c609719bSwdenk * Main Loop for Monitor Command Processing 330*c609719bSwdenk */ 331*c609719bSwdenk #ifdef CFG_HUSH_PARSER 332*c609719bSwdenk parse_file_outer(); 333*c609719bSwdenk /* This point is never reached */ 334*c609719bSwdenk for (;;); 335*c609719bSwdenk #else 336*c609719bSwdenk for (;;) { 337*c609719bSwdenk #ifdef CONFIG_BOOT_RETRY_TIME 338*c609719bSwdenk if (rc >= 0) { 339*c609719bSwdenk /* Saw enough of a valid command to 340*c609719bSwdenk * restart the timeout. 341*c609719bSwdenk */ 342*c609719bSwdenk reset_cmd_timeout(); 343*c609719bSwdenk } 344*c609719bSwdenk #endif 345*c609719bSwdenk len = readline (CFG_PROMPT); 346*c609719bSwdenk 347*c609719bSwdenk flag = 0; /* assume no special flags for now */ 348*c609719bSwdenk if (len > 0) 349*c609719bSwdenk strcpy (lastcommand, console_buffer); 350*c609719bSwdenk else if (len == 0) 351*c609719bSwdenk flag |= CMD_FLAG_REPEAT; 352*c609719bSwdenk #ifdef CONFIG_BOOT_RETRY_TIME 353*c609719bSwdenk else if (len == -2) { 354*c609719bSwdenk /* -2 means timed out, retry autoboot 355*c609719bSwdenk */ 356*c609719bSwdenk printf("\nTimed out waiting for command\n"); 357*c609719bSwdenk # ifdef CONFIG_RESET_TO_RETRY 358*c609719bSwdenk /* Reinit board to run initialization code again */ 359*c609719bSwdenk do_reset (NULL, 0, 0, NULL); 360*c609719bSwdenk # else 361*c609719bSwdenk return; /* retry autoboot */ 362*c609719bSwdenk # endif 363*c609719bSwdenk } 364*c609719bSwdenk #endif 365*c609719bSwdenk 366*c609719bSwdenk if (len == -1) 367*c609719bSwdenk printf ("<INTERRUPT>\n"); 368*c609719bSwdenk else 369*c609719bSwdenk rc = run_command (lastcommand, flag); 370*c609719bSwdenk 371*c609719bSwdenk if (rc <= 0) { 372*c609719bSwdenk /* invalid command or not repeatable, forget it */ 373*c609719bSwdenk lastcommand[0] = 0; 374*c609719bSwdenk } 375*c609719bSwdenk } 376*c609719bSwdenk #endif /*CFG_HUSH_PARSER*/ 377*c609719bSwdenk } 378*c609719bSwdenk 379*c609719bSwdenk /*************************************************************************** 380*c609719bSwdenk * reset command line timeout to retry_time seconds 381*c609719bSwdenk */ 382*c609719bSwdenk #ifdef CONFIG_BOOT_RETRY_TIME 383*c609719bSwdenk void reset_cmd_timeout(void) 384*c609719bSwdenk { 385*c609719bSwdenk endtime = endtick(retry_time); 386*c609719bSwdenk } 387*c609719bSwdenk #endif 388*c609719bSwdenk 389*c609719bSwdenk /****************************************************************************/ 390*c609719bSwdenk 391*c609719bSwdenk /* 392*c609719bSwdenk * Prompt for input and read a line. 393*c609719bSwdenk * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0, 394*c609719bSwdenk * time out when time goes past endtime (timebase time in ticks). 395*c609719bSwdenk * Return: number of read characters 396*c609719bSwdenk * -1 if break 397*c609719bSwdenk * -2 if timed out 398*c609719bSwdenk */ 399*c609719bSwdenk int readline (const char *const prompt) 400*c609719bSwdenk { 401*c609719bSwdenk char *p = console_buffer; 402*c609719bSwdenk int n = 0; /* buffer index */ 403*c609719bSwdenk int plen = 0; /* prompt length */ 404*c609719bSwdenk int col; /* output column cnt */ 405*c609719bSwdenk char c; 406*c609719bSwdenk 407*c609719bSwdenk /* print prompt */ 408*c609719bSwdenk if (prompt) { 409*c609719bSwdenk plen = strlen (prompt); 410*c609719bSwdenk puts (prompt); 411*c609719bSwdenk } 412*c609719bSwdenk col = plen; 413*c609719bSwdenk 414*c609719bSwdenk for (;;) { 415*c609719bSwdenk #ifdef CONFIG_BOOT_RETRY_TIME 416*c609719bSwdenk while (!tstc()) { /* while no incoming data */ 417*c609719bSwdenk if (retry_time >= 0 && get_ticks() > endtime) 418*c609719bSwdenk return (-2); /* timed out */ 419*c609719bSwdenk } 420*c609719bSwdenk #endif 421*c609719bSwdenk WATCHDOG_RESET(); /* Trigger watchdog, if needed */ 422*c609719bSwdenk 423*c609719bSwdenk #ifdef CONFIG_SHOW_ACTIVITY 424*c609719bSwdenk while (!tstc()) { 425*c609719bSwdenk extern void show_activity(int arg); 426*c609719bSwdenk show_activity(0); 427*c609719bSwdenk } 428*c609719bSwdenk #endif 429*c609719bSwdenk c = getc(); 430*c609719bSwdenk 431*c609719bSwdenk /* 432*c609719bSwdenk * Special character handling 433*c609719bSwdenk */ 434*c609719bSwdenk switch (c) { 435*c609719bSwdenk case '\r': /* Enter */ 436*c609719bSwdenk case '\n': 437*c609719bSwdenk *p = '\0'; 438*c609719bSwdenk puts ("\r\n"); 439*c609719bSwdenk return (p - console_buffer); 440*c609719bSwdenk 441*c609719bSwdenk case 0x03: /* ^C - break */ 442*c609719bSwdenk console_buffer[0] = '\0'; /* discard input */ 443*c609719bSwdenk return (-1); 444*c609719bSwdenk 445*c609719bSwdenk case 0x15: /* ^U - erase line */ 446*c609719bSwdenk while (col > plen) { 447*c609719bSwdenk puts (erase_seq); 448*c609719bSwdenk --col; 449*c609719bSwdenk } 450*c609719bSwdenk p = console_buffer; 451*c609719bSwdenk n = 0; 452*c609719bSwdenk continue; 453*c609719bSwdenk 454*c609719bSwdenk case 0x17: /* ^W - erase word */ 455*c609719bSwdenk p=delete_char(console_buffer, p, &col, &n, plen); 456*c609719bSwdenk while ((n > 0) && (*p != ' ')) { 457*c609719bSwdenk p=delete_char(console_buffer, p, &col, &n, plen); 458*c609719bSwdenk } 459*c609719bSwdenk continue; 460*c609719bSwdenk 461*c609719bSwdenk case 0x08: /* ^H - backspace */ 462*c609719bSwdenk case 0x7F: /* DEL - backspace */ 463*c609719bSwdenk p=delete_char(console_buffer, p, &col, &n, plen); 464*c609719bSwdenk continue; 465*c609719bSwdenk 466*c609719bSwdenk default: 467*c609719bSwdenk /* 468*c609719bSwdenk * Must be a normal character then 469*c609719bSwdenk */ 470*c609719bSwdenk if (n < CFG_CBSIZE-2) { 471*c609719bSwdenk if (c == '\t') { /* expand TABs */ 472*c609719bSwdenk puts (tab_seq+(col&07)); 473*c609719bSwdenk col += 8 - (col&07); 474*c609719bSwdenk } else { 475*c609719bSwdenk ++col; /* echo input */ 476*c609719bSwdenk putc (c); 477*c609719bSwdenk } 478*c609719bSwdenk *p++ = c; 479*c609719bSwdenk ++n; 480*c609719bSwdenk } else { /* Buffer full */ 481*c609719bSwdenk putc ('\a'); 482*c609719bSwdenk } 483*c609719bSwdenk } 484*c609719bSwdenk } 485*c609719bSwdenk } 486*c609719bSwdenk 487*c609719bSwdenk /****************************************************************************/ 488*c609719bSwdenk 489*c609719bSwdenk static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen) 490*c609719bSwdenk { 491*c609719bSwdenk char *s; 492*c609719bSwdenk 493*c609719bSwdenk if (*np == 0) { 494*c609719bSwdenk return (p); 495*c609719bSwdenk } 496*c609719bSwdenk 497*c609719bSwdenk if (*(--p) == '\t') { /* will retype the whole line */ 498*c609719bSwdenk while (*colp > plen) { 499*c609719bSwdenk puts (erase_seq); 500*c609719bSwdenk (*colp)--; 501*c609719bSwdenk } 502*c609719bSwdenk for (s=buffer; s<p; ++s) { 503*c609719bSwdenk if (*s == '\t') { 504*c609719bSwdenk puts (tab_seq+((*colp) & 07)); 505*c609719bSwdenk *colp += 8 - ((*colp) & 07); 506*c609719bSwdenk } else { 507*c609719bSwdenk ++(*colp); 508*c609719bSwdenk putc (*s); 509*c609719bSwdenk } 510*c609719bSwdenk } 511*c609719bSwdenk } else { 512*c609719bSwdenk puts (erase_seq); 513*c609719bSwdenk (*colp)--; 514*c609719bSwdenk } 515*c609719bSwdenk (*np)--; 516*c609719bSwdenk return (p); 517*c609719bSwdenk } 518*c609719bSwdenk 519*c609719bSwdenk /****************************************************************************/ 520*c609719bSwdenk 521*c609719bSwdenk int parse_line (char *line, char *argv[]) 522*c609719bSwdenk { 523*c609719bSwdenk int nargs = 0; 524*c609719bSwdenk 525*c609719bSwdenk #ifdef DEBUG_PARSER 526*c609719bSwdenk printf ("parse_line: \"%s\"\n", line); 527*c609719bSwdenk #endif 528*c609719bSwdenk while (nargs < CFG_MAXARGS) { 529*c609719bSwdenk 530*c609719bSwdenk /* skip any white space */ 531*c609719bSwdenk while ((*line == ' ') || (*line == '\t')) { 532*c609719bSwdenk ++line; 533*c609719bSwdenk } 534*c609719bSwdenk 535*c609719bSwdenk if (*line == '\0') { /* end of line, no more args */ 536*c609719bSwdenk argv[nargs] = NULL; 537*c609719bSwdenk #ifdef DEBUG_PARSER 538*c609719bSwdenk printf ("parse_line: nargs=%d\n", nargs); 539*c609719bSwdenk #endif 540*c609719bSwdenk return (nargs); 541*c609719bSwdenk } 542*c609719bSwdenk 543*c609719bSwdenk argv[nargs++] = line; /* begin of argument string */ 544*c609719bSwdenk 545*c609719bSwdenk /* find end of string */ 546*c609719bSwdenk while (*line && (*line != ' ') && (*line != '\t')) { 547*c609719bSwdenk ++line; 548*c609719bSwdenk } 549*c609719bSwdenk 550*c609719bSwdenk if (*line == '\0') { /* end of line, no more args */ 551*c609719bSwdenk argv[nargs] = NULL; 552*c609719bSwdenk #ifdef DEBUG_PARSER 553*c609719bSwdenk printf ("parse_line: nargs=%d\n", nargs); 554*c609719bSwdenk #endif 555*c609719bSwdenk return (nargs); 556*c609719bSwdenk } 557*c609719bSwdenk 558*c609719bSwdenk *line++ = '\0'; /* terminate current arg */ 559*c609719bSwdenk } 560*c609719bSwdenk 561*c609719bSwdenk printf ("** Too many args (max. %d) **\n", CFG_MAXARGS); 562*c609719bSwdenk 563*c609719bSwdenk #ifdef DEBUG_PARSER 564*c609719bSwdenk printf ("parse_line: nargs=%d\n", nargs); 565*c609719bSwdenk #endif 566*c609719bSwdenk return (nargs); 567*c609719bSwdenk } 568*c609719bSwdenk 569*c609719bSwdenk /****************************************************************************/ 570*c609719bSwdenk 571*c609719bSwdenk static void process_macros (const char *input, char *output) 572*c609719bSwdenk { 573*c609719bSwdenk char c, prev; 574*c609719bSwdenk const char *varname_start = NULL; 575*c609719bSwdenk int inputcnt = strlen (input); 576*c609719bSwdenk int outputcnt = CFG_CBSIZE; 577*c609719bSwdenk int state = 0; /* 0 = waiting for '$' */ 578*c609719bSwdenk /* 1 = waiting for '(' */ 579*c609719bSwdenk /* 2 = waiting for ')' */ 580*c609719bSwdenk 581*c609719bSwdenk #ifdef DEBUG_PARSER 582*c609719bSwdenk char *output_start = output; 583*c609719bSwdenk 584*c609719bSwdenk printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input), input); 585*c609719bSwdenk #endif 586*c609719bSwdenk 587*c609719bSwdenk prev = '\0'; /* previous character */ 588*c609719bSwdenk 589*c609719bSwdenk while (inputcnt && outputcnt) { 590*c609719bSwdenk c = *input++; 591*c609719bSwdenk inputcnt--; 592*c609719bSwdenk 593*c609719bSwdenk /* remove one level of escape characters */ 594*c609719bSwdenk if ((c == '\\') && (prev != '\\')) { 595*c609719bSwdenk if (inputcnt-- == 0) 596*c609719bSwdenk break; 597*c609719bSwdenk prev = c; 598*c609719bSwdenk c = *input++; 599*c609719bSwdenk } 600*c609719bSwdenk 601*c609719bSwdenk switch (state) { 602*c609719bSwdenk case 0: /* Waiting for (unescaped) $ */ 603*c609719bSwdenk if ((c == '$') && (prev != '\\')) { 604*c609719bSwdenk state++; 605*c609719bSwdenk } else { 606*c609719bSwdenk *(output++) = c; 607*c609719bSwdenk outputcnt--; 608*c609719bSwdenk } 609*c609719bSwdenk break; 610*c609719bSwdenk case 1: /* Waiting for ( */ 611*c609719bSwdenk if (c == '(') { 612*c609719bSwdenk state++; 613*c609719bSwdenk varname_start = input; 614*c609719bSwdenk } else { 615*c609719bSwdenk state = 0; 616*c609719bSwdenk *(output++) = '$'; 617*c609719bSwdenk outputcnt--; 618*c609719bSwdenk 619*c609719bSwdenk if (outputcnt) { 620*c609719bSwdenk *(output++) = c; 621*c609719bSwdenk outputcnt--; 622*c609719bSwdenk } 623*c609719bSwdenk } 624*c609719bSwdenk break; 625*c609719bSwdenk case 2: /* Waiting for ) */ 626*c609719bSwdenk if (c == ')') { 627*c609719bSwdenk int i; 628*c609719bSwdenk char envname[CFG_CBSIZE], *envval; 629*c609719bSwdenk int envcnt = input-varname_start-1; /* Varname # of chars */ 630*c609719bSwdenk 631*c609719bSwdenk /* Get the varname */ 632*c609719bSwdenk for (i = 0; i < envcnt; i++) { 633*c609719bSwdenk envname[i] = varname_start[i]; 634*c609719bSwdenk } 635*c609719bSwdenk envname[i] = 0; 636*c609719bSwdenk 637*c609719bSwdenk /* Get its value */ 638*c609719bSwdenk envval = getenv (envname); 639*c609719bSwdenk 640*c609719bSwdenk /* Copy into the line if it exists */ 641*c609719bSwdenk if (envval != NULL) 642*c609719bSwdenk while ((*envval) && outputcnt) { 643*c609719bSwdenk *(output++) = *(envval++); 644*c609719bSwdenk outputcnt--; 645*c609719bSwdenk } 646*c609719bSwdenk /* Look for another '$' */ 647*c609719bSwdenk state = 0; 648*c609719bSwdenk } 649*c609719bSwdenk break; 650*c609719bSwdenk } 651*c609719bSwdenk 652*c609719bSwdenk prev = c; 653*c609719bSwdenk } 654*c609719bSwdenk 655*c609719bSwdenk if (outputcnt) 656*c609719bSwdenk *output = 0; 657*c609719bSwdenk 658*c609719bSwdenk #ifdef DEBUG_PARSER 659*c609719bSwdenk printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n", 660*c609719bSwdenk strlen(output_start), output_start); 661*c609719bSwdenk #endif 662*c609719bSwdenk } 663*c609719bSwdenk 664*c609719bSwdenk /**************************************************************************** 665*c609719bSwdenk * returns: 666*c609719bSwdenk * 1 - command executed, repeatable 667*c609719bSwdenk * 0 - command executed but not repeatable, interrupted commands are 668*c609719bSwdenk * always considered not repeatable 669*c609719bSwdenk * -1 - not executed (unrecognized, bootd recursion or too many args) 670*c609719bSwdenk * (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is 671*c609719bSwdenk * considered unrecognized) 672*c609719bSwdenk * 673*c609719bSwdenk * WARNING: 674*c609719bSwdenk * 675*c609719bSwdenk * We must create a temporary copy of the command since the command we get 676*c609719bSwdenk * may be the result from getenv(), which returns a pointer directly to 677*c609719bSwdenk * the environment data, which may change magicly when the command we run 678*c609719bSwdenk * creates or modifies environment variables (like "bootp" does). 679*c609719bSwdenk */ 680*c609719bSwdenk 681*c609719bSwdenk int run_command (const char *cmd, int flag) 682*c609719bSwdenk { 683*c609719bSwdenk cmd_tbl_t *cmdtp; 684*c609719bSwdenk char cmdbuf[CFG_CBSIZE]; /* working copy of cmd */ 685*c609719bSwdenk char *token; /* start of token in cmdbuf */ 686*c609719bSwdenk char *sep; /* end of token (separator) in cmdbuf */ 687*c609719bSwdenk char finaltoken[CFG_CBSIZE]; 688*c609719bSwdenk char *str = cmdbuf; 689*c609719bSwdenk char *argv[CFG_MAXARGS + 1]; /* NULL terminated */ 690*c609719bSwdenk int argc; 691*c609719bSwdenk int repeatable = 1; 692*c609719bSwdenk 693*c609719bSwdenk #ifdef DEBUG_PARSER 694*c609719bSwdenk printf ("[RUN_COMMAND] cmd[%p]=\"", cmd); 695*c609719bSwdenk puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */ 696*c609719bSwdenk puts ("\"\n"); 697*c609719bSwdenk #endif 698*c609719bSwdenk 699*c609719bSwdenk clear_ctrlc(); /* forget any previous Control C */ 700*c609719bSwdenk 701*c609719bSwdenk if (!cmd || !*cmd) { 702*c609719bSwdenk return -1; /* empty command */ 703*c609719bSwdenk } 704*c609719bSwdenk 705*c609719bSwdenk if (strlen(cmd) >= CFG_CBSIZE) { 706*c609719bSwdenk puts ("## Command too long!\n"); 707*c609719bSwdenk return -1; 708*c609719bSwdenk } 709*c609719bSwdenk 710*c609719bSwdenk strcpy (cmdbuf, cmd); 711*c609719bSwdenk 712*c609719bSwdenk /* Process separators and check for invalid 713*c609719bSwdenk * repeatable commands 714*c609719bSwdenk */ 715*c609719bSwdenk 716*c609719bSwdenk #ifdef DEBUG_PARSER 717*c609719bSwdenk printf ("[PROCESS_SEPARATORS] %s\n", cmd); 718*c609719bSwdenk #endif 719*c609719bSwdenk while (*str) { 720*c609719bSwdenk 721*c609719bSwdenk /* 722*c609719bSwdenk * Find separator, or string end 723*c609719bSwdenk * Allow simple escape of ';' by writing "\;" 724*c609719bSwdenk */ 725*c609719bSwdenk for (sep = str; *sep; sep++) { 726*c609719bSwdenk if ((*sep == ';') && /* separator */ 727*c609719bSwdenk ( sep != str) && /* past string start */ 728*c609719bSwdenk (*(sep-1) != '\\')) /* and NOT escaped */ 729*c609719bSwdenk break; 730*c609719bSwdenk } 731*c609719bSwdenk 732*c609719bSwdenk /* 733*c609719bSwdenk * Limit the token to data between separators 734*c609719bSwdenk */ 735*c609719bSwdenk token = str; 736*c609719bSwdenk if (*sep) { 737*c609719bSwdenk str = sep + 1; /* start of command for next pass */ 738*c609719bSwdenk *sep = '\0'; 739*c609719bSwdenk } 740*c609719bSwdenk else 741*c609719bSwdenk str = sep; /* no more commands for next pass */ 742*c609719bSwdenk #ifdef DEBUG_PARSER 743*c609719bSwdenk printf ("token: \"%s\"\n", token); 744*c609719bSwdenk #endif 745*c609719bSwdenk 746*c609719bSwdenk /* find macros in this token and replace them */ 747*c609719bSwdenk process_macros (token, finaltoken); 748*c609719bSwdenk 749*c609719bSwdenk /* Extract arguments */ 750*c609719bSwdenk argc = parse_line (finaltoken, argv); 751*c609719bSwdenk 752*c609719bSwdenk /* Look up command in command table */ 753*c609719bSwdenk if ((cmdtp = find_cmd(argv[0])) == NULL) { 754*c609719bSwdenk printf ("Unknown command '%s' - try 'help'\n", argv[0]); 755*c609719bSwdenk return -1; /* give up after bad command */ 756*c609719bSwdenk } 757*c609719bSwdenk 758*c609719bSwdenk /* found - check max args */ 759*c609719bSwdenk if (argc > cmdtp->maxargs) { 760*c609719bSwdenk printf ("Usage:\n%s\n", cmdtp->usage); 761*c609719bSwdenk return -1; 762*c609719bSwdenk } 763*c609719bSwdenk 764*c609719bSwdenk #if (CONFIG_COMMANDS & CFG_CMD_BOOTD) 765*c609719bSwdenk /* avoid "bootd" recursion */ 766*c609719bSwdenk if (cmdtp->cmd == do_bootd) { 767*c609719bSwdenk #ifdef DEBUG_PARSER 768*c609719bSwdenk printf ("[%s]\n", finaltoken); 769*c609719bSwdenk #endif 770*c609719bSwdenk if (flag & CMD_FLAG_BOOTD) { 771*c609719bSwdenk printf ("'bootd' recursion detected\n"); 772*c609719bSwdenk return -1; 773*c609719bSwdenk } 774*c609719bSwdenk else 775*c609719bSwdenk flag |= CMD_FLAG_BOOTD; 776*c609719bSwdenk } 777*c609719bSwdenk #endif /* CFG_CMD_BOOTD */ 778*c609719bSwdenk 779*c609719bSwdenk /* OK - call function to do the command */ 780*c609719bSwdenk if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) { 781*c609719bSwdenk return (-1); 782*c609719bSwdenk } 783*c609719bSwdenk 784*c609719bSwdenk repeatable &= cmdtp->repeatable; 785*c609719bSwdenk 786*c609719bSwdenk /* Did the user stop this? */ 787*c609719bSwdenk if (had_ctrlc ()) 788*c609719bSwdenk return 0; /* if stopped then not repeatable */ 789*c609719bSwdenk } 790*c609719bSwdenk 791*c609719bSwdenk return repeatable; 792*c609719bSwdenk } 793*c609719bSwdenk 794*c609719bSwdenk /****************************************************************************/ 795*c609719bSwdenk 796*c609719bSwdenk #if (CONFIG_COMMANDS & CFG_CMD_RUN) 797*c609719bSwdenk int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) 798*c609719bSwdenk { 799*c609719bSwdenk int i; 800*c609719bSwdenk int rcode = 1; 801*c609719bSwdenk 802*c609719bSwdenk if (argc < 2) { 803*c609719bSwdenk printf ("Usage:\n%s\n", cmdtp->usage); 804*c609719bSwdenk return 1; 805*c609719bSwdenk } 806*c609719bSwdenk 807*c609719bSwdenk for (i=1; i<argc; ++i) { 808*c609719bSwdenk #ifndef CFG_HUSH_PARSER 809*c609719bSwdenk if (run_command (getenv (argv[i]), flag) != -1) ++rcode; 810*c609719bSwdenk #else 811*c609719bSwdenk if (parse_string_outer(getenv (argv[i]), 812*c609719bSwdenk FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) == 0) ++rcode; 813*c609719bSwdenk #endif 814*c609719bSwdenk } 815*c609719bSwdenk return ((rcode == i) ? 0 : 1); 816*c609719bSwdenk } 817*c609719bSwdenk #endif 818