aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
Diffstat (limited to 'shell')
-rw-r--r--shell/lash.c126
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
58struct redir_struct { 61struct 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 */
156static const char *cwd; 159static const char *cwd;
157static char *local_pending_command = NULL; 160static char *local_pending_command;
158static struct jobset job_list = { NULL, NULL }; 161static struct jobset job_list = { NULL, NULL };
159static int argc; 162static int argc;
160static char **argv; 163static 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
179static inline void debug_printf(const char *format, ...) { } 182static 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 */
307static int builtin_help(struct child_prog *dummy) 310static 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 */
346static int builtin_pwd(struct child_prog *dummy) 349static 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 */
387static int builtin_read(struct child_prog *child) 390static 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
689static char * strsep_space( char *string, int * ix) 688static 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
718static int expand_arguments(char *command) 713static 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) {
1069empty_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
1513int lash_main(int argc_l, char **argv_l) 1504int 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]);