aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2000-07-03 23:56:26 +0000
committerEric Andersen <andersen@codepoet.org>2000-07-03 23:56:26 +0000
commitb54833cde0dfde26ad7c2d3a6cda9d7ff2dfe9ba (patch)
tree5198af3f042d52372f2aec604b21eeb2cdfda672
parent7c31ea4e2978eee19988efbfddb2a8f3e0c6873d (diff)
downloadbusybox-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.h2
-rw-r--r--lash.c79
-rw-r--r--sh.c79
-rw-r--r--shell/lash.c79
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)
diff --git a/lash.c b/lash.c
index 785e9cc3f..2d6bfb526 100644
--- a/lash.c
+++ b/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);
100static int shell_export(struct job *cmd, struct jobSet *junk); 100static int shell_export(struct job *cmd, struct jobSet *junk);
101static int shell_source(struct job *cmd, struct jobSet *jobList); 101static int shell_source(struct job *cmd, struct jobSet *jobList);
102static int shell_unset(struct job *cmd, struct jobSet *junk); 102static int shell_unset(struct job *cmd, struct jobSet *junk);
103static int shell_read(struct job *cmd, struct jobSet *junk);
103 104
104static void checkJobs(struct jobSet *jobList); 105static void checkJobs(struct jobSet *jobList);
105static int getCommand(FILE * source, char *command); 106static 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
141static char cwd[1024];
142static char *prompt = "# "; 143static char *prompt = "# ";
144static char *cwd = NULL;
143static char *local_pending_command = NULL; 145static 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 */
306static 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) */
304static int shell_source(struct job *cmd, struct jobSet *junk) 340static 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/sh.c b/sh.c
index 785e9cc3f..2d6bfb526 100644
--- a/sh.c
+++ b/sh.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);
100static int shell_export(struct job *cmd, struct jobSet *junk); 100static int shell_export(struct job *cmd, struct jobSet *junk);
101static int shell_source(struct job *cmd, struct jobSet *jobList); 101static int shell_source(struct job *cmd, struct jobSet *jobList);
102static int shell_unset(struct job *cmd, struct jobSet *junk); 102static int shell_unset(struct job *cmd, struct jobSet *junk);
103static int shell_read(struct job *cmd, struct jobSet *junk);
103 104
104static void checkJobs(struct jobSet *jobList); 105static void checkJobs(struct jobSet *jobList);
105static int getCommand(FILE * source, char *command); 106static 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
141static char cwd[1024];
142static char *prompt = "# "; 143static char *prompt = "# ";
144static char *cwd = NULL;
143static char *local_pending_command = NULL; 145static 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 */
306static 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) */
304static int shell_source(struct job *cmd, struct jobSet *junk) 340static 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);
100static int shell_export(struct job *cmd, struct jobSet *junk); 100static int shell_export(struct job *cmd, struct jobSet *junk);
101static int shell_source(struct job *cmd, struct jobSet *jobList); 101static int shell_source(struct job *cmd, struct jobSet *jobList);
102static int shell_unset(struct job *cmd, struct jobSet *junk); 102static int shell_unset(struct job *cmd, struct jobSet *junk);
103static int shell_read(struct job *cmd, struct jobSet *junk);
103 104
104static void checkJobs(struct jobSet *jobList); 105static void checkJobs(struct jobSet *jobList);
105static int getCommand(FILE * source, char *command); 106static 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
141static char cwd[1024];
142static char *prompt = "# "; 143static char *prompt = "# ";
144static char *cwd = NULL;
143static char *local_pending_command = NULL; 145static 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 */
306static 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) */
304static int shell_source(struct job *cmd, struct jobSet *junk) 340static 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;