diff options
author | Eric Andersen <andersen@codepoet.org> | 2000-07-03 23:56:26 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2000-07-03 23:56:26 +0000 |
commit | b54833cde0dfde26ad7c2d3a6cda9d7ff2dfe9ba (patch) | |
tree | 5198af3f042d52372f2aec604b21eeb2cdfda672 | |
parent | 7c31ea4e2978eee19988efbfddb2a8f3e0c6873d (diff) | |
download | busybox-w32-b54833cde0dfde26ad7c2d3a6cda9d7ff2dfe9ba.tar.gz busybox-w32-b54833cde0dfde26ad7c2d3a6cda9d7ff2dfe9ba.tar.bz2 busybox-w32-b54833cde0dfde26ad7c2d3a6cda9d7ff2dfe9ba.zip |
sh fixes from Marius Groeger <mag@sysgo.de>
-Erik
-rw-r--r-- | busybox.def.h | 2 | ||||
-rw-r--r-- | lash.c | 79 | ||||
-rw-r--r-- | sh.c | 79 | ||||
-rw-r--r-- | shell/lash.c | 79 |
4 files changed, 202 insertions, 37 deletions
diff --git a/busybox.def.h b/busybox.def.h index a07327e4b..81e5f1070 100644 --- a/busybox.def.h +++ b/busybox.def.h | |||
@@ -211,7 +211,7 @@ | |||
211 | //Allow the shell to invoke all the compiled in BusyBox commands as if they | 211 | //Allow the shell to invoke all the compiled in BusyBox commands as if they |
212 | //were shell builtins. Nice for staticly linking an emergency rescue shell | 212 | //were shell builtins. Nice for staticly linking an emergency rescue shell |
213 | //amoung other thing. | 213 | //amoung other thing. |
214 | #define BB_FEATURE_STANDALONE_SHELL | 214 | #define BB_FEATURE_SH_STANDALONE_SHELL |
215 | // | 215 | // |
216 | // Enable tab completion in the shell (not yet | 216 | // Enable tab completion in the shell (not yet |
217 | // working very well -- so don't turn this on) | 217 | // working very well -- so don't turn this on) |
@@ -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; |
@@ -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; |
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; |