diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/lash.c | 126 |
1 files changed, 54 insertions, 72 deletions
diff --git a/shell/lash.c b/shell/lash.c index eae949e18..fd6bea177 100644 --- a/shell/lash.c +++ b/shell/lash.c | |||
@@ -54,6 +54,9 @@ enum { | |||
54 | ELSE_EXP_CONTEXT = 0x10 | 54 | ELSE_EXP_CONTEXT = 0x10 |
55 | }; | 55 | }; |
56 | 56 | ||
57 | #define LASH_OPT_DONE (1) | ||
58 | #define LASH_OPT_SAW_QUOTE (2) | ||
59 | |||
57 | #ifdef CONFIG_LASH_PIPE_N_REDIRECTS | 60 | #ifdef CONFIG_LASH_PIPE_N_REDIRECTS |
58 | struct redir_struct { | 61 | struct redir_struct { |
59 | enum redir_type type; /* type of redirection */ | 62 | enum redir_type type; /* type of redirection */ |
@@ -154,7 +157,7 @@ static int shell_context; /* Type prompt trigger (PS1 or PS2) */ | |||
154 | 157 | ||
155 | /* Globals that are static to this file */ | 158 | /* Globals that are static to this file */ |
156 | static const char *cwd; | 159 | static const char *cwd; |
157 | static char *local_pending_command = NULL; | 160 | static char *local_pending_command; |
158 | static struct jobset job_list = { NULL, NULL }; | 161 | static struct jobset job_list = { NULL, NULL }; |
159 | static int argc; | 162 | static int argc; |
160 | static char **argv; | 163 | static char **argv; |
@@ -176,7 +179,7 @@ static inline void debug_printf(const char *format, ...) | |||
176 | va_end(args); | 179 | va_end(args); |
177 | } | 180 | } |
178 | #else | 181 | #else |
179 | static inline void debug_printf(const char *format, ...) { } | 182 | static inline void debug_printf(const char ATTRIBUTE_UNUSED *format, ...) { } |
180 | #endif | 183 | #endif |
181 | 184 | ||
182 | /* | 185 | /* |
@@ -304,12 +307,12 @@ static int builtin_fg_bg(struct child_prog *child) | |||
304 | } | 307 | } |
305 | 308 | ||
306 | /* built-in 'help' handler */ | 309 | /* built-in 'help' handler */ |
307 | static int builtin_help(struct child_prog *dummy) | 310 | static int builtin_help(struct child_prog ATTRIBUTE_UNUSED *dummy) |
308 | { | 311 | { |
309 | struct built_in_command *x; | 312 | struct built_in_command *x; |
310 | 313 | ||
311 | printf("\nBuilt-in commands:\n"); | 314 | printf("\nBuilt-in commands:\n" |
312 | printf("-------------------\n"); | 315 | "-------------------\n"); |
313 | for (x = bltins; x->cmd; x++) { | 316 | for (x = bltins; x->cmd; x++) { |
314 | if (x->descr==NULL) | 317 | if (x->descr==NULL) |
315 | continue; | 318 | continue; |
@@ -320,7 +323,7 @@ static int builtin_help(struct child_prog *dummy) | |||
320 | continue; | 323 | continue; |
321 | printf("%s\t%s\n", x->cmd, x->descr); | 324 | printf("%s\t%s\n", x->cmd, x->descr); |
322 | } | 325 | } |
323 | printf("\n\n"); | 326 | putchar('\n'); |
324 | return EXIT_SUCCESS; | 327 | return EXIT_SUCCESS; |
325 | } | 328 | } |
326 | 329 | ||
@@ -343,7 +346,7 @@ static int builtin_jobs(struct child_prog *child) | |||
343 | 346 | ||
344 | 347 | ||
345 | /* built-in 'pwd' handler */ | 348 | /* built-in 'pwd' handler */ |
346 | static int builtin_pwd(struct child_prog *dummy) | 349 | static int builtin_pwd(struct child_prog ATTRIBUTE_UNUSED *dummy) |
347 | { | 350 | { |
348 | cwd = xgetcwd((char *)cwd); | 351 | cwd = xgetcwd((char *)cwd); |
349 | if (!cwd) | 352 | if (!cwd) |
@@ -386,7 +389,7 @@ static int builtin_export(struct child_prog *child) | |||
386 | /* built-in 'read VAR' handler */ | 389 | /* built-in 'read VAR' handler */ |
387 | static int builtin_read(struct child_prog *child) | 390 | static int builtin_read(struct child_prog *child) |
388 | { | 391 | { |
389 | int res = 0, len, newlen; | 392 | int res = 0, len; |
390 | char *s; | 393 | char *s; |
391 | char string[MAX_READ]; | 394 | char string[MAX_READ]; |
392 | 395 | ||
@@ -397,16 +400,16 @@ static int builtin_read(struct child_prog *child) | |||
397 | string[len++] = '='; | 400 | string[len++] = '='; |
398 | string[len] = '\0'; | 401 | string[len] = '\0'; |
399 | fgets(&string[len], sizeof(string) - len, stdin); /* read string */ | 402 | fgets(&string[len], sizeof(string) - len, stdin); /* read string */ |
400 | newlen = strlen(string); | 403 | res = strlen(string); |
401 | if(newlen > len) | 404 | if (res > len) |
402 | string[--newlen] = '\0'; /* chomp trailing newline */ | 405 | string[--res] = '\0'; /* chomp trailing newline */ |
403 | /* | 406 | /* |
404 | ** string should now contain "VAR=<value>" | 407 | ** string should now contain "VAR=<value>" |
405 | ** copy it (putenv() won't do that, so we must make sure | 408 | ** copy it (putenv() won't do that, so we must make sure |
406 | ** the string resides in a static buffer!) | 409 | ** the string resides in a static buffer!) |
407 | */ | 410 | */ |
408 | res = -1; | 411 | res = -1; |
409 | if((s = strdup(string))) | 412 | if ((s = strdup(string))) |
410 | res = putenv(s); | 413 | res = putenv(s); |
411 | if (res) | 414 | if (res) |
412 | bb_perror_msg("read"); | 415 | bb_perror_msg("read"); |
@@ -423,12 +426,8 @@ static int builtin_source(struct child_prog *child) | |||
423 | FILE *input; | 426 | FILE *input; |
424 | int status; | 427 | int status; |
425 | 428 | ||
426 | if (child->argv[1] == NULL) | 429 | input = bb_wfopen(child->argv[1], "r"); |
427 | return EXIT_FAILURE; | ||
428 | |||
429 | input = fopen(child->argv[1], "r"); | ||
430 | if (!input) { | 430 | if (!input) { |
431 | printf( "Couldn't open file '%s'\n", child->argv[1]); | ||
432 | return EXIT_FAILURE; | 431 | return EXIT_FAILURE; |
433 | } | 432 | } |
434 | 433 | ||
@@ -635,7 +634,7 @@ static inline void setup_prompt_string(char **prompt_str) | |||
635 | if (shell_context == 0) { | 634 | if (shell_context == 0) { |
636 | free(PS1); | 635 | free(PS1); |
637 | PS1=xmalloc(strlen(cwd)+4); | 636 | PS1=xmalloc(strlen(cwd)+4); |
638 | sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); | 637 | sprintf(PS1, "%s %c ", cwd, ( geteuid() != 0 ) ? '$': '#'); |
639 | *prompt_str = PS1; | 638 | *prompt_str = PS1; |
640 | } else { | 639 | } else { |
641 | *prompt_str = PS2; | 640 | *prompt_str = PS2; |
@@ -688,20 +687,18 @@ static int get_command(FILE * source, char *command) | |||
688 | 687 | ||
689 | static char * strsep_space( char *string, int * ix) | 688 | static char * strsep_space( char *string, int * ix) |
690 | { | 689 | { |
691 | char *token; | ||
692 | |||
693 | /* Short circuit the trivial case */ | 690 | /* Short circuit the trivial case */ |
694 | if ( !string || ! string[*ix]) | 691 | if ( !string || ! string[*ix]) |
695 | return NULL; | 692 | return NULL; |
696 | 693 | ||
697 | /* Find the end of the token. */ | 694 | /* Find the end of the token. */ |
698 | while( string[*ix] && !isspace(string[*ix]) ) { | 695 | while (string[*ix] && !isspace(string[*ix]) ) { |
699 | (*ix)++; | 696 | (*ix)++; |
700 | } | 697 | } |
701 | 698 | ||
702 | /* Find the end of any whitespace trailing behind | 699 | /* Find the end of any whitespace trailing behind |
703 | * the token and let that be part of the token */ | 700 | * the token and let that be part of the token */ |
704 | while( string[*ix] && isspace(string[*ix]) ) { | 701 | while (string[*ix] && (isspace)(string[*ix]) ) { |
705 | (*ix)++; | 702 | (*ix)++; |
706 | } | 703 | } |
707 | 704 | ||
@@ -710,9 +707,7 @@ static char * strsep_space( char *string, int * ix) | |||
710 | return NULL; | 707 | return NULL; |
711 | } | 708 | } |
712 | 709 | ||
713 | token = xstrndup(string, *ix); | 710 | return xstrndup(string, *ix); |
714 | |||
715 | return token; | ||
716 | } | 711 | } |
717 | 712 | ||
718 | static int expand_arguments(char *command) | 713 | static int expand_arguments(char *command) |
@@ -721,7 +716,7 @@ static int expand_arguments(char *command) | |||
721 | expand_t expand_result; | 716 | expand_t expand_result; |
722 | char *tmpcmd, *cmd, *cmd_copy; | 717 | char *tmpcmd, *cmd, *cmd_copy; |
723 | char *src, *dst, *var; | 718 | char *src, *dst, *var; |
724 | const char *out_of_space = "out of space during expansion"; | 719 | const char * const out_of_space = "out of space during expansion"; |
725 | int flags = GLOB_NOCHECK | 720 | int flags = GLOB_NOCHECK |
726 | #ifdef GLOB_BRACE | 721 | #ifdef GLOB_BRACE |
727 | | GLOB_BRACE | 722 | | GLOB_BRACE |
@@ -846,7 +841,7 @@ static int expand_arguments(char *command) | |||
846 | num_skip_chars=1; | 841 | num_skip_chars=1; |
847 | } else { | 842 | } else { |
848 | src=dst+1; | 843 | src=dst+1; |
849 | while(isalnum(*src) || *src=='_') src++; | 844 | while((isalnum)(*src) || *src=='_') src++; |
850 | } | 845 | } |
851 | if (src == NULL) { | 846 | if (src == NULL) { |
852 | src = dst+dstlen; | 847 | src = dst+dstlen; |
@@ -890,10 +885,9 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg) | |||
890 | char *command; | 885 | char *command; |
891 | char *return_command = NULL; | 886 | char *return_command = NULL; |
892 | char *src, *buf; | 887 | char *src, *buf; |
893 | int argc_l = 0; | 888 | int argc_l; |
894 | int done = 0; | 889 | int flag; |
895 | int argv_alloced; | 890 | int argv_alloced; |
896 | int saw_quote = 0; | ||
897 | char quote = '\0'; | 891 | char quote = '\0'; |
898 | struct child_prog *prog; | 892 | struct child_prog *prog; |
899 | #ifdef CONFIG_LASH_PIPE_N_REDIRECTS | 893 | #ifdef CONFIG_LASH_PIPE_N_REDIRECTS |
@@ -902,8 +896,7 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg) | |||
902 | #endif | 896 | #endif |
903 | 897 | ||
904 | /* skip leading white space */ | 898 | /* skip leading white space */ |
905 | while (**command_ptr && isspace(**command_ptr)) | 899 | *command_ptr = skip_whitespace(*command_ptr); |
906 | (*command_ptr)++; | ||
907 | 900 | ||
908 | /* this handles empty lines or leading '#' characters */ | 901 | /* this handles empty lines or leading '#' characters */ |
909 | if (!**command_ptr || (**command_ptr == '#')) { | 902 | if (!**command_ptr || (**command_ptr == '#')) { |
@@ -937,9 +930,10 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg) | |||
937 | prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced); | 930 | prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced); |
938 | prog->argv[0] = job->cmdbuf; | 931 | prog->argv[0] = job->cmdbuf; |
939 | 932 | ||
933 | flag = argc_l = 0; | ||
940 | buf = command; | 934 | buf = command; |
941 | src = *command_ptr; | 935 | src = *command_ptr; |
942 | while (*src && !done) { | 936 | while (*src && !(flag & LASH_OPT_DONE)) { |
943 | if (quote == *src) { | 937 | if (quote == *src) { |
944 | quote = '\0'; | 938 | quote = '\0'; |
945 | } else if (quote) { | 939 | } else if (quote) { |
@@ -960,7 +954,7 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg) | |||
960 | *src == ']') *buf++ = '\\'; | 954 | *src == ']') *buf++ = '\\'; |
961 | *buf++ = *src; | 955 | *buf++ = *src; |
962 | } else if (isspace(*src)) { | 956 | } else if (isspace(*src)) { |
963 | if (*prog->argv[argc_l] || saw_quote) { | 957 | if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) { |
964 | buf++, argc_l++; | 958 | buf++, argc_l++; |
965 | /* +1 here leaves room for the NULL which ends argv */ | 959 | /* +1 here leaves room for the NULL which ends argv */ |
966 | if ((argc_l + 1) == argv_alloced) { | 960 | if ((argc_l + 1) == argv_alloced) { |
@@ -970,21 +964,21 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg) | |||
970 | argv_alloced); | 964 | argv_alloced); |
971 | } | 965 | } |
972 | prog->argv[argc_l] = buf; | 966 | prog->argv[argc_l] = buf; |
973 | saw_quote = 0; | 967 | flag ^= LASH_OPT_SAW_QUOTE; |
974 | } | 968 | } |
975 | } else | 969 | } else |
976 | switch (*src) { | 970 | switch (*src) { |
977 | case '"': | 971 | case '"': |
978 | case '\'': | 972 | case '\'': |
979 | quote = *src; | 973 | quote = *src; |
980 | saw_quote = 1; | 974 | flag |= LASH_OPT_SAW_QUOTE; |
981 | break; | 975 | break; |
982 | 976 | ||
983 | case '#': /* comment */ | 977 | case '#': /* comment */ |
984 | if (*(src-1)== '$') | 978 | if (*(src-1)== '$') |
985 | *buf++ = *src; | 979 | *buf++ = *src; |
986 | else | 980 | else |
987 | done = 1; | 981 | flag |= LASH_OPT_DONE; |
988 | break; | 982 | break; |
989 | 983 | ||
990 | #ifdef CONFIG_LASH_PIPE_N_REDIRECTS | 984 | #ifdef CONFIG_LASH_PIPE_N_REDIRECTS |
@@ -1027,8 +1021,7 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg) | |||
1027 | 1021 | ||
1028 | /* This isn't POSIX sh compliant. Oh well. */ | 1022 | /* This isn't POSIX sh compliant. Oh well. */ |
1029 | chptr = src; | 1023 | chptr = src; |
1030 | while (isspace(*chptr)) | 1024 | chptr = skip_whitespace(chptr); |
1031 | chptr++; | ||
1032 | 1025 | ||
1033 | if (!*chptr) { | 1026 | if (!*chptr) { |
1034 | bb_error_msg("file name expected after %c", *(src-1)); | 1027 | bb_error_msg("file name expected after %c", *(src-1)); |
@@ -1047,13 +1040,10 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg) | |||
1047 | 1040 | ||
1048 | case '|': /* pipe */ | 1041 | case '|': /* pipe */ |
1049 | /* finish this command */ | 1042 | /* finish this command */ |
1050 | if (*prog->argv[argc_l] || saw_quote) | 1043 | if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) |
1051 | argc_l++; | 1044 | argc_l++; |
1052 | if (!argc_l) { | 1045 | if (!argc_l) { |
1053 | bb_error_msg("empty command in pipe"); | 1046 | goto empty_command_in_pipe; |
1054 | free_job(job); | ||
1055 | job->num_progs=0; | ||
1056 | return 1; | ||
1057 | } | 1047 | } |
1058 | prog->argv[argc_l] = NULL; | 1048 | prog->argv[argc_l] = NULL; |
1059 | 1049 | ||
@@ -1073,10 +1063,10 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg) | |||
1073 | prog->argv[0] = ++buf; | 1063 | prog->argv[0] = ++buf; |
1074 | 1064 | ||
1075 | src++; | 1065 | src++; |
1076 | while (*src && isspace(*src)) | 1066 | src = skip_whitespace(src); |
1077 | src++; | ||
1078 | 1067 | ||
1079 | if (!*src) { | 1068 | if (!*src) { |
1069 | empty_command_in_pipe: | ||
1080 | bb_error_msg("empty command in pipe"); | 1070 | bb_error_msg("empty command in pipe"); |
1081 | free_job(job); | 1071 | free_job(job); |
1082 | job->num_progs=0; | 1072 | job->num_progs=0; |
@@ -1090,9 +1080,10 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg) | |||
1090 | #ifdef CONFIG_LASH_JOB_CONTROL | 1080 | #ifdef CONFIG_LASH_JOB_CONTROL |
1091 | case '&': /* background */ | 1081 | case '&': /* background */ |
1092 | *inbg = 1; | 1082 | *inbg = 1; |
1083 | /* fallthrough */ | ||
1093 | #endif | 1084 | #endif |
1094 | case ';': /* multiple commands */ | 1085 | case ';': /* multiple commands */ |
1095 | done = 1; | 1086 | flag |= LASH_OPT_DONE; |
1096 | return_command = *command_ptr + (src - *command_ptr) + 1; | 1087 | return_command = *command_ptr + (src - *command_ptr) + 1; |
1097 | break; | 1088 | break; |
1098 | 1089 | ||
@@ -1113,7 +1104,7 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg) | |||
1113 | src++; | 1104 | src++; |
1114 | } | 1105 | } |
1115 | 1106 | ||
1116 | if (*prog->argv[argc_l] || saw_quote) { | 1107 | if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) { |
1117 | argc_l++; | 1108 | argc_l++; |
1118 | } | 1109 | } |
1119 | if (!argc_l) { | 1110 | if (!argc_l) { |
@@ -1295,7 +1286,7 @@ static int run_command(struct job *newjob, int inbg, int outpipe[2]) | |||
1295 | signal(SIGTTOU, SIG_DFL); | 1286 | signal(SIGTTOU, SIG_DFL); |
1296 | signal(SIGCHLD, SIG_DFL); | 1287 | signal(SIGCHLD, SIG_DFL); |
1297 | 1288 | ||
1298 | // Close all open filehandles. | 1289 | /* Close all open filehandles. */ |
1299 | while(close_me_list) close((long)llist_pop(&close_me_list)); | 1290 | while(close_me_list) close((long)llist_pop(&close_me_list)); |
1300 | 1291 | ||
1301 | if (outpipe[1]!=-1) { | 1292 | if (outpipe[1]!=-1) { |
@@ -1512,14 +1503,13 @@ static inline void setup_job_control(void) | |||
1512 | 1503 | ||
1513 | int lash_main(int argc_l, char **argv_l) | 1504 | int lash_main(int argc_l, char **argv_l) |
1514 | { | 1505 | { |
1515 | int opt, interactive=FALSE; | 1506 | unsigned long opt; |
1516 | FILE *input = stdin; | 1507 | FILE *input = stdin; |
1517 | argc = argc_l; | 1508 | argc = argc_l; |
1518 | argv = argv_l; | 1509 | argv = argv_l; |
1519 | 1510 | ||
1520 | /* These variables need re-initializing when recursing */ | 1511 | /* These variables need re-initializing when recursing */ |
1521 | last_jobid = 0; | 1512 | last_jobid = 0; |
1522 | local_pending_command = NULL; | ||
1523 | close_me_list = NULL; | 1513 | close_me_list = NULL; |
1524 | job_list.head = NULL; | 1514 | job_list.head = NULL; |
1525 | job_list.fg = NULL; | 1515 | job_list.fg = NULL; |
@@ -1532,27 +1522,18 @@ int lash_main(int argc_l, char **argv_l) | |||
1532 | llist_add_to(&close_me_list, (void *)(long)fileno(prof_input)); | 1522 | llist_add_to(&close_me_list, (void *)(long)fileno(prof_input)); |
1533 | /* Now run the file */ | 1523 | /* Now run the file */ |
1534 | busy_loop(prof_input); | 1524 | busy_loop(prof_input); |
1535 | fclose(prof_input); | 1525 | bb_fclose_nonstdin(prof_input); |
1536 | llist_pop(&close_me_list); | 1526 | llist_pop(&close_me_list); |
1537 | } | 1527 | } |
1538 | } | 1528 | } |
1539 | 1529 | ||
1540 | while ((opt = getopt(argc_l, argv_l, "cxi")) > 0) { | 1530 | opt = bb_getopt_ulflags(argc_l, argv_l, "+ic:", &local_pending_command); |
1541 | switch (opt) { | 1531 | #define LASH_OPT_i (1<<0) |
1542 | case 'c': | 1532 | #define LASH_OPT_c (1<<2) |
1543 | input = NULL; | 1533 | if (opt & LASH_OPT_c) { |
1544 | if (local_pending_command != 0) | 1534 | input = NULL; |
1545 | bb_error_msg_and_die("multiple -c arguments"); | 1535 | optind++; |
1546 | local_pending_command = xstrdup(argv[optind]); | 1536 | argv += optind; |
1547 | optind++; | ||
1548 | argv = argv+optind; | ||
1549 | break; | ||
1550 | case 'i': | ||
1551 | interactive++; | ||
1552 | break; | ||
1553 | default: | ||
1554 | bb_show_usage(); | ||
1555 | } | ||
1556 | } | 1537 | } |
1557 | /* A shell is interactive if the `-i' flag was given, or if all of | 1538 | /* A shell is interactive if the `-i' flag was given, or if all of |
1558 | * the following conditions are met: | 1539 | * the following conditions are met: |
@@ -1564,14 +1545,15 @@ int lash_main(int argc_l, char **argv_l) | |||
1564 | if (argv[optind]==NULL && input==stdin && | 1545 | if (argv[optind]==NULL && input==stdin && |
1565 | isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) | 1546 | isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) |
1566 | { | 1547 | { |
1567 | interactive++; | 1548 | opt |= LASH_OPT_i; |
1568 | } | 1549 | } |
1569 | setup_job_control(); | 1550 | setup_job_control(); |
1570 | if (interactive) { | 1551 | if (opt & LASH_OPT_i) { |
1571 | /* Looks like they want an interactive shell */ | 1552 | /* Looks like they want an interactive shell */ |
1572 | if (!ENABLE_FEATURE_SH_EXTRA_QUIET) { | 1553 | if (!ENABLE_FEATURE_SH_EXTRA_QUIET) { |
1573 | printf( "\n\n%s Built-in shell (lash)\n", BB_BANNER); | 1554 | printf("\n\n%s Built-in shell (lash)\n" |
1574 | printf( "Enter 'help' for a list of built-in commands.\n\n"); | 1555 | "Enter 'help' for a list of built-in commands.\n\n", |
1556 | BB_BANNER); | ||
1575 | } | 1557 | } |
1576 | } else if (!local_pending_command && argv[optind]) { | 1558 | } else if (!local_pending_command && argv[optind]) { |
1577 | //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]); | 1559 | //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]); |