diff options
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/lash.c | 79 |
1 files changed, 67 insertions, 12 deletions
diff --git a/shell/lash.c b/shell/lash.c index 785e9cc3f..2d6bfb526 100644 --- a/shell/lash.c +++ b/shell/lash.c | |||
| @@ -41,7 +41,7 @@ | |||
| 41 | #include "cmdedit.h" | 41 | #include "cmdedit.h" |
| 42 | #endif | 42 | #endif |
| 43 | 43 | ||
| 44 | 44 | #define MAX_READ 128 /* size of input buffer for `read' builtin */ | |
| 45 | #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" | 45 | #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" |
| 46 | 46 | ||
| 47 | 47 | ||
| @@ -100,6 +100,7 @@ static int shell_pwd(struct job *dummy, struct jobSet *junk); | |||
| 100 | static int shell_export(struct job *cmd, struct jobSet *junk); | 100 | static int shell_export(struct job *cmd, struct jobSet *junk); |
| 101 | static int shell_source(struct job *cmd, struct jobSet *jobList); | 101 | static int shell_source(struct job *cmd, struct jobSet *jobList); |
| 102 | static int shell_unset(struct job *cmd, struct jobSet *junk); | 102 | static int shell_unset(struct job *cmd, struct jobSet *junk); |
| 103 | static int shell_read(struct job *cmd, struct jobSet *junk); | ||
| 103 | 104 | ||
| 104 | static void checkJobs(struct jobSet *jobList); | 105 | static void checkJobs(struct jobSet *jobList); |
| 105 | static int getCommand(FILE * source, char *command); | 106 | static int getCommand(FILE * source, char *command); |
| @@ -118,6 +119,7 @@ static struct builtInCommand bltins[] = { | |||
| 118 | {"jobs", "Lists the active jobs", "jobs", shell_jobs}, | 119 | {"jobs", "Lists the active jobs", "jobs", shell_jobs}, |
| 119 | {"export", "Set environment variable", "export [VAR=value]", shell_export}, | 120 | {"export", "Set environment variable", "export [VAR=value]", shell_export}, |
| 120 | {"unset", "Unset environment variable", "unset VAR", shell_unset}, | 121 | {"unset", "Unset environment variable", "unset VAR", shell_unset}, |
| 122 | {"read", "Input environment variable", "read [VAR]", shell_read}, | ||
| 121 | {NULL, NULL, NULL, NULL} | 123 | {NULL, NULL, NULL, NULL} |
| 122 | }; | 124 | }; |
| 123 | 125 | ||
| @@ -138,8 +140,8 @@ static const char shell_usage[] = | |||
| 138 | #endif | 140 | #endif |
| 139 | ; | 141 | ; |
| 140 | 142 | ||
| 141 | static char cwd[1024]; | ||
| 142 | static char *prompt = "# "; | 143 | static char *prompt = "# "; |
| 144 | static char *cwd = NULL; | ||
| 143 | static char *local_pending_command = NULL; | 145 | static char *local_pending_command = NULL; |
| 144 | 146 | ||
| 145 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 147 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
| @@ -300,6 +302,40 @@ static int shell_export(struct job *cmd, struct jobSet *junk) | |||
| 300 | return (res); | 302 | return (res); |
| 301 | } | 303 | } |
| 302 | 304 | ||
| 305 | /* built-in 'read VAR' handler */ | ||
| 306 | static int shell_read(struct job *cmd, struct jobSet *junk) | ||
| 307 | { | ||
| 308 | int res = 0, len, newlen; | ||
| 309 | char *s; | ||
| 310 | char string[MAX_READ]; | ||
| 311 | |||
| 312 | if (cmd->progs[0].argv[1]) { | ||
| 313 | /* argument (VAR) given: put "VAR=" into buffer */ | ||
| 314 | strcpy(string, cmd->progs[0].argv[1]); | ||
| 315 | len = strlen(string); | ||
| 316 | string[len++] = '='; | ||
| 317 | string[len] = '\0'; | ||
| 318 | fgets(&string[len], sizeof(string) - len, stdin); /* read string */ | ||
| 319 | newlen = strlen(string); | ||
| 320 | if(newlen > len) | ||
| 321 | string[--newlen] = '\0'; /* chomp trailing newline */ | ||
| 322 | /* | ||
| 323 | ** string should now contain "VAR=<value>" | ||
| 324 | ** copy it (putenv() won't do that, so we must make sure | ||
| 325 | ** the string resides in a static buffer!) | ||
| 326 | */ | ||
| 327 | res = -1; | ||
| 328 | if((s = strdup(string))) | ||
| 329 | res = putenv(s); | ||
| 330 | if (res) | ||
| 331 | fprintf(stdout, "read: %s\n", strerror(errno)); | ||
| 332 | } | ||
| 333 | else | ||
| 334 | fgets(string, sizeof(string), stdin); | ||
| 335 | |||
| 336 | return (res); | ||
| 337 | } | ||
| 338 | |||
| 303 | /* Built-in '.' handler (read-in and execute commands from file) */ | 339 | /* Built-in '.' handler (read-in and execute commands from file) */ |
| 304 | static int shell_source(struct job *cmd, struct jobSet *junk) | 340 | static int shell_source(struct job *cmd, struct jobSet *junk) |
| 305 | { | 341 | { |
| @@ -461,7 +497,7 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr, | |||
| 461 | int rc; | 497 | int rc; |
| 462 | int flags; | 498 | int flags; |
| 463 | int i; | 499 | int i; |
| 464 | char *src, *dst; | 500 | char *src, *dst, *var; |
| 465 | 501 | ||
| 466 | if (argc > 1) { /* cmd->globResult is already initialized */ | 502 | if (argc > 1) { /* cmd->globResult is already initialized */ |
| 467 | flags = GLOB_APPEND; | 503 | flags = GLOB_APPEND; |
| @@ -471,6 +507,9 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr, | |||
| 471 | flags = 0; | 507 | flags = 0; |
| 472 | i = 0; | 508 | i = 0; |
| 473 | } | 509 | } |
| 510 | /* do shell variable substitution */ | ||
| 511 | if(*prog->argv[argc - 1] == '$' && (var = getenv(prog->argv[argc - 1] + 1))) | ||
| 512 | prog->argv[argc - 1] = var; | ||
| 474 | 513 | ||
| 475 | rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult); | 514 | rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult); |
| 476 | if (rc == GLOB_NOSPACE) { | 515 | if (rc == GLOB_NOSPACE) { |
| @@ -535,12 +574,13 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg) | |||
| 535 | job->progs = malloc(sizeof(*job->progs)); | 574 | job->progs = malloc(sizeof(*job->progs)); |
| 536 | 575 | ||
| 537 | /* We set the argv elements to point inside of this string. The | 576 | /* We set the argv elements to point inside of this string. The |
| 538 | memory is freed by freeJob(). | 577 | memory is freed by freeJob(). Allocate twice the original |
| 578 | length in case we need to quote every single character. | ||
| 539 | 579 | ||
| 540 | Getting clean memory relieves us of the task of NULL | 580 | Getting clean memory relieves us of the task of NULL |
| 541 | terminating things and makes the rest of this look a bit | 581 | terminating things and makes the rest of this look a bit |
| 542 | cleaner (though it is, admittedly, a tad less efficient) */ | 582 | cleaner (though it is, admittedly, a tad less efficient) */ |
| 543 | job->cmdBuf = command = calloc(1, strlen(*commandPtr) + 1); | 583 | job->cmdBuf = command = calloc(1, 2*strlen(*commandPtr) + 1); |
| 544 | job->text = NULL; | 584 | job->text = NULL; |
| 545 | 585 | ||
| 546 | prog = job->progs; | 586 | prog = job->progs; |
| @@ -583,9 +623,8 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg) | |||
| 583 | sizeof(*prog->argv) * | 623 | sizeof(*prog->argv) * |
| 584 | argvAlloced); | 624 | argvAlloced); |
| 585 | } | 625 | } |
| 586 | prog->argv[argc] = buf; | ||
| 587 | |||
| 588 | globLastArgument(prog, &argc, &argvAlloced); | 626 | globLastArgument(prog, &argc, &argvAlloced); |
| 627 | prog->argv[argc] = buf; | ||
| 589 | } | 628 | } |
| 590 | } else | 629 | } else |
| 591 | switch (*src) { | 630 | switch (*src) { |
| @@ -615,6 +654,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg) | |||
| 615 | if (*chptr && *prog->argv[argc]) { | 654 | if (*chptr && *prog->argv[argc]) { |
| 616 | buf++, argc++; | 655 | buf++, argc++; |
| 617 | globLastArgument(prog, &argc, &argvAlloced); | 656 | globLastArgument(prog, &argc, &argvAlloced); |
| 657 | prog->argv[argc] = buf; | ||
| 618 | } | 658 | } |
| 619 | } | 659 | } |
| 620 | 660 | ||
| @@ -749,7 +789,7 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg) | |||
| 749 | int nextin, nextout; | 789 | int nextin, nextout; |
| 750 | int pipefds[2]; /* pipefd[0] is for reading */ | 790 | int pipefds[2]; /* pipefd[0] is for reading */ |
| 751 | struct builtInCommand *x; | 791 | struct builtInCommand *x; |
| 752 | #ifdef BB_FEATURE_STANDALONE_SHELL | 792 | #ifdef BB_FEATURE_SH_STANDALONE_SHELL |
| 753 | const struct BB_applet *a = applets; | 793 | const struct BB_applet *a = applets; |
| 754 | #endif | 794 | #endif |
| 755 | 795 | ||
| @@ -792,7 +832,7 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg) | |||
| 792 | exit (x->function(&newJob, jobList)); | 832 | exit (x->function(&newJob, jobList)); |
| 793 | } | 833 | } |
| 794 | } | 834 | } |
| 795 | #ifdef BB_FEATURE_STANDALONE_SHELL | 835 | #ifdef BB_FEATURE_SH_STANDALONE_SHELL |
| 796 | /* Handle busybox internals here */ | 836 | /* Handle busybox internals here */ |
| 797 | while (a->name != 0) { | 837 | while (a->name != 0) { |
| 798 | if (strcmp(newJob.progs[i].argv[0], a->name) == 0) { | 838 | if (strcmp(newJob.progs[i].argv[0], a->name) == 0) { |
| @@ -984,6 +1024,14 @@ static int busy_loop(FILE * input) | |||
| 984 | if (tcsetpgrp(0, parent_pgrp)) | 1024 | if (tcsetpgrp(0, parent_pgrp)) |
| 985 | perror("tcsetpgrp"); | 1025 | perror("tcsetpgrp"); |
| 986 | 1026 | ||
| 1027 | /* return controlling TTY back to parent process group before exiting */ | ||
| 1028 | if (tcsetpgrp(0, parent_pgrp)) | ||
| 1029 | perror("tcsetpgrp"); | ||
| 1030 | |||
| 1031 | /* return exit status if called with "-c" */ | ||
| 1032 | if (input == NULL && WIFEXITED(status)) | ||
| 1033 | return WEXITSTATUS(status); | ||
| 1034 | |||
| 987 | return 0; | 1035 | return 0; |
| 988 | } | 1036 | } |
| 989 | 1037 | ||
| @@ -993,7 +1041,11 @@ int shell_main(int argc, char **argv) | |||
| 993 | FILE *input = stdin; | 1041 | FILE *input = stdin; |
| 994 | 1042 | ||
| 995 | /* initialize the cwd */ | 1043 | /* initialize the cwd */ |
| 996 | getcwd(cwd, sizeof(cwd)); | 1044 | cwd = (char *) calloc(BUFSIZ, sizeof(char)); |
| 1045 | if (cwd == 0) { | ||
| 1046 | fatalError("sh: out of memory\n"); | ||
| 1047 | } | ||
| 1048 | getcwd(cwd, sizeof(char)*BUFSIZ); | ||
| 997 | 1049 | ||
| 998 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 1050 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
| 999 | cmdedit_init(); | 1051 | cmdedit_init(); |
| @@ -1018,10 +1070,13 @@ int shell_main(int argc, char **argv) | |||
| 1018 | for(i=2; i<argc; i++) | 1070 | for(i=2; i<argc; i++) |
| 1019 | { | 1071 | { |
| 1020 | if (strlen(local_pending_command) + strlen(argv[i]) >= BUFSIZ) { | 1072 | if (strlen(local_pending_command) + strlen(argv[i]) >= BUFSIZ) { |
| 1021 | fatalError("sh: commands for -c option too long\n"); | 1073 | local_pending_command = realloc(local_pending_command, |
| 1074 | strlen(local_pending_command) + strlen(argv[i])); | ||
| 1075 | if (local_pending_command==NULL) | ||
| 1076 | fatalError("sh: commands for -c option too long\n"); | ||
| 1022 | } | 1077 | } |
| 1023 | strcat(local_pending_command, argv[i]); | 1078 | strcat(local_pending_command, argv[i]); |
| 1024 | if (i + 1 < argc) | 1079 | if ( (i + 1) < argc) |
| 1025 | strcat(local_pending_command, " "); | 1080 | strcat(local_pending_command, " "); |
| 1026 | } | 1081 | } |
| 1027 | input = NULL; | 1082 | input = NULL; |
