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