Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/shell/lash.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/shell/lash.c
r821 r1770 21 21 //#define DEBUG_SHELL 22 22 23 24 #include "busybox.h"25 #include <stdio.h>26 #include <stdlib.h>27 #include <ctype.h>28 #include <errno.h>29 #include <fcntl.h>30 #include <signal.h>31 #include <string.h>32 #include <sys/ioctl.h>33 #include <sys/wait.h>34 #include <unistd.h>35 23 #include <getopt.h> 36 #include <termios.h>37 #include "cmdedit.h"38 39 #ifdef CONFIG_LOCALE_SUPPORT40 #include <locale.h>41 #endif42 43 24 #include <glob.h> 25 26 #include "busybox.h" /* for struct bb_applet */ 27 44 28 #define expand_t glob_t 45 29 … … 47 31 #define CONFIG_LASH_PIPE_N_REDIRECTS 48 32 #define CONFIG_LASH_JOB_CONTROL 49 50 static const int MAX_READ = 128; /* size of input buffer for `read' builtin */ 33 #define ENABLE_LASH_PIPE_N_REDIRECTS 1 34 #define ENABLE_LASH_JOB_CONTROL 1 35 36 37 enum { MAX_READ = 128 }; /* size of input buffer for 'read' builtin */ 51 38 #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 52 39 53 40 54 #if def CONFIG_LASH_PIPE_N_REDIRECTS41 #if ENABLE_LASH_PIPE_N_REDIRECTS 55 42 enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE, 56 43 REDIRECT_APPEND … … 66 53 }; 67 54 68 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS 55 #define LASH_OPT_DONE (1) 56 #define LASH_OPT_SAW_QUOTE (2) 57 58 #if ENABLE_LASH_PIPE_N_REDIRECTS 69 59 struct redir_struct { 70 60 enum redir_type type; /* type of redirection */ … … 80 70 int is_stopped; /* is the program currently running? */ 81 71 struct job *family; /* pointer back to the child's parent job */ 82 #if def CONFIG_LASH_PIPE_N_REDIRECTS72 #if ENABLE_LASH_PIPE_N_REDIRECTS 83 73 struct redir_struct *redirects; /* I/O redirects */ 84 74 #endif … … 105 95 106 96 struct built_in_command { 107 c har *cmd;/* name */108 c har *descr;/* description */97 const char *cmd; /* name */ 98 const char *descr; /* description */ 109 99 int (*function) (struct child_prog *); /* function ptr */ 110 100 }; … … 127 117 static void checkjobs(struct jobset *job_list); 128 118 static void remove_job(struct jobset *j_list, struct job *job); 129 static int get_command (FILE * source, char *command);119 static int get_command_bufsiz(FILE * source, char *command); 130 120 static int parse_command(char **command_ptr, struct job *job, int *inbg); 131 121 static int run_command(struct job *newjob, int inbg, int outpipe[2]); … … 137 127 * can change global variables in the parent shell process but they will not 138 128 * work with pipes and redirects; 'unset foo | whatever' will not work) */ 139 static struct built_in_command bltins[] = {140 {"bg" , "Resume a job in the background", builtin_fg_bg},141 {"cd" , "Change working directory", builtin_cd},142 {"exec" , "Exec command, replacing this shell with the exec'd process", builtin_exec},143 {"exit" , "Exit from shell()", builtin_exit},144 {"fg" , "Bring job into the foreground", builtin_fg_bg},145 {"jobs" , "Lists the active jobs", builtin_jobs},129 static const struct built_in_command bltins[] = { 130 {"bg" , "Resume a job in the background", builtin_fg_bg}, 131 {"cd" , "Change working directory", builtin_cd}, 132 {"exec" , "Exec command, replacing this shell with the exec'd process", builtin_exec}, 133 {"exit" , "Exit from shell()", builtin_exit}, 134 {"fg" , "Bring job into the foreground", builtin_fg_bg}, 135 {"jobs" , "Lists the active jobs", builtin_jobs}, 146 136 {"export", "Set environment variable", builtin_export}, 147 {"unset", "Unset environment variable", builtin_unset}, 148 {"read", "Input environment variable", builtin_read}, 149 {".", "Source-in and run commands in a file", builtin_source}, 137 {"unset" , "Unset environment variable", builtin_unset}, 138 {"read" , "Input environment variable", builtin_read}, 139 {"." , "Source-in and run commands in a file", builtin_source}, 140 /* These were "forked applets", but distinction was nuked */ 141 /* Original comment retained: */ 142 /* Table of forking built-in functions (things that fork cannot change global 143 * variables in the parent process, such as the current working directory) */ 144 {"pwd" , "Print current directory", builtin_pwd}, 145 {"help" , "List shell built-in commands", builtin_help}, 150 146 /* to do: add ulimit */ 151 {NULL, NULL, NULL}152 147 }; 153 148 154 /* Table of forking built-in functions (things that fork cannot change global 155 * variables in the parent process, such as the current working directory) */ 156 static struct built_in_command bltins_forking[] = { 157 {"pwd", "Print current directory", builtin_pwd}, 158 {"help", "List shell built-in commands", builtin_help}, 159 {NULL, NULL, NULL} 160 }; 149 150 #define VEC_LAST(v) v[ARRAY_SIZE(v)-1] 161 151 162 152 … … 165 155 166 156 /* Globals that are static to this file */ 167 static c onst char *cwd;168 static char *local_pending_command = NULL;157 static char *cwd; 158 static char *local_pending_command; 169 159 static struct jobset job_list = { NULL, NULL }; 170 160 static int argc; … … 175 165 static unsigned int last_jobid; 176 166 static int shell_terminal; 177 static c har *PS1;178 static c har *PS2 = "> ";167 static const char *PS1; 168 static const char *PS2 = "> "; 179 169 180 170 … … 188 178 } 189 179 #else 190 static inline void debug_printf(const char *format, ...) { }180 static inline void debug_printf(const char ATTRIBUTE_UNUSED *format, ...) { } 191 181 #endif 192 182 … … 219 209 */ 220 210 211 212 static void update_cwd(void) 213 { 214 cwd = xrealloc_getcwd_or_warn(cwd); 215 if (!cwd) 216 cwd = xstrdup(bb_msg_unknown); 217 } 218 221 219 /* built-in 'cd <path>' handler */ 222 220 static int builtin_cd(struct child_prog *child) … … 232 230 return EXIT_FAILURE; 233 231 } 234 cwd = xgetcwd((char *)cwd); 235 if (!cwd) 236 cwd = bb_msg_unknown; 232 update_cwd(); 237 233 return EXIT_SUCCESS; 238 234 } … … 244 240 return EXIT_SUCCESS; /* Really? */ 245 241 child->argv++; 246 while(close_me_list) close((long)llist_pop(&close_me_list)); 242 while (close_me_list) 243 close((long)llist_pop(&close_me_list)); 247 244 pseudo_exec(child); 248 245 /* never returns */ … … 255 252 exit(EXIT_SUCCESS); 256 253 257 exit 254 exit(atoi(child->argv[1])); 258 255 } 259 256 … … 262 259 { 263 260 int i, jobnum; 264 struct job *job =NULL;261 struct job *job; 265 262 266 263 /* If they gave us no args, assume they want the last backgrounded task */ … … 268 265 for (job = child->family->job_list->head; job; job = job->next) { 269 266 if (job->jobid == last_jobid) { 270 break; 271 } 272 } 273 if (!job) { 274 bb_error_msg("%s: no current job", child->argv[0]); 275 return EXIT_FAILURE; 276 } 277 } else { 278 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { 279 bb_error_msg(bb_msg_invalid_arg, child->argv[1], child->argv[0]); 280 return EXIT_FAILURE; 281 } 282 for (job = child->family->job_list->head; job; job = job->next) { 283 if (job->jobid == jobnum) { 284 break; 285 } 286 } 287 if (!job) { 288 bb_error_msg("%s: %d: no such job", child->argv[0], jobnum); 289 return EXIT_FAILURE; 290 } 291 } 292 267 goto found; 268 } 269 } 270 bb_error_msg("%s: no current job", child->argv[0]); 271 return EXIT_FAILURE; 272 } 273 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { 274 bb_error_msg(bb_msg_invalid_arg, child->argv[1], child->argv[0]); 275 return EXIT_FAILURE; 276 } 277 for (job = child->family->job_list->head; job; job = job->next) { 278 if (job->jobid == jobnum) { 279 goto found; 280 } 281 } 282 bb_error_msg("%s: %d: no such job", child->argv[0], jobnum); 283 return EXIT_FAILURE; 284 found: 293 285 if (*child->argv[0] == 'f') { 294 286 /* Put the job into the foreground. */ … … 304 296 job->stopped_progs = 0; 305 297 306 if ( (i=kill(- job->pgrp, SIGCONT)) < 0) { 307 if (i == ESRCH) { 298 i = kill(- job->pgrp, SIGCONT); 299 if (i < 0) { 300 if (errno == ESRCH) { 308 301 remove_job(&job_list, job); 309 302 } else { … … 316 309 317 310 /* built-in 'help' handler */ 318 static int builtin_help(struct child_prog *dummy)319 { 320 struct built_in_command *x;321 322 printf("\nBuilt-in commands:\n" );323 printf("-------------------\n");324 for (x = bltins; x ->cmd; x++) {325 if (x->descr ==NULL)311 static int builtin_help(struct child_prog ATTRIBUTE_UNUSED *dummy) 312 { 313 const struct built_in_command *x; 314 315 printf("\nBuilt-in commands:\n" 316 "-------------------\n"); 317 for (x = bltins; x <= &VEC_LAST(bltins); x++) { 318 if (x->descr == NULL) 326 319 continue; 327 320 printf("%s\t%s\n", x->cmd, x->descr); 328 321 } 329 for (x = bltins_forking; x->cmd; x++) { 330 if (x->descr==NULL) 331 continue; 332 printf("%s\t%s\n", x->cmd, x->descr); 333 } 334 printf("\n\n"); 322 putchar('\n'); 335 323 return EXIT_SUCCESS; 336 324 } … … 340 328 { 341 329 struct job *job; 342 c har *status_string;330 const char *status_string; 343 331 344 332 for (job = child->family->job_list->head; job; job = job->next) { … … 355 343 356 344 /* built-in 'pwd' handler */ 357 static int builtin_pwd(struct child_prog *dummy) 358 { 359 cwd = xgetcwd((char *)cwd); 360 if (!cwd) 361 cwd = bb_msg_unknown; 345 static int builtin_pwd(struct child_prog ATTRIBUTE_UNUSED *dummy) 346 { 347 update_cwd(); 362 348 puts(cwd); 363 349 return EXIT_SUCCESS; … … 380 366 if (res) 381 367 bb_perror_msg("export"); 382 #if def CONFIG_FEATURE_SH_FANCY_PROMPT383 if (strncmp(v, "PS1=", 4) ==0)368 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT 369 if (strncmp(v, "PS1=", 4) == 0) 384 370 PS1 = getenv("PS1"); 385 371 #endif 386 372 387 #ifdef CONFIG_LOCALE_SUPPORT 388 if(strncmp(v, "LC_ALL=", 7)==0) 373 #if ENABLE_LOCALE_SUPPORT 374 // TODO: why getenv? "" would be just as good... 375 if (strncmp(v, "LC_ALL=", 7) == 0) 389 376 setlocale(LC_ALL, getenv("LC_ALL")); 390 if (strncmp(v, "LC_CTYPE=", 9)==0)377 if (strncmp(v, "LC_CTYPE=", 9) == 0) 391 378 setlocale(LC_CTYPE, getenv("LC_CTYPE")); 392 379 #endif 393 380 394 return (res);381 return res; 395 382 } 396 383 … … 398 385 static int builtin_read(struct child_prog *child) 399 386 { 400 int res = 0, len , newlen;387 int res = 0, len; 401 388 char *s; 402 389 char string[MAX_READ]; … … 409 396 string[len] = '\0'; 410 397 fgets(&string[len], sizeof(string) - len, stdin); /* read string */ 411 newlen= strlen(string);412 if (newlen> len)413 string[-- newlen] = '\0'; /* chomp trailing newline */398 res = strlen(string); 399 if (res > len) 400 string[--res] = '\0'; /* chomp trailing newline */ 414 401 /* 415 402 ** string should now contain "VAR=<value>" … … 418 405 */ 419 406 res = -1; 420 if((s = strdup(string))) 407 s = strdup(string); 408 if (s) 421 409 res = putenv(s); 422 410 if (res) 423 411 bb_perror_msg("read"); 424 } 425 else 412 } else 426 413 fgets(string, sizeof(string), stdin); 427 414 428 return (res);415 return res; 429 416 } 430 417 … … 435 422 int status; 436 423 437 if (child->argv[1] == NULL) 438 return EXIT_FAILURE; 439 440 input = fopen(child->argv[1], "r"); 424 input = fopen_or_warn(child->argv[1], "r"); 441 425 if (!input) { 442 printf( "Couldn't open file '%s'\n", child->argv[1]);443 426 return EXIT_FAILURE; 444 427 } … … 449 432 fclose(input); 450 433 llist_pop(&close_me_list); 451 return (status);434 return status; 452 435 } 453 436 … … 463 446 } 464 447 465 #if def CONFIG_LASH_JOB_CONTROL448 #if ENABLE_LASH_JOB_CONTROL 466 449 /* free up all memory from a job */ 467 450 static void free_job(struct job *cmd) … … 472 455 for (i = 0; i < cmd->num_progs; i++) { 473 456 free(cmd->progs[i].argv); 474 #if def CONFIG_LASH_PIPE_N_REDIRECTS457 #if ENABLE_LASH_PIPE_N_REDIRECTS 475 458 if (cmd->progs[i].redirects) 476 459 free(cmd->progs[i].redirects); … … 527 510 528 511 /* This happens on backticked commands */ 529 if (job==NULL)512 if (job == NULL) 530 513 return; 531 514 … … 537 520 if (!job->running_progs) { 538 521 printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text); 539 last_jobid =0;522 last_jobid = 0; 540 523 remove_job(j_list, job); 541 524 } … … 544 527 job->stopped_progs++; 545 528 job->progs[prognum].is_stopped = 1; 546 547 #if 0548 /* Printing this stuff is a pain, since it tends to549 * overwrite the prompt an inconveinient moments. So550 * don't do that. */551 if (job->stopped_progs == job->num_progs) {552 printf(JOB_STATUS_FORMAT, job->jobid, "Stopped",553 job->text);554 }555 #endif556 529 } 557 530 } … … 572 545 #endif 573 546 574 #if def CONFIG_LASH_PIPE_N_REDIRECTS547 #if ENABLE_LASH_PIPE_N_REDIRECTS 575 548 /* squirrel != NULL means we squirrel away copies of stdin, stdout, 576 549 * and stderr if they are redirected. */ … … 595 568 } 596 569 597 openfd = open (redir->filename, mode, 0666);570 openfd = open3_or_warn(redir->filename, mode, 0666); 598 571 if (openfd < 0) { 599 572 /* this could get lost if stderr has been redirected, but 600 573 bash and ash both lose it as well (though zsh doesn't!) */ 601 bb_perror_msg("error opening %s", redir->filename);602 574 return 1; 603 575 } … … 606 578 if (squirrel && redir->fd < 3) { 607 579 squirrel[redir->fd] = dup(redir->fd); 608 fcntl 580 fcntl(squirrel[redir->fd], F_SETFD, FD_CLOEXEC); 609 581 } 610 582 dup2(openfd, redir->fd); … … 619 591 { 620 592 int i, fd; 621 for (i =0; i<3; i++) {593 for (i = 0; i < 3; i++) { 622 594 fd = squirrel[i]; 623 595 if (fd != -1) { … … 641 613 static inline void cmdedit_set_initial_prompt(void) 642 614 { 643 #if ndef CONFIG_FEATURE_SH_FANCY_PROMPT615 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 644 616 PS1 = NULL; 645 617 #else 646 618 PS1 = getenv("PS1"); 647 if (PS1==0)619 if (PS1 == 0) 648 620 PS1 = "\\w \\$ "; 649 621 #endif 650 622 } 651 623 652 static inline void setup_prompt_string(char **prompt_str)653 { 654 #if ndef CONFIG_FEATURE_SH_FANCY_PROMPT624 static inline const char* setup_prompt_string(void) 625 { 626 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 655 627 /* Set up the prompt */ 656 628 if (shell_context == 0) { 657 free(PS1); 658 PS1=xmalloc(strlen(cwd)+4); 659 sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); 660 *prompt_str = PS1; 629 char *ns; 630 free((char*)PS1); 631 ns = xmalloc(strlen(cwd)+4); 632 sprintf(ns, "%s %c ", cwd, (geteuid() != 0) ? '$': '#'); 633 PS1 = ns; 634 return ns; 661 635 } else { 662 *prompt_str =PS2;636 return PS2; 663 637 } 664 638 #else 665 *prompt_str = (shell_context==0)? PS1 : PS2; 666 #endif 667 } 668 669 static int get_command(FILE * source, char *command) 670 { 671 char *prompt_str; 639 return (shell_context == 0)? PS1 : PS2; 640 #endif 641 } 642 643 #if ENABLE_FEATURE_EDITING 644 static line_input_t *line_input_state; 645 #endif 646 647 static int get_command_bufsiz(FILE * source, char *command) 648 { 649 const char *prompt_str; 672 650 673 651 if (source == NULL) { 674 652 if (local_pending_command) { 675 653 /* a command specified (-c option): return it & mark it done */ 676 strcpy(command, local_pending_command); 677 free(local_pending_command); 654 strncpy(command, local_pending_command, BUFSIZ); 678 655 local_pending_command = NULL; 679 656 return 0; … … 683 660 684 661 if (source == stdin) { 685 setup_prompt_string(&prompt_str);686 687 #if def CONFIG_FEATURE_COMMAND_EDITING662 prompt_str = setup_prompt_string(); 663 664 #if ENABLE_FEATURE_EDITING 688 665 /* 689 666 ** enable command line editing only while a command line … … 692 669 ** child processes (rob@sysgo.de) 693 670 */ 694 cmdedit_read_input(prompt_str, command);671 read_line_input(prompt_str, command, BUFSIZ, line_input_state); 695 672 return 0; 696 673 #else … … 701 678 if (!fgets(command, BUFSIZ - 2, source)) { 702 679 if (source == stdin) 703 p rintf("\n");680 puts(""); 704 681 return 1; 705 682 } … … 708 685 } 709 686 710 static char* itoa(register int i) 711 { 712 static char a[7]; /* Max 7 ints */ 713 register char *b = a + sizeof(a) - 1; 714 int sign = (i < 0); 715 716 if (sign) 717 i = -i; 718 *b = 0; 719 do 720 { 721 *--b = '0' + (i % 10); 722 i /= 10; 723 } 724 while (i); 725 if (sign) 726 *--b = '-'; 727 return b; 728 } 729 730 static char * strsep_space( char *string, int * ix) 731 { 732 char *token; 733 687 static char * strsep_space(char *string, int * ix) 688 { 734 689 /* Short circuit the trivial case */ 735 if ( 690 if (!string || ! string[*ix]) 736 691 return NULL; 737 692 738 693 /* Find the end of the token. */ 739 while (string[*ix] && !isspace(string[*ix]) ) {694 while (string[*ix] && !isspace(string[*ix]) ) { 740 695 (*ix)++; 741 696 } … … 743 698 /* Find the end of any whitespace trailing behind 744 699 * the token and let that be part of the token */ 745 while ( string[*ix] && isspace(string[*ix]) ) {700 while (string[*ix] && (isspace)(string[*ix]) ) { 746 701 (*ix)++; 747 702 } … … 752 707 } 753 708 754 token = bb_xstrndup(string, *ix); 755 756 return token; 709 return xstrndup(string, *ix); 757 710 } 758 711 759 712 static int expand_arguments(char *command) 760 713 { 761 int total_length=0, length, i, retval, ix = 0; 714 static const char out_of_space[] ALIGN1 = "out of space during expansion"; 715 716 int total_length = 0, length, i, retval, ix = 0; 762 717 expand_t expand_result; 763 718 char *tmpcmd, *cmd, *cmd_copy; 764 719 char *src, *dst, *var; 765 const char *out_of_space = "out of space during expansion";766 720 int flags = GLOB_NOCHECK 767 721 #ifdef GLOB_BRACE … … 777 731 778 732 /* Fix up escape sequences to be the Real Thing(tm) */ 779 while (command && command[ix]) {733 while (command && command[ix]) { 780 734 if (command[ix] == '\\') { 781 735 const char *tmp = command+ix+1; … … 793 747 /* We need a clean copy, so strsep can mess up the copy while 794 748 * we write stuff into the original (in a minute) */ 795 cmd = cmd_copy = bb_xstrdup(command);749 cmd = cmd_copy = xstrdup(command); 796 750 *command = '\0'; 797 751 for (ix = 0, tmpcmd = cmd; 798 (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix =0) {752 (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix = 0) { 799 753 if (*tmpcmd == '\0') 800 754 break; … … 805 759 if (retval == GLOB_NOSPACE) { 806 760 /* Mem may have been allocated... */ 807 globfree 761 globfree(&expand_result); 808 762 bb_error_msg(out_of_space); 809 763 return FALSE; … … 817 771 /* Convert from char** (one word per string) to a simple char*, 818 772 * but don't overflow command which is BUFSIZ in length */ 819 for (i =0; i < expand_result.gl_pathc; i++) {820 length =strlen(expand_result.gl_pathv[i]);773 for (i = 0; i < expand_result.gl_pathc; i++) { 774 length = strlen(expand_result.gl_pathv[i]); 821 775 if (total_length+length+1 >= BUFSIZ) { 822 776 bb_error_msg(out_of_space); … … 824 778 } 825 779 strcat(command+total_length, " "); 826 total_length +=1;780 total_length += 1; 827 781 strcat(command+total_length, expand_result.gl_pathv[i]); 828 total_length +=length;829 } 830 globfree 782 total_length += length; 783 } 784 globfree(&expand_result); 831 785 } 832 786 } … … 837 791 * wordexp can't do for us, namely $? and $! */ 838 792 src = command; 839 while ((dst = strchr(src,'$')) != NULL){793 while ((dst = strchr(src,'$')) != NULL) { 840 794 var = NULL; 841 switch (*(dst+1)) {795 switch (*(dst+1)) { 842 796 case '?': 843 797 var = itoa(last_return_code); 844 798 break; 845 799 case '!': 846 if (last_bg_pid ==-1)847 * (var)='\0';800 if (last_bg_pid == -1) 801 *var = '\0'; 848 802 else 849 803 var = itoa(last_bg_pid); … … 863 817 case '5':case '6':case '7':case '8':case '9': 864 818 { 865 int ixx =*(dst+1)-48+1;819 int ixx = *(dst+1)-48+1; 866 820 if (ixx >= argc) { 867 var ='\0';821 var = '\0'; 868 822 } else { 869 823 var = argv[ixx]; … … 876 830 /* a single character construction was found, and 877 831 * already handled in the case statement */ 878 src =dst+2;832 src = dst + 2; 879 833 } else { 880 834 /* Looks like an environment variable */ 881 835 char delim_hold; 882 int num_skip_chars =0;836 int num_skip_chars = 0; 883 837 int dstlen = strlen(dst); 884 838 /* Is this a ${foo} type variable? */ 885 if (dstlen >= 2 && *(dst+1) == '{') {886 src =strchr(dst+1, '}');887 num_skip_chars =1;839 if (dstlen >= 2 && *(dst+1) == '{') { 840 src = strchr(dst+1, '}'); 841 num_skip_chars = 1; 888 842 } else { 889 src =dst+1;890 while (isalnum(*src) || *src=='_') src++;843 src = dst + 1; 844 while ((isalnum)(*src) || *src == '_') src++; 891 845 } 892 846 if (src == NULL) { 893 847 src = dst+dstlen; 894 848 } 895 delim_hold =*src;896 *src ='\0'; /* temporary */849 delim_hold = *src; 850 *src = '\0'; /* temporary */ 897 851 var = getenv(dst + 1 + num_skip_chars); 898 *src =delim_hold;852 *src = delim_hold; 899 853 src += num_skip_chars; 900 854 } 901 855 if (var == NULL) { 902 856 /* Seems we got an un-expandable variable. So delete it. */ 903 var = "";857 var = (char*)""; 904 858 } 905 859 { … … 932 886 char *return_command = NULL; 933 887 char *src, *buf; 934 int argc_l = 0;935 int done = 0;888 int argc_l; 889 int flag; 936 890 int argv_alloced; 937 int saw_quote = 0;938 891 char quote = '\0'; 939 892 struct child_prog *prog; 940 #if def CONFIG_LASH_PIPE_N_REDIRECTS893 #if ENABLE_LASH_PIPE_N_REDIRECTS 941 894 int i; 942 895 char *chptr; … … 944 897 945 898 /* skip leading white space */ 946 while (**command_ptr && isspace(**command_ptr)) 947 (*command_ptr)++; 899 *command_ptr = skip_whitespace(*command_ptr); 948 900 949 901 /* this handles empty lines or leading '#' characters */ 950 902 if (!**command_ptr || (**command_ptr == '#')) { 951 job->num_progs =0;903 job->num_progs = 0; 952 904 return 0; 953 905 } … … 971 923 prog->is_stopped = 0; 972 924 prog->family = job; 973 #if def CONFIG_LASH_PIPE_N_REDIRECTS925 #if ENABLE_LASH_PIPE_N_REDIRECTS 974 926 prog->redirects = NULL; 975 927 #endif … … 979 931 prog->argv[0] = job->cmdbuf; 980 932 933 flag = argc_l = 0; 981 934 buf = command; 982 935 src = *command_ptr; 983 while (*src && ! done) {936 while (*src && !(flag & LASH_OPT_DONE)) { 984 937 if (quote == *src) { 985 938 quote = '\0'; … … 1002 955 *buf++ = *src; 1003 956 } else if (isspace(*src)) { 1004 if (*prog->argv[argc_l] || saw_quote) {957 if (*prog->argv[argc_l] || (flag & LASH_OPT_SAW_QUOTE)) { 1005 958 buf++, argc_l++; 1006 959 /* +1 here leaves room for the NULL which ends argv */ … … 1008 961 argv_alloced += 5; 1009 962 prog->argv = xrealloc(prog->argv, 1010 sizeof(*prog->argv) * 1011 argv_alloced); 963 sizeof(*prog->argv) * argv_alloced); 1012 964 } 1013 965 prog->argv[argc_l] = buf; 1014 saw_quote = 0;966 flag ^= LASH_OPT_SAW_QUOTE; 1015 967 } 1016 968 } else … … 1019 971 case '\'': 1020 972 quote = *src; 1021 saw_quote = 1;973 flag |= LASH_OPT_SAW_QUOTE; 1022 974 break; 1023 975 … … 1026 978 *buf++ = *src; 1027 979 else 1028 done = 1;980 flag |= LASH_OPT_DONE; 1029 981 break; 1030 982 1031 #if def CONFIG_LASH_PIPE_N_REDIRECTS983 #if ENABLE_LASH_PIPE_N_REDIRECTS 1032 984 case '>': /* redirects */ 1033 985 case '<': 1034 986 i = prog->num_redirects++; 1035 987 prog->redirects = xrealloc(prog->redirects, 1036 sizeof(*prog->redirects) * 1037 (i + 1)); 988 sizeof(*prog->redirects) * (i + 1)); 1038 989 1039 990 prog->redirects[i].fd = -1; … … 1069 1020 /* This isn't POSIX sh compliant. Oh well. */ 1070 1021 chptr = src; 1071 while (isspace(*chptr)) 1072 chptr++; 1022 chptr = skip_whitespace(chptr); 1073 1023 1074 1024 if (!*chptr) { 1075 1025 bb_error_msg("file name expected after %c", *(src-1)); 1076 1026 free_job(job); 1077 job->num_progs =0;1027 job->num_progs = 0; 1078 1028 return 1; 1079 1029 } … … 1089 1039 case '|': /* pipe */ 1090 1040 /* finish this command */ 1091 if (*prog->argv[argc_l] || saw_quote)1041 if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) 1092 1042 argc_l++; 1093 1043 if (!argc_l) { 1094 bb_error_msg("empty command in pipe"); 1095 free_job(job); 1096 job->num_progs=0; 1097 return 1; 1044 goto empty_command_in_pipe; 1098 1045 } 1099 1046 prog->argv[argc_l] = NULL; … … 1102 1049 job->num_progs++; 1103 1050 job->progs = xrealloc(job->progs, 1104 1051 sizeof(*job->progs) * job->num_progs); 1105 1052 prog = job->progs + (job->num_progs - 1); 1106 1053 prog->num_redirects = 0; … … 1115 1062 1116 1063 src++; 1117 while (*src && isspace(*src)) 1118 src++; 1064 src = skip_whitespace(src); 1119 1065 1120 1066 if (!*src) { 1067 empty_command_in_pipe: 1121 1068 bb_error_msg("empty command in pipe"); 1122 1069 free_job(job); 1123 job->num_progs =0;1070 job->num_progs = 0; 1124 1071 return 1; 1125 1072 } … … 1129 1076 #endif 1130 1077 1131 #if def CONFIG_LASH_JOB_CONTROL1078 #if ENABLE_LASH_JOB_CONTROL 1132 1079 case '&': /* background */ 1133 1080 *inbg = 1; 1081 /* fallthrough */ 1134 1082 #endif 1135 1083 case ';': /* multiple commands */ 1136 done = 1;1084 flag |= LASH_OPT_DONE; 1137 1085 return_command = *command_ptr + (src - *command_ptr) + 1; 1138 1086 break; … … 1155 1103 } 1156 1104 1157 if (*prog->argv[argc_l] || saw_quote) {1105 if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) { 1158 1106 argc_l++; 1159 1107 } … … 1165 1113 1166 1114 if (!return_command) { 1167 job->text = bb_xstrdup(*command_ptr);1115 job->text = xstrdup(*command_ptr); 1168 1116 } else { 1169 1117 /* This leaves any trailing spaces, which is a bit sloppy */ 1170 job->text = bb_xstrndup(*command_ptr, return_command - *command_ptr);1118 job->text = xstrndup(*command_ptr, return_command - *command_ptr); 1171 1119 } 1172 1120 … … 1180 1128 static int pseudo_exec(struct child_prog *child) 1181 1129 { 1182 struct built_in_command *x;1130 const struct built_in_command *x; 1183 1131 1184 1132 /* Check if the command matches any of the non-forking builtins. … … 1187 1135 * if this is one of those cases. 1188 1136 */ 1189 for (x = bltins; x->cmd; x++) { 1190 if (strcmp(child->argv[0], x->cmd) == 0 ) { 1137 /* Check if the command matches any of the forking builtins. */ 1138 for (x = bltins; x <= &VEC_LAST(bltins); x++) { 1139 if (strcmp(child->argv[0], x->cmd) == 0) { 1191 1140 _exit(x->function(child)); 1192 1141 } 1193 1142 } 1194 1143 1195 /* Check if the command matches any of the forking builtins. */1196 for (x = bltins_forking; x->cmd; x++) {1197 if (strcmp(child->argv[0], x->cmd) == 0) {1198 bb_applet_name=x->cmd;1199 _exit (x->function(child));1200 }1201 }1202 1144 1203 1145 /* Check if the command matches any busybox internal … … 1212 1154 * /bin/foo is a symlink to busybox. 1213 1155 */ 1214 1215 if (ENABLE_FEATURE_SH_STANDALONE_SHELL) { 1216 char **argv_l = child->argv; 1217 int argc_l; 1218 1219 for(argc_l=0; *argv_l; argv_l++, argc_l++); 1220 optind = 1; 1221 run_applet_by_name(child->argv[0], argc_l, child->argv); 1156 if (ENABLE_FEATURE_SH_STANDALONE) { 1157 run_applet_and_exit(child->argv[0], child->argv); 1222 1158 } 1223 1159 … … 1233 1169 { 1234 1170 struct job *thejob; 1235 struct jobset *j_list =newjob->job_list;1171 struct jobset *j_list = newjob->job_list; 1236 1172 1237 1173 /* find the ID for thejob to use */ … … 1255 1191 thejob->stopped_progs = 0; 1256 1192 1257 #if def CONFIG_LASH_JOB_CONTROL1193 #if ENABLE_LASH_JOB_CONTROL 1258 1194 if (inbg) { 1259 1195 /* we don't wait for background thejobs to return -- append it … … 1262 1198 newjob->progs[newjob->num_progs - 1].pid); 1263 1199 last_jobid = newjob->jobid; 1264 last_bg_pid =newjob->progs[newjob->num_progs - 1].pid;1200 last_bg_pid = newjob->progs[newjob->num_progs - 1].pid; 1265 1201 } else { 1266 1202 newjob->job_list->fg = thejob; … … 1279 1215 int nextin, nextout; 1280 1216 int pipefds[2]; /* pipefd[0] is for reading */ 1281 struct built_in_command *x;1217 const struct built_in_command *x; 1282 1218 struct child_prog *child; 1283 1219 1284 nextin = 0 , nextout = 1;1220 nextin = 0; 1285 1221 for (i = 0; i < newjob->num_progs; i++) { 1286 child = & (newjob->progs[i]); 1287 1222 child = &(newjob->progs[i]); 1223 1224 nextout = 1; 1288 1225 if ((i + 1) < newjob->num_progs) { 1289 if (pipe(pipefds)<0) bb_perror_msg_and_die("pipe");1226 xpipe(pipefds); 1290 1227 nextout = pipefds[1]; 1291 } else { 1292 if (outpipe[1]!=-1) { 1293 nextout = outpipe[1]; 1294 } else { 1295 nextout = 1; 1296 } 1297 } 1298 1228 } else if (outpipe[1] != -1) { 1229 nextout = outpipe[1]; 1230 } 1299 1231 1300 1232 /* Check if the command matches any non-forking builtins, … … 1305 1237 */ 1306 1238 if (newjob->num_progs == 1) { 1239 int rcode; 1240 int squirrel[] = {-1, -1, -1}; 1241 1307 1242 /* Check if the command sets an environment variable. */ 1308 1243 if (strchr(child->argv[0], '=') != NULL) { … … 1311 1246 } 1312 1247 1313 for (x = bltins; x->cmd; x++) { 1314 if (strcmp(child->argv[0], x->cmd) == 0 ) { 1315 int rcode; 1316 int squirrel[] = {-1, -1, -1}; 1248 for (x = bltins; x <= &VEC_LAST(bltins); x++) { 1249 if (strcmp(child->argv[0], x->cmd) == 0) { 1317 1250 setup_redirects(child, squirrel); 1318 1251 rcode = x->function(child); … … 1321 1254 } 1322 1255 } 1323 } 1324 1325 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__) 1326 if (!(child->pid = fork())) 1256 #if ENABLE_FEATURE_SH_STANDALONE 1257 { 1258 const struct bb_applet *a = find_applet_by_name(child->argv[i]); 1259 if (a && a->nofork) { 1260 setup_redirects(child, squirrel); 1261 rcode = run_nofork_applet(a, child->argv + i); 1262 restore_redirects(squirrel); 1263 return rcode; 1264 } 1265 } 1266 #endif 1267 } 1268 1269 #if BB_MMU 1270 child->pid = fork(); 1327 1271 #else 1328 if (!(child->pid = vfork()))1329 #endif 1330 {1272 child->pid = vfork(); 1273 #endif 1274 if (!child->pid) { 1331 1275 /* Set the handling for job control signals back to the default. */ 1332 1276 signal(SIGINT, SIG_DFL); … … 1337 1281 signal(SIGCHLD, SIG_DFL); 1338 1282 1339 // Close all open filehandles. 1340 while(close_me_list) close((long)llist_pop(&close_me_list)); 1341 1342 if (outpipe[1]!=-1) { 1283 /* Close all open filehandles. */ 1284 while (close_me_list) 1285 close((long)llist_pop(&close_me_list)); 1286 1287 if (outpipe[1] != -1) { 1343 1288 close(outpipe[0]); 1344 1289 } … … 1360 1305 pseudo_exec(child); 1361 1306 } 1362 if (outpipe[1] !=-1) {1307 if (outpipe[1] != -1) { 1363 1308 close(outpipe[1]); 1364 1309 } … … 1392 1337 int inbg = 0; 1393 1338 int status; 1394 #if def CONFIG_LASH_JOB_CONTROL1339 #if ENABLE_LASH_JOB_CONTROL 1395 1340 pid_t parent_pgrp; 1396 1341 /* save current owner of TTY so we can restore it on exit */ … … 1410 1355 1411 1356 if (!next_command) { 1412 if (get_command (input, command))1357 if (get_command_bufsiz(input, command)) 1413 1358 break; 1414 1359 next_command = command; 1415 1360 } 1416 1361 1417 if (! 1362 if (!expand_arguments(next_command)) { 1418 1363 free(command); 1419 1364 command = xzalloc(BUFSIZ); … … 1424 1369 if (!parse_command(&next_command, &newjob, &inbg) && 1425 1370 newjob.num_progs) { 1426 int pipefds[2] = { -1,-1};1427 debug_printf( 1371 int pipefds[2] = { -1, -1 }; 1372 debug_printf("job=%p fed to run_command by busy_loop()'\n", 1428 1373 &newjob); 1429 1374 run_command(&newjob, inbg, pipefds); … … 1431 1376 else { 1432 1377 free(command); 1433 command = (char *)xzalloc(BUFSIZ);1378 command = xzalloc(BUFSIZ); 1434 1379 next_command = NULL; 1435 1380 } … … 1440 1385 job_list.fg->progs[i].is_stopped == 1) i++; 1441 1386 1442 if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED) <0) {1387 if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED) < 0) { 1443 1388 if (errno != ECHILD) { 1444 bb_perror_msg_and_die("waitpid(%d)", job_list.fg->progs[i].pid);1389 bb_perror_msg_and_die("waitpid(%d)", job_list.fg->progs[i].pid); 1445 1390 } 1446 1391 } … … 1451 1396 job_list.fg->progs[i].pid = 0; 1452 1397 1453 last_return_code =WEXITSTATUS(status);1398 last_return_code = WEXITSTATUS(status); 1454 1399 1455 1400 if (!job_list.fg->running_progs) { … … 1459 1404 } 1460 1405 } 1461 #if def CONFIG_LASH_JOB_CONTROL1406 #if ENABLE_LASH_JOB_CONTROL 1462 1407 else { 1463 1408 /* the child was stopped */ … … 1483 1428 free(command); 1484 1429 1485 #if def CONFIG_LASH_JOB_CONTROL1430 #if ENABLE_LASH_JOB_CONTROL 1486 1431 /* return controlling TTY back to parent process group before exiting */ 1487 1432 if (tcsetpgrp(shell_terminal, parent_pgrp) && errno != ENOTTY) … … 1496 1441 } 1497 1442 1498 #if def CONFIG_FEATURE_CLEAN_UP1443 #if ENABLE_FEATURE_CLEAN_UP 1499 1444 static void free_memory(void) 1500 1445 { 1501 if (cwd && cwd!=bb_msg_unknown) { 1502 free((char*)cwd); 1503 } 1504 if (local_pending_command) 1505 free(local_pending_command); 1446 free(cwd); 1506 1447 1507 1448 if (job_list.fg && !job_list.fg->running_progs) { … … 1513 1454 #endif 1514 1455 1515 #if def CONFIG_LASH_JOB_CONTROL1456 #if ENABLE_LASH_JOB_CONTROL 1516 1457 /* Make sure we have a controlling tty. If we get started under a job 1517 1458 * aware app (like bash for example), make sure we are now in charge so … … 1523 1464 1524 1465 /* Loop until we are in the foreground. */ 1525 while ((status = tcgetpgrp (shell_terminal)) >= 0) { 1526 if (status == (shell_pgrp = getpgrp ())) { 1466 while ((status = tcgetpgrp(shell_terminal)) >= 0) { 1467 shell_pgrp = getpgrp(); 1468 if (status == shell_pgrp) { 1527 1469 break; 1528 1470 } 1529 kill 1471 kill(- shell_pgrp, SIGTTIN); 1530 1472 } 1531 1473 … … 1540 1482 /* Put ourselves in our own process group. */ 1541 1483 setsid(); 1542 shell_pgrp = getpid 1484 shell_pgrp = getpid(); 1543 1485 setpgid(shell_pgrp, shell_pgrp); 1544 1486 … … 1552 1494 #endif 1553 1495 1496 int lash_main(int argc_l, char **argv_l); 1554 1497 int lash_main(int argc_l, char **argv_l) 1555 1498 { 1556 int opt, interactive=FALSE;1499 unsigned opt; 1557 1500 FILE *input = stdin; 1558 1501 argc = argc_l; 1559 1502 argv = argv_l; 1560 1503 1504 #if ENABLE_FEATURE_EDITING 1505 line_input_state = new_line_input_t(FOR_SHELL); 1506 #endif 1507 1561 1508 /* These variables need re-initializing when recursing */ 1562 1509 last_jobid = 0; 1563 local_pending_command = NULL;1564 1510 close_me_list = NULL; 1565 1511 job_list.head = NULL; 1566 1512 job_list.fg = NULL; 1567 last_return_code =1;1513 last_return_code = 1; 1568 1514 1569 1515 if (argv[0] && argv[0][0] == '-') { … … 1574 1520 /* Now run the file */ 1575 1521 busy_loop(prof_input); 1576 fclose (prof_input);1522 fclose_if_not_stdin(prof_input); 1577 1523 llist_pop(&close_me_list); 1578 1524 } 1579 1525 } 1580 1526 1581 while ((opt = getopt(argc_l, argv_l, "cxi")) > 0) { 1582 switch (opt) { 1583 case 'c': 1584 input = NULL; 1585 if (local_pending_command != 0) 1586 bb_error_msg_and_die("multiple -c arguments"); 1587 local_pending_command = bb_xstrdup(argv[optind]); 1588 optind++; 1589 argv = argv+optind; 1590 break; 1591 case 'i': 1592 interactive++; 1593 break; 1594 default: 1595 bb_show_usage(); 1596 } 1527 opt = getopt32(argv_l, "+ic:", &local_pending_command); 1528 #define LASH_OPT_i (1<<0) 1529 #define LASH_OPT_c (1<<1) 1530 if (opt & LASH_OPT_c) { 1531 input = NULL; 1532 optind++; 1533 argv += optind; 1597 1534 } 1598 1535 /* A shell is interactive if the `-i' flag was given, or if all of … … 1603 1540 * standard output is a terminal 1604 1541 * Refer to Posix.2, the description of the `sh' utility. */ 1605 if (argv[optind] ==NULL && input==stdin &&1606 isatty(STDIN_FILENO) && isatty(STDOUT_FILENO))1607 {1608 interactive++;1542 if (argv[optind] == NULL && input == stdin 1543 && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) 1544 ) { 1545 opt |= LASH_OPT_i; 1609 1546 } 1610 1547 setup_job_control(); 1611 if ( interactive) {1548 if (opt & LASH_OPT_i) { 1612 1549 /* Looks like they want an interactive shell */ 1613 1550 if (!ENABLE_FEATURE_SH_EXTRA_QUIET) { 1614 printf( "\n\n%s Built-in shell (lash)\n", BB_BANNER); 1615 printf( "Enter 'help' for a list of built-in commands.\n\n"); 1551 printf("\n\n%s built-in shell (lash)\n" 1552 "Enter 'help' for a list of built-in commands.\n\n", 1553 bb_banner); 1616 1554 } 1617 1555 } else if (!local_pending_command && argv[optind]) { 1618 1556 //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]); 1619 input = bb_xfopen(argv[optind], "r");1557 input = xfopen(argv[optind], "r"); 1620 1558 /* be lazy, never mark this closed */ 1621 1559 llist_add_to(&close_me_list, (void *)(long)fileno(input)); … … 1623 1561 1624 1562 /* initialize the cwd -- this is never freed...*/ 1625 cwd = xgetcwd(0); 1626 if (!cwd) 1627 cwd = bb_msg_unknown; 1563 update_cwd(); 1628 1564 1629 1565 if (ENABLE_FEATURE_CLEAN_UP) atexit(free_memory); 1630 1566 1631 if (ENABLE_FEATURE_ COMMAND_EDITING) cmdedit_set_initial_prompt();1567 if (ENABLE_FEATURE_EDITING) cmdedit_set_initial_prompt(); 1632 1568 else PS1 = NULL; 1633 1569 1634 return (busy_loop(input));1635 } 1570 return busy_loop(input); 1571 }
Note:
See TracChangeset
for help on using the changeset viewer.