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 #include <fdtdec.h> 34 #include <malloc.h> 35 #include <version.h> 36 #ifdef CONFIG_MODEM_SUPPORT 37 #include <malloc.h> /* for free() prototype */ 38 #endif 39 40 #ifdef CONFIG_SYS_HUSH_PARSER 41 #include <hush.h> 42 #endif 43 44 #ifdef CONFIG_OF_CONTROL 45 #include <fdtdec.h> 46 #endif 47 48 #include <post.h> 49 #include <linux/ctype.h> 50 #include <menu.h> 51 52 DECLARE_GLOBAL_DATA_PTR; 53 54 /* 55 * Board-specific Platform code can reimplement show_boot_progress () if needed 56 */ 57 void inline __show_boot_progress (int val) {} 58 void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress"))); 59 60 #define MAX_DELAY_STOP_STR 32 61 62 #undef DEBUG_PARSER 63 64 char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */ 65 66 static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen); 67 static const char erase_seq[] = "\b \b"; /* erase sequence */ 68 static const char tab_seq[] = " "; /* used to expand TABs */ 69 70 #ifdef CONFIG_BOOT_RETRY_TIME 71 static uint64_t endtime = 0; /* must be set, default is instant timeout */ 72 static int retry_time = -1; /* -1 so can call readline before main_loop */ 73 #endif 74 75 #define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk()) 76 77 #ifndef CONFIG_BOOT_RETRY_MIN 78 #define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME 79 #endif 80 81 #ifdef CONFIG_MODEM_SUPPORT 82 int do_mdm_init = 0; 83 extern void mdm_init(void); /* defined in board.c */ 84 #endif 85 86 /*************************************************************************** 87 * Watch for 'delay' seconds for autoboot stop or autoboot delay string. 88 * returns: 0 - no key string, allow autoboot 1 - got key string, abort 89 */ 90 #if defined(CONFIG_BOOTDELAY) 91 # if defined(CONFIG_AUTOBOOT_KEYED) 92 static int abortboot_keyed(int bootdelay) 93 { 94 int abort = 0; 95 uint64_t etime = endtick(bootdelay); 96 struct { 97 char* str; 98 u_int len; 99 int retry; 100 } 101 delaykey [] = { 102 { str: getenv ("bootdelaykey"), retry: 1 }, 103 { str: getenv ("bootdelaykey2"), retry: 1 }, 104 { str: getenv ("bootstopkey"), retry: 0 }, 105 { str: getenv ("bootstopkey2"), retry: 0 }, 106 }; 107 108 char presskey [MAX_DELAY_STOP_STR]; 109 u_int presskey_len = 0; 110 u_int presskey_max = 0; 111 u_int i; 112 113 #ifndef CONFIG_ZERO_BOOTDELAY_CHECK 114 if (bootdelay == 0) 115 return 0; 116 #endif 117 118 # ifdef CONFIG_AUTOBOOT_PROMPT 119 printf(CONFIG_AUTOBOOT_PROMPT); 120 # endif 121 122 # ifdef CONFIG_AUTOBOOT_DELAY_STR 123 if (delaykey[0].str == NULL) 124 delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR; 125 # endif 126 # ifdef CONFIG_AUTOBOOT_DELAY_STR2 127 if (delaykey[1].str == NULL) 128 delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2; 129 # endif 130 # ifdef CONFIG_AUTOBOOT_STOP_STR 131 if (delaykey[2].str == NULL) 132 delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR; 133 # endif 134 # ifdef CONFIG_AUTOBOOT_STOP_STR2 135 if (delaykey[3].str == NULL) 136 delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2; 137 # endif 138 139 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) { 140 delaykey[i].len = delaykey[i].str == NULL ? 141 0 : strlen (delaykey[i].str); 142 delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ? 143 MAX_DELAY_STOP_STR : delaykey[i].len; 144 145 presskey_max = presskey_max > delaykey[i].len ? 146 presskey_max : delaykey[i].len; 147 148 # if DEBUG_BOOTKEYS 149 printf("%s key:<%s>\n", 150 delaykey[i].retry ? "delay" : "stop", 151 delaykey[i].str ? delaykey[i].str : "NULL"); 152 # endif 153 } 154 155 /* In order to keep up with incoming data, check timeout only 156 * when catch up. 157 */ 158 do { 159 if (tstc()) { 160 if (presskey_len < presskey_max) { 161 presskey [presskey_len ++] = getc(); 162 } 163 else { 164 for (i = 0; i < presskey_max - 1; i ++) 165 presskey [i] = presskey [i + 1]; 166 167 presskey [i] = getc(); 168 } 169 } 170 171 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) { 172 if (delaykey[i].len > 0 && 173 presskey_len >= delaykey[i].len && 174 memcmp (presskey + presskey_len - delaykey[i].len, 175 delaykey[i].str, 176 delaykey[i].len) == 0) { 177 # if DEBUG_BOOTKEYS 178 printf("got %skey\n", 179 delaykey[i].retry ? "delay" : "stop"); 180 # endif 181 182 # ifdef CONFIG_BOOT_RETRY_TIME 183 /* don't retry auto boot */ 184 if (! delaykey[i].retry) 185 retry_time = -1; 186 # endif 187 abort = 1; 188 } 189 } 190 } while (!abort && get_ticks() <= etime); 191 192 # if DEBUG_BOOTKEYS 193 if (!abort) 194 puts("key timeout\n"); 195 # endif 196 197 #ifdef CONFIG_SILENT_CONSOLE 198 if (abort) 199 gd->flags &= ~GD_FLG_SILENT; 200 #endif 201 202 return abort; 203 } 204 205 # else /* !defined(CONFIG_AUTOBOOT_KEYED) */ 206 207 #ifdef CONFIG_MENUKEY 208 static int menukey = 0; 209 #endif 210 211 static int abortboot_normal(int bootdelay) 212 { 213 int abort = 0; 214 unsigned long ts; 215 216 #ifdef CONFIG_MENUPROMPT 217 printf(CONFIG_MENUPROMPT); 218 #else 219 if (bootdelay >= 0) 220 printf("Hit any key to stop autoboot: %2d ", bootdelay); 221 #endif 222 223 #if defined CONFIG_ZERO_BOOTDELAY_CHECK 224 /* 225 * Check if key already pressed 226 * Don't check if bootdelay < 0 227 */ 228 if (bootdelay >= 0) { 229 if (tstc()) { /* we got a key press */ 230 (void) getc(); /* consume input */ 231 puts ("\b\b\b 0"); 232 abort = 1; /* don't auto boot */ 233 } 234 } 235 #endif 236 237 while ((bootdelay > 0) && (!abort)) { 238 --bootdelay; 239 /* delay 1000 ms */ 240 ts = get_timer(0); 241 do { 242 if (tstc()) { /* we got a key press */ 243 abort = 1; /* don't auto boot */ 244 bootdelay = 0; /* no more delay */ 245 # ifdef CONFIG_MENUKEY 246 menukey = getc(); 247 # else 248 (void) getc(); /* consume input */ 249 # endif 250 break; 251 } 252 udelay(10000); 253 } while (!abort && get_timer(ts) < 1000); 254 255 printf("\b\b\b%2d ", bootdelay); 256 } 257 258 putc('\n'); 259 260 #ifdef CONFIG_SILENT_CONSOLE 261 if (abort) 262 gd->flags &= ~GD_FLG_SILENT; 263 #endif 264 265 return abort; 266 } 267 # endif /* CONFIG_AUTOBOOT_KEYED */ 268 269 static int abortboot(int bootdelay) 270 { 271 #ifdef CONFIG_AUTOBOOT_KEYED 272 return abortboot_keyed(bootdelay); 273 #else 274 return abortboot_normal(bootdelay); 275 #endif 276 } 277 #endif /* CONFIG_BOOTDELAY */ 278 279 /* 280 * Runs the given boot command securely. Specifically: 281 * - Doesn't run the command with the shell (run_command or parse_string_outer), 282 * since that's a lot of code surface that an attacker might exploit. 283 * Because of this, we don't do any argument parsing--the secure boot command 284 * has to be a full-fledged u-boot command. 285 * - Doesn't check for keypresses before booting, since that could be a 286 * security hole; also disables Ctrl-C. 287 * - Doesn't allow the command to return. 288 * 289 * Upon any failures, this function will drop into an infinite loop after 290 * printing the error message to console. 291 */ 292 293 #if defined(CONFIG_BOOTDELAY) && defined(CONFIG_OF_CONTROL) 294 static void secure_boot_cmd(char *cmd) 295 { 296 cmd_tbl_t *cmdtp; 297 int rc; 298 299 if (!cmd) { 300 printf("## Error: Secure boot command not specified\n"); 301 goto err; 302 } 303 304 /* Disable Ctrl-C just in case some command is used that checks it. */ 305 disable_ctrlc(1); 306 307 /* Find the command directly. */ 308 cmdtp = find_cmd(cmd); 309 if (!cmdtp) { 310 printf("## Error: \"%s\" not defined\n", cmd); 311 goto err; 312 } 313 314 /* Run the command, forcing no flags and faking argc and argv. */ 315 rc = (cmdtp->cmd)(cmdtp, 0, 1, &cmd); 316 317 /* Shouldn't ever return from boot command. */ 318 printf("## Error: \"%s\" returned (code %d)\n", cmd, rc); 319 320 err: 321 /* 322 * Not a whole lot to do here. Rebooting won't help much, since we'll 323 * just end up right back here. Just loop. 324 */ 325 hang(); 326 } 327 328 static void process_fdt_options(const void *blob) 329 { 330 ulong addr; 331 332 /* Add an env variable to point to a kernel payload, if available */ 333 addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0); 334 if (addr) 335 setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); 336 337 /* Add an env variable to point to a root disk, if available */ 338 addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0); 339 if (addr) 340 setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); 341 } 342 #endif /* CONFIG_OF_CONTROL */ 343 344 345 /****************************************************************************/ 346 347 void main_loop (void) 348 { 349 #ifndef CONFIG_SYS_HUSH_PARSER 350 static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, }; 351 int len; 352 int rc = 1; 353 int flag; 354 #endif 355 #if defined(CONFIG_BOOTDELAY) && defined(CONFIG_OF_CONTROL) 356 char *env; 357 #endif 358 #if defined(CONFIG_BOOTDELAY) 359 char *s; 360 int bootdelay; 361 #endif 362 #ifdef CONFIG_PREBOOT 363 char *p; 364 #endif 365 #ifdef CONFIG_BOOTCOUNT_LIMIT 366 unsigned long bootcount = 0; 367 unsigned long bootlimit = 0; 368 char *bcs; 369 char bcs_set[16]; 370 #endif /* CONFIG_BOOTCOUNT_LIMIT */ 371 372 bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop"); 373 374 #ifdef CONFIG_BOOTCOUNT_LIMIT 375 bootcount = bootcount_load(); 376 bootcount++; 377 bootcount_store (bootcount); 378 sprintf (bcs_set, "%lu", bootcount); 379 setenv ("bootcount", bcs_set); 380 bcs = getenv ("bootlimit"); 381 bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0; 382 #endif /* CONFIG_BOOTCOUNT_LIMIT */ 383 384 #ifdef CONFIG_MODEM_SUPPORT 385 debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init); 386 if (do_mdm_init) { 387 char *str = strdup(getenv("mdm_cmd")); 388 setenv ("preboot", str); /* set or delete definition */ 389 if (str != NULL) 390 free (str); 391 mdm_init(); /* wait for modem connection */ 392 } 393 #endif /* CONFIG_MODEM_SUPPORT */ 394 395 #ifdef CONFIG_VERSION_VARIABLE 396 { 397 setenv ("ver", version_string); /* set version variable */ 398 } 399 #endif /* CONFIG_VERSION_VARIABLE */ 400 401 #ifdef CONFIG_SYS_HUSH_PARSER 402 u_boot_hush_start (); 403 #endif 404 405 #if defined(CONFIG_HUSH_INIT_VAR) 406 hush_init_var (); 407 #endif 408 409 #ifdef CONFIG_PREBOOT 410 if ((p = getenv ("preboot")) != NULL) { 411 # ifdef CONFIG_AUTOBOOT_KEYED 412 int prev = disable_ctrlc(1); /* disable Control C checking */ 413 # endif 414 415 run_command_list(p, -1, 0); 416 417 # ifdef CONFIG_AUTOBOOT_KEYED 418 disable_ctrlc(prev); /* restore Control C checking */ 419 # endif 420 } 421 #endif /* CONFIG_PREBOOT */ 422 423 #if defined(CONFIG_UPDATE_TFTP) 424 update_tftp (0UL); 425 #endif /* CONFIG_UPDATE_TFTP */ 426 427 #if defined(CONFIG_BOOTDELAY) 428 s = getenv ("bootdelay"); 429 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; 430 431 debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay); 432 433 #if defined(CONFIG_MENU_SHOW) 434 bootdelay = menu_show(bootdelay); 435 #endif 436 # ifdef CONFIG_BOOT_RETRY_TIME 437 init_cmd_timeout (); 438 # endif /* CONFIG_BOOT_RETRY_TIME */ 439 440 #ifdef CONFIG_POST 441 if (gd->flags & GD_FLG_POSTFAIL) { 442 s = getenv("failbootcmd"); 443 } 444 else 445 #endif /* CONFIG_POST */ 446 #ifdef CONFIG_BOOTCOUNT_LIMIT 447 if (bootlimit && (bootcount > bootlimit)) { 448 printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n", 449 (unsigned)bootlimit); 450 s = getenv ("altbootcmd"); 451 } 452 else 453 #endif /* CONFIG_BOOTCOUNT_LIMIT */ 454 s = getenv ("bootcmd"); 455 #ifdef CONFIG_OF_CONTROL 456 /* Allow the fdt to override the boot command */ 457 env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd"); 458 if (env) 459 s = env; 460 461 process_fdt_options(gd->fdt_blob); 462 463 /* 464 * If the bootsecure option was chosen, use secure_boot_cmd(). 465 * Always use 'env' in this case, since bootsecure requres that the 466 * bootcmd was specified in the FDT too. 467 */ 468 if (fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0)) 469 secure_boot_cmd(env); 470 471 #endif /* CONFIG_OF_CONTROL */ 472 473 debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); 474 475 if (bootdelay != -1 && s && !abortboot(bootdelay)) { 476 # ifdef CONFIG_AUTOBOOT_KEYED 477 int prev = disable_ctrlc(1); /* disable Control C checking */ 478 # endif 479 480 run_command_list(s, -1, 0); 481 482 # ifdef CONFIG_AUTOBOOT_KEYED 483 disable_ctrlc(prev); /* restore Control C checking */ 484 # endif 485 } 486 487 # ifdef CONFIG_MENUKEY 488 if (menukey == CONFIG_MENUKEY) { 489 s = getenv("menucmd"); 490 if (s) 491 run_command_list(s, -1, 0); 492 } 493 #endif /* CONFIG_MENUKEY */ 494 #endif /* CONFIG_BOOTDELAY */ 495 496 /* 497 * Main Loop for Monitor Command Processing 498 */ 499 #ifdef CONFIG_SYS_HUSH_PARSER 500 parse_file_outer(); 501 /* This point is never reached */ 502 for (;;); 503 #else 504 for (;;) { 505 #ifdef CONFIG_BOOT_RETRY_TIME 506 if (rc >= 0) { 507 /* Saw enough of a valid command to 508 * restart the timeout. 509 */ 510 reset_cmd_timeout(); 511 } 512 #endif 513 len = readline (CONFIG_SYS_PROMPT); 514 515 flag = 0; /* assume no special flags for now */ 516 if (len > 0) 517 strcpy (lastcommand, console_buffer); 518 else if (len == 0) 519 flag |= CMD_FLAG_REPEAT; 520 #ifdef CONFIG_BOOT_RETRY_TIME 521 else if (len == -2) { 522 /* -2 means timed out, retry autoboot 523 */ 524 puts ("\nTimed out waiting for command\n"); 525 # ifdef CONFIG_RESET_TO_RETRY 526 /* Reinit board to run initialization code again */ 527 do_reset (NULL, 0, 0, NULL); 528 # else 529 return; /* retry autoboot */ 530 # endif 531 } 532 #endif 533 534 if (len == -1) 535 puts ("<INTERRUPT>\n"); 536 else 537 rc = run_command(lastcommand, flag); 538 539 if (rc <= 0) { 540 /* invalid command or not repeatable, forget it */ 541 lastcommand[0] = 0; 542 } 543 } 544 #endif /*CONFIG_SYS_HUSH_PARSER*/ 545 } 546 547 #ifdef CONFIG_BOOT_RETRY_TIME 548 /*************************************************************************** 549 * initialize command line timeout 550 */ 551 void init_cmd_timeout(void) 552 { 553 char *s = getenv ("bootretry"); 554 555 if (s != NULL) 556 retry_time = (int)simple_strtol(s, NULL, 10); 557 else 558 retry_time = CONFIG_BOOT_RETRY_TIME; 559 560 if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN) 561 retry_time = CONFIG_BOOT_RETRY_MIN; 562 } 563 564 /*************************************************************************** 565 * reset command line timeout to retry_time seconds 566 */ 567 void reset_cmd_timeout(void) 568 { 569 endtime = endtick(retry_time); 570 } 571 #endif 572 573 #ifdef CONFIG_CMDLINE_EDITING 574 575 /* 576 * cmdline-editing related codes from vivi. 577 * Author: Janghoon Lyu <nandy@mizi.com> 578 */ 579 580 #define putnstr(str,n) do { \ 581 printf ("%.*s", (int)n, str); \ 582 } while (0) 583 584 #define CTL_CH(c) ((c) - 'a' + 1) 585 #define CTL_BACKSPACE ('\b') 586 #define DEL ((char)255) 587 #define DEL7 ((char)127) 588 #define CREAD_HIST_CHAR ('!') 589 590 #define getcmd_putch(ch) putc(ch) 591 #define getcmd_getch() getc() 592 #define getcmd_cbeep() getcmd_putch('\a') 593 594 #define HIST_MAX 20 595 #define HIST_SIZE CONFIG_SYS_CBSIZE 596 597 static int hist_max; 598 static int hist_add_idx; 599 static int hist_cur = -1; 600 static unsigned hist_num; 601 602 static char *hist_list[HIST_MAX]; 603 static char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */ 604 605 #define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1) 606 607 static void hist_init(void) 608 { 609 int i; 610 611 hist_max = 0; 612 hist_add_idx = 0; 613 hist_cur = -1; 614 hist_num = 0; 615 616 for (i = 0; i < HIST_MAX; i++) { 617 hist_list[i] = hist_lines[i]; 618 hist_list[i][0] = '\0'; 619 } 620 } 621 622 static void cread_add_to_hist(char *line) 623 { 624 strcpy(hist_list[hist_add_idx], line); 625 626 if (++hist_add_idx >= HIST_MAX) 627 hist_add_idx = 0; 628 629 if (hist_add_idx > hist_max) 630 hist_max = hist_add_idx; 631 632 hist_num++; 633 } 634 635 static char* hist_prev(void) 636 { 637 char *ret; 638 int old_cur; 639 640 if (hist_cur < 0) 641 return NULL; 642 643 old_cur = hist_cur; 644 if (--hist_cur < 0) 645 hist_cur = hist_max; 646 647 if (hist_cur == hist_add_idx) { 648 hist_cur = old_cur; 649 ret = NULL; 650 } else 651 ret = hist_list[hist_cur]; 652 653 return (ret); 654 } 655 656 static char* hist_next(void) 657 { 658 char *ret; 659 660 if (hist_cur < 0) 661 return NULL; 662 663 if (hist_cur == hist_add_idx) 664 return NULL; 665 666 if (++hist_cur > hist_max) 667 hist_cur = 0; 668 669 if (hist_cur == hist_add_idx) { 670 ret = ""; 671 } else 672 ret = hist_list[hist_cur]; 673 674 return (ret); 675 } 676 677 #ifndef CONFIG_CMDLINE_EDITING 678 static void cread_print_hist_list(void) 679 { 680 int i; 681 unsigned long n; 682 683 n = hist_num - hist_max; 684 685 i = hist_add_idx + 1; 686 while (1) { 687 if (i > hist_max) 688 i = 0; 689 if (i == hist_add_idx) 690 break; 691 printf("%s\n", hist_list[i]); 692 n++; 693 i++; 694 } 695 } 696 #endif /* CONFIG_CMDLINE_EDITING */ 697 698 #define BEGINNING_OF_LINE() { \ 699 while (num) { \ 700 getcmd_putch(CTL_BACKSPACE); \ 701 num--; \ 702 } \ 703 } 704 705 #define ERASE_TO_EOL() { \ 706 if (num < eol_num) { \ 707 printf("%*s", (int)(eol_num - num), ""); \ 708 do { \ 709 getcmd_putch(CTL_BACKSPACE); \ 710 } while (--eol_num > num); \ 711 } \ 712 } 713 714 #define REFRESH_TO_EOL() { \ 715 if (num < eol_num) { \ 716 wlen = eol_num - num; \ 717 putnstr(buf + num, wlen); \ 718 num = eol_num; \ 719 } \ 720 } 721 722 static void cread_add_char(char ichar, int insert, unsigned long *num, 723 unsigned long *eol_num, char *buf, unsigned long len) 724 { 725 unsigned long wlen; 726 727 /* room ??? */ 728 if (insert || *num == *eol_num) { 729 if (*eol_num > len - 1) { 730 getcmd_cbeep(); 731 return; 732 } 733 (*eol_num)++; 734 } 735 736 if (insert) { 737 wlen = *eol_num - *num; 738 if (wlen > 1) { 739 memmove(&buf[*num+1], &buf[*num], wlen-1); 740 } 741 742 buf[*num] = ichar; 743 putnstr(buf + *num, wlen); 744 (*num)++; 745 while (--wlen) { 746 getcmd_putch(CTL_BACKSPACE); 747 } 748 } else { 749 /* echo the character */ 750 wlen = 1; 751 buf[*num] = ichar; 752 putnstr(buf + *num, wlen); 753 (*num)++; 754 } 755 } 756 757 static void cread_add_str(char *str, int strsize, int insert, unsigned long *num, 758 unsigned long *eol_num, char *buf, unsigned long len) 759 { 760 while (strsize--) { 761 cread_add_char(*str, insert, num, eol_num, buf, len); 762 str++; 763 } 764 } 765 766 static int cread_line(const char *const prompt, char *buf, unsigned int *len, 767 int timeout) 768 { 769 unsigned long num = 0; 770 unsigned long eol_num = 0; 771 unsigned long wlen; 772 char ichar; 773 int insert = 1; 774 int esc_len = 0; 775 char esc_save[8]; 776 int init_len = strlen(buf); 777 int first = 1; 778 779 if (init_len) 780 cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len); 781 782 while (1) { 783 #ifdef CONFIG_BOOT_RETRY_TIME 784 while (!tstc()) { /* while no incoming data */ 785 if (retry_time >= 0 && get_ticks() > endtime) 786 return (-2); /* timed out */ 787 WATCHDOG_RESET(); 788 } 789 #endif 790 if (first && timeout) { 791 uint64_t etime = endtick(timeout); 792 793 while (!tstc()) { /* while no incoming data */ 794 if (get_ticks() >= etime) 795 return -2; /* timed out */ 796 WATCHDOG_RESET(); 797 } 798 first = 0; 799 } 800 801 ichar = getcmd_getch(); 802 803 if ((ichar == '\n') || (ichar == '\r')) { 804 putc('\n'); 805 break; 806 } 807 808 /* 809 * handle standard linux xterm esc sequences for arrow key, etc. 810 */ 811 if (esc_len != 0) { 812 if (esc_len == 1) { 813 if (ichar == '[') { 814 esc_save[esc_len] = ichar; 815 esc_len = 2; 816 } else { 817 cread_add_str(esc_save, esc_len, insert, 818 &num, &eol_num, buf, *len); 819 esc_len = 0; 820 } 821 continue; 822 } 823 824 switch (ichar) { 825 826 case 'D': /* <- key */ 827 ichar = CTL_CH('b'); 828 esc_len = 0; 829 break; 830 case 'C': /* -> key */ 831 ichar = CTL_CH('f'); 832 esc_len = 0; 833 break; /* pass off to ^F handler */ 834 case 'H': /* Home key */ 835 ichar = CTL_CH('a'); 836 esc_len = 0; 837 break; /* pass off to ^A handler */ 838 case 'A': /* up arrow */ 839 ichar = CTL_CH('p'); 840 esc_len = 0; 841 break; /* pass off to ^P handler */ 842 case 'B': /* down arrow */ 843 ichar = CTL_CH('n'); 844 esc_len = 0; 845 break; /* pass off to ^N handler */ 846 default: 847 esc_save[esc_len++] = ichar; 848 cread_add_str(esc_save, esc_len, insert, 849 &num, &eol_num, buf, *len); 850 esc_len = 0; 851 continue; 852 } 853 } 854 855 switch (ichar) { 856 case 0x1b: 857 if (esc_len == 0) { 858 esc_save[esc_len] = ichar; 859 esc_len = 1; 860 } else { 861 puts("impossible condition #876\n"); 862 esc_len = 0; 863 } 864 break; 865 866 case CTL_CH('a'): 867 BEGINNING_OF_LINE(); 868 break; 869 case CTL_CH('c'): /* ^C - break */ 870 *buf = '\0'; /* discard input */ 871 return (-1); 872 case CTL_CH('f'): 873 if (num < eol_num) { 874 getcmd_putch(buf[num]); 875 num++; 876 } 877 break; 878 case CTL_CH('b'): 879 if (num) { 880 getcmd_putch(CTL_BACKSPACE); 881 num--; 882 } 883 break; 884 case CTL_CH('d'): 885 if (num < eol_num) { 886 wlen = eol_num - num - 1; 887 if (wlen) { 888 memmove(&buf[num], &buf[num+1], wlen); 889 putnstr(buf + num, wlen); 890 } 891 892 getcmd_putch(' '); 893 do { 894 getcmd_putch(CTL_BACKSPACE); 895 } while (wlen--); 896 eol_num--; 897 } 898 break; 899 case CTL_CH('k'): 900 ERASE_TO_EOL(); 901 break; 902 case CTL_CH('e'): 903 REFRESH_TO_EOL(); 904 break; 905 case CTL_CH('o'): 906 insert = !insert; 907 break; 908 case CTL_CH('x'): 909 case CTL_CH('u'): 910 BEGINNING_OF_LINE(); 911 ERASE_TO_EOL(); 912 break; 913 case DEL: 914 case DEL7: 915 case 8: 916 if (num) { 917 wlen = eol_num - num; 918 num--; 919 memmove(&buf[num], &buf[num+1], wlen); 920 getcmd_putch(CTL_BACKSPACE); 921 putnstr(buf + num, wlen); 922 getcmd_putch(' '); 923 do { 924 getcmd_putch(CTL_BACKSPACE); 925 } while (wlen--); 926 eol_num--; 927 } 928 break; 929 case CTL_CH('p'): 930 case CTL_CH('n'): 931 { 932 char * hline; 933 934 esc_len = 0; 935 936 if (ichar == CTL_CH('p')) 937 hline = hist_prev(); 938 else 939 hline = hist_next(); 940 941 if (!hline) { 942 getcmd_cbeep(); 943 continue; 944 } 945 946 /* nuke the current line */ 947 /* first, go home */ 948 BEGINNING_OF_LINE(); 949 950 /* erase to end of line */ 951 ERASE_TO_EOL(); 952 953 /* copy new line into place and display */ 954 strcpy(buf, hline); 955 eol_num = strlen(buf); 956 REFRESH_TO_EOL(); 957 continue; 958 } 959 #ifdef CONFIG_AUTO_COMPLETE 960 case '\t': { 961 int num2, col; 962 963 /* do not autocomplete when in the middle */ 964 if (num < eol_num) { 965 getcmd_cbeep(); 966 break; 967 } 968 969 buf[num] = '\0'; 970 col = strlen(prompt) + eol_num; 971 num2 = num; 972 if (cmd_auto_complete(prompt, buf, &num2, &col)) { 973 col = num2 - num; 974 num += col; 975 eol_num += col; 976 } 977 break; 978 } 979 #endif 980 default: 981 cread_add_char(ichar, insert, &num, &eol_num, buf, *len); 982 break; 983 } 984 } 985 *len = eol_num; 986 buf[eol_num] = '\0'; /* lose the newline */ 987 988 if (buf[0] && buf[0] != CREAD_HIST_CHAR) 989 cread_add_to_hist(buf); 990 hist_cur = hist_add_idx; 991 992 return 0; 993 } 994 995 #endif /* CONFIG_CMDLINE_EDITING */ 996 997 /****************************************************************************/ 998 999 /* 1000 * Prompt for input and read a line. 1001 * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0, 1002 * time out when time goes past endtime (timebase time in ticks). 1003 * Return: number of read characters 1004 * -1 if break 1005 * -2 if timed out 1006 */ 1007 int readline (const char *const prompt) 1008 { 1009 /* 1010 * If console_buffer isn't 0-length the user will be prompted to modify 1011 * it instead of entering it from scratch as desired. 1012 */ 1013 console_buffer[0] = '\0'; 1014 1015 return readline_into_buffer(prompt, console_buffer, 0); 1016 } 1017 1018 1019 int readline_into_buffer(const char *const prompt, char *buffer, int timeout) 1020 { 1021 char *p = buffer; 1022 #ifdef CONFIG_CMDLINE_EDITING 1023 unsigned int len = CONFIG_SYS_CBSIZE; 1024 int rc; 1025 static int initted = 0; 1026 1027 /* 1028 * History uses a global array which is not 1029 * writable until after relocation to RAM. 1030 * Revert to non-history version if still 1031 * running from flash. 1032 */ 1033 if (gd->flags & GD_FLG_RELOC) { 1034 if (!initted) { 1035 hist_init(); 1036 initted = 1; 1037 } 1038 1039 if (prompt) 1040 puts (prompt); 1041 1042 rc = cread_line(prompt, p, &len, timeout); 1043 return rc < 0 ? rc : len; 1044 1045 } else { 1046 #endif /* CONFIG_CMDLINE_EDITING */ 1047 char * p_buf = p; 1048 int n = 0; /* buffer index */ 1049 int plen = 0; /* prompt length */ 1050 int col; /* output column cnt */ 1051 char c; 1052 1053 /* print prompt */ 1054 if (prompt) { 1055 plen = strlen (prompt); 1056 puts (prompt); 1057 } 1058 col = plen; 1059 1060 for (;;) { 1061 #ifdef CONFIG_BOOT_RETRY_TIME 1062 while (!tstc()) { /* while no incoming data */ 1063 if (retry_time >= 0 && get_ticks() > endtime) 1064 return (-2); /* timed out */ 1065 WATCHDOG_RESET(); 1066 } 1067 #endif 1068 WATCHDOG_RESET(); /* Trigger watchdog, if needed */ 1069 1070 #ifdef CONFIG_SHOW_ACTIVITY 1071 while (!tstc()) { 1072 show_activity(0); 1073 WATCHDOG_RESET(); 1074 } 1075 #endif 1076 c = getc(); 1077 1078 /* 1079 * Special character handling 1080 */ 1081 switch (c) { 1082 case '\r': /* Enter */ 1083 case '\n': 1084 *p = '\0'; 1085 puts ("\r\n"); 1086 return (p - p_buf); 1087 1088 case '\0': /* nul */ 1089 continue; 1090 1091 case 0x03: /* ^C - break */ 1092 p_buf[0] = '\0'; /* discard input */ 1093 return (-1); 1094 1095 case 0x15: /* ^U - erase line */ 1096 while (col > plen) { 1097 puts (erase_seq); 1098 --col; 1099 } 1100 p = p_buf; 1101 n = 0; 1102 continue; 1103 1104 case 0x17: /* ^W - erase word */ 1105 p=delete_char(p_buf, p, &col, &n, plen); 1106 while ((n > 0) && (*p != ' ')) { 1107 p=delete_char(p_buf, p, &col, &n, plen); 1108 } 1109 continue; 1110 1111 case 0x08: /* ^H - backspace */ 1112 case 0x7F: /* DEL - backspace */ 1113 p=delete_char(p_buf, p, &col, &n, plen); 1114 continue; 1115 1116 default: 1117 /* 1118 * Must be a normal character then 1119 */ 1120 if (n < CONFIG_SYS_CBSIZE-2) { 1121 if (c == '\t') { /* expand TABs */ 1122 #ifdef CONFIG_AUTO_COMPLETE 1123 /* if auto completion triggered just continue */ 1124 *p = '\0'; 1125 if (cmd_auto_complete(prompt, console_buffer, &n, &col)) { 1126 p = p_buf + n; /* reset */ 1127 continue; 1128 } 1129 #endif 1130 puts (tab_seq+(col&07)); 1131 col += 8 - (col&07); 1132 } else { 1133 char buf[2]; 1134 1135 /* 1136 * Echo input using puts() to force am 1137 * LCD flush if we are using an LCD 1138 */ 1139 ++col; 1140 buf[0] = c; 1141 buf[1] = '\0'; 1142 puts(buf); 1143 } 1144 *p++ = c; 1145 ++n; 1146 } else { /* Buffer full */ 1147 putc ('\a'); 1148 } 1149 } 1150 } 1151 #ifdef CONFIG_CMDLINE_EDITING 1152 } 1153 #endif 1154 } 1155 1156 /****************************************************************************/ 1157 1158 static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen) 1159 { 1160 char *s; 1161 1162 if (*np == 0) { 1163 return (p); 1164 } 1165 1166 if (*(--p) == '\t') { /* will retype the whole line */ 1167 while (*colp > plen) { 1168 puts (erase_seq); 1169 (*colp)--; 1170 } 1171 for (s=buffer; s<p; ++s) { 1172 if (*s == '\t') { 1173 puts (tab_seq+((*colp) & 07)); 1174 *colp += 8 - ((*colp) & 07); 1175 } else { 1176 ++(*colp); 1177 putc (*s); 1178 } 1179 } 1180 } else { 1181 puts (erase_seq); 1182 (*colp)--; 1183 } 1184 (*np)--; 1185 return (p); 1186 } 1187 1188 /****************************************************************************/ 1189 1190 int parse_line (char *line, char *argv[]) 1191 { 1192 int nargs = 0; 1193 1194 #ifdef DEBUG_PARSER 1195 printf ("parse_line: \"%s\"\n", line); 1196 #endif 1197 while (nargs < CONFIG_SYS_MAXARGS) { 1198 1199 /* skip any white space */ 1200 while (isblank(*line)) 1201 ++line; 1202 1203 if (*line == '\0') { /* end of line, no more args */ 1204 argv[nargs] = NULL; 1205 #ifdef DEBUG_PARSER 1206 printf ("parse_line: nargs=%d\n", nargs); 1207 #endif 1208 return (nargs); 1209 } 1210 1211 argv[nargs++] = line; /* begin of argument string */ 1212 1213 /* find end of string */ 1214 while (*line && !isblank(*line)) 1215 ++line; 1216 1217 if (*line == '\0') { /* end of line, no more args */ 1218 argv[nargs] = NULL; 1219 #ifdef DEBUG_PARSER 1220 printf ("parse_line: nargs=%d\n", nargs); 1221 #endif 1222 return (nargs); 1223 } 1224 1225 *line++ = '\0'; /* terminate current arg */ 1226 } 1227 1228 printf ("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS); 1229 1230 #ifdef DEBUG_PARSER 1231 printf ("parse_line: nargs=%d\n", nargs); 1232 #endif 1233 return (nargs); 1234 } 1235 1236 /****************************************************************************/ 1237 1238 #ifndef CONFIG_SYS_HUSH_PARSER 1239 static void process_macros (const char *input, char *output) 1240 { 1241 char c, prev; 1242 const char *varname_start = NULL; 1243 int inputcnt = strlen (input); 1244 int outputcnt = CONFIG_SYS_CBSIZE; 1245 int state = 0; /* 0 = waiting for '$' */ 1246 1247 /* 1 = waiting for '(' or '{' */ 1248 /* 2 = waiting for ')' or '}' */ 1249 /* 3 = waiting for ''' */ 1250 #ifdef DEBUG_PARSER 1251 char *output_start = output; 1252 1253 printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen (input), 1254 input); 1255 #endif 1256 1257 prev = '\0'; /* previous character */ 1258 1259 while (inputcnt && outputcnt) { 1260 c = *input++; 1261 inputcnt--; 1262 1263 if (state != 3) { 1264 /* remove one level of escape characters */ 1265 if ((c == '\\') && (prev != '\\')) { 1266 if (inputcnt-- == 0) 1267 break; 1268 prev = c; 1269 c = *input++; 1270 } 1271 } 1272 1273 switch (state) { 1274 case 0: /* Waiting for (unescaped) $ */ 1275 if ((c == '\'') && (prev != '\\')) { 1276 state = 3; 1277 break; 1278 } 1279 if ((c == '$') && (prev != '\\')) { 1280 state++; 1281 } else { 1282 *(output++) = c; 1283 outputcnt--; 1284 } 1285 break; 1286 case 1: /* Waiting for ( */ 1287 if (c == '(' || c == '{') { 1288 state++; 1289 varname_start = input; 1290 } else { 1291 state = 0; 1292 *(output++) = '$'; 1293 outputcnt--; 1294 1295 if (outputcnt) { 1296 *(output++) = c; 1297 outputcnt--; 1298 } 1299 } 1300 break; 1301 case 2: /* Waiting for ) */ 1302 if (c == ')' || c == '}') { 1303 int i; 1304 char envname[CONFIG_SYS_CBSIZE], *envval; 1305 int envcnt = input - varname_start - 1; /* Varname # of chars */ 1306 1307 /* Get the varname */ 1308 for (i = 0; i < envcnt; i++) { 1309 envname[i] = varname_start[i]; 1310 } 1311 envname[i] = 0; 1312 1313 /* Get its value */ 1314 envval = getenv (envname); 1315 1316 /* Copy into the line if it exists */ 1317 if (envval != NULL) 1318 while ((*envval) && outputcnt) { 1319 *(output++) = *(envval++); 1320 outputcnt--; 1321 } 1322 /* Look for another '$' */ 1323 state = 0; 1324 } 1325 break; 1326 case 3: /* Waiting for ' */ 1327 if ((c == '\'') && (prev != '\\')) { 1328 state = 0; 1329 } else { 1330 *(output++) = c; 1331 outputcnt--; 1332 } 1333 break; 1334 } 1335 prev = c; 1336 } 1337 1338 if (outputcnt) 1339 *output = 0; 1340 else 1341 *(output - 1) = 0; 1342 1343 #ifdef DEBUG_PARSER 1344 printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n", 1345 strlen (output_start), output_start); 1346 #endif 1347 } 1348 1349 /**************************************************************************** 1350 * returns: 1351 * 1 - command executed, repeatable 1352 * 0 - command executed but not repeatable, interrupted commands are 1353 * always considered not repeatable 1354 * -1 - not executed (unrecognized, bootd recursion or too many args) 1355 * (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is 1356 * considered unrecognized) 1357 * 1358 * WARNING: 1359 * 1360 * We must create a temporary copy of the command since the command we get 1361 * may be the result from getenv(), which returns a pointer directly to 1362 * the environment data, which may change magicly when the command we run 1363 * creates or modifies environment variables (like "bootp" does). 1364 */ 1365 static int builtin_run_command(const char *cmd, int flag) 1366 { 1367 char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */ 1368 char *token; /* start of token in cmdbuf */ 1369 char *sep; /* end of token (separator) in cmdbuf */ 1370 char finaltoken[CONFIG_SYS_CBSIZE]; 1371 char *str = cmdbuf; 1372 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */ 1373 int argc, inquotes; 1374 int repeatable = 1; 1375 int rc = 0; 1376 1377 #ifdef DEBUG_PARSER 1378 printf ("[RUN_COMMAND] cmd[%p]=\"", cmd); 1379 puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */ 1380 puts ("\"\n"); 1381 #endif 1382 1383 clear_ctrlc(); /* forget any previous Control C */ 1384 1385 if (!cmd || !*cmd) { 1386 return -1; /* empty command */ 1387 } 1388 1389 if (strlen(cmd) >= CONFIG_SYS_CBSIZE) { 1390 puts ("## Command too long!\n"); 1391 return -1; 1392 } 1393 1394 strcpy (cmdbuf, cmd); 1395 1396 /* Process separators and check for invalid 1397 * repeatable commands 1398 */ 1399 1400 #ifdef DEBUG_PARSER 1401 printf ("[PROCESS_SEPARATORS] %s\n", cmd); 1402 #endif 1403 while (*str) { 1404 1405 /* 1406 * Find separator, or string end 1407 * Allow simple escape of ';' by writing "\;" 1408 */ 1409 for (inquotes = 0, sep = str; *sep; sep++) { 1410 if ((*sep=='\'') && 1411 (*(sep-1) != '\\')) 1412 inquotes=!inquotes; 1413 1414 if (!inquotes && 1415 (*sep == ';') && /* separator */ 1416 ( sep != str) && /* past string start */ 1417 (*(sep-1) != '\\')) /* and NOT escaped */ 1418 break; 1419 } 1420 1421 /* 1422 * Limit the token to data between separators 1423 */ 1424 token = str; 1425 if (*sep) { 1426 str = sep + 1; /* start of command for next pass */ 1427 *sep = '\0'; 1428 } 1429 else 1430 str = sep; /* no more commands for next pass */ 1431 #ifdef DEBUG_PARSER 1432 printf ("token: \"%s\"\n", token); 1433 #endif 1434 1435 /* find macros in this token and replace them */ 1436 process_macros (token, finaltoken); 1437 1438 /* Extract arguments */ 1439 if ((argc = parse_line (finaltoken, argv)) == 0) { 1440 rc = -1; /* no command at all */ 1441 continue; 1442 } 1443 1444 if (cmd_process(flag, argc, argv, &repeatable, NULL)) 1445 rc = -1; 1446 1447 /* Did the user stop this? */ 1448 if (had_ctrlc ()) 1449 return -1; /* if stopped then not repeatable */ 1450 } 1451 1452 return rc ? rc : repeatable; 1453 } 1454 #endif 1455 1456 /* 1457 * Run a command using the selected parser. 1458 * 1459 * @param cmd Command to run 1460 * @param flag Execution flags (CMD_FLAG_...) 1461 * @return 0 on success, or != 0 on error. 1462 */ 1463 int run_command(const char *cmd, int flag) 1464 { 1465 #ifndef CONFIG_SYS_HUSH_PARSER 1466 /* 1467 * builtin_run_command can return 0 or 1 for success, so clean up 1468 * its result. 1469 */ 1470 if (builtin_run_command(cmd, flag) == -1) 1471 return 1; 1472 1473 return 0; 1474 #else 1475 return parse_string_outer(cmd, 1476 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); 1477 #endif 1478 } 1479 1480 #ifndef CONFIG_SYS_HUSH_PARSER 1481 /** 1482 * Execute a list of command separated by ; or \n using the built-in parser. 1483 * 1484 * This function cannot take a const char * for the command, since if it 1485 * finds newlines in the string, it replaces them with \0. 1486 * 1487 * @param cmd String containing list of commands 1488 * @param flag Execution flags (CMD_FLAG_...) 1489 * @return 0 on success, or != 0 on error. 1490 */ 1491 static int builtin_run_command_list(char *cmd, int flag) 1492 { 1493 char *line, *next; 1494 int rcode = 0; 1495 1496 /* 1497 * Break into individual lines, and execute each line; terminate on 1498 * error. 1499 */ 1500 line = next = cmd; 1501 while (*next) { 1502 if (*next == '\n') { 1503 *next = '\0'; 1504 /* run only non-empty commands */ 1505 if (*line) { 1506 debug("** exec: \"%s\"\n", line); 1507 if (builtin_run_command(line, 0) < 0) { 1508 rcode = 1; 1509 break; 1510 } 1511 } 1512 line = next + 1; 1513 } 1514 ++next; 1515 } 1516 if (rcode == 0 && *line) 1517 rcode = (builtin_run_command(line, 0) >= 0); 1518 1519 return rcode; 1520 } 1521 #endif 1522 1523 int run_command_list(const char *cmd, int len, int flag) 1524 { 1525 int need_buff = 1; 1526 char *buff = (char *)cmd; /* cast away const */ 1527 int rcode = 0; 1528 1529 if (len == -1) { 1530 len = strlen(cmd); 1531 #ifdef CONFIG_SYS_HUSH_PARSER 1532 /* hush will never change our string */ 1533 need_buff = 0; 1534 #else 1535 /* the built-in parser will change our string if it sees \n */ 1536 need_buff = strchr(cmd, '\n') != NULL; 1537 #endif 1538 } 1539 if (need_buff) { 1540 buff = malloc(len + 1); 1541 if (!buff) 1542 return 1; 1543 memcpy(buff, cmd, len); 1544 buff[len] = '\0'; 1545 } 1546 #ifdef CONFIG_SYS_HUSH_PARSER 1547 rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON); 1548 #else 1549 /* 1550 * This function will overwrite any \n it sees with a \0, which 1551 * is why it can't work with a const char *. Here we are making 1552 * using of internal knowledge of this function, to avoid always 1553 * doing a malloc() which is actually required only in a case that 1554 * is pretty rare. 1555 */ 1556 rcode = builtin_run_command_list(buff, flag); 1557 if (need_buff) 1558 free(buff); 1559 #endif 1560 1561 return rcode; 1562 } 1563 1564 /****************************************************************************/ 1565 1566 #if defined(CONFIG_CMD_RUN) 1567 int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 1568 { 1569 int i; 1570 1571 if (argc < 2) 1572 return CMD_RET_USAGE; 1573 1574 for (i=1; i<argc; ++i) { 1575 char *arg; 1576 1577 if ((arg = getenv (argv[i])) == NULL) { 1578 printf ("## Error: \"%s\" not defined\n", argv[i]); 1579 return 1; 1580 } 1581 1582 if (run_command(arg, flag) != 0) 1583 return 1; 1584 } 1585 return 0; 1586 } 1587 #endif 1588