diff options
author | Eric Andersen <andersen@codepoet.org> | 2000-07-27 00:15:20 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2000-07-27 00:15:20 +0000 |
commit | 6a99aaf0208151b7f5e5058efaa409496e2b7c4b (patch) | |
tree | c2f6f79643b050fb13345f1176795397aa98ae66 | |
parent | 7ce41ad69296d391e4ef2fa92112e57264687063 (diff) | |
download | busybox-w32-6a99aaf0208151b7f5e5058efaa409496e2b7c4b.tar.gz busybox-w32-6a99aaf0208151b7f5e5058efaa409496e2b7c4b.tar.bz2 busybox-w32-6a99aaf0208151b7f5e5058efaa409496e2b7c4b.zip |
More shell features.... if-then-else-fi is now basically usable (disable
by default pending further debugging). Added in some basic shell environment
support (i.e. $?, $0-$9, $$, $!, $#).
-Erik
-rw-r--r-- | lash.c | 352 | ||||
-rw-r--r-- | sh.c | 352 | ||||
-rw-r--r-- | shell/lash.c | 352 |
3 files changed, 717 insertions, 339 deletions
@@ -26,9 +26,9 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | 28 | ||
29 | #define BB_FEATURE_SH_BACKTICKS | 29 | //#define BB_FEATURE_SH_BACKTICKS |
30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS | 30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS |
31 | 31 | //#define BB_FEATURE_SH_ENVIRONMENT | |
32 | 32 | ||
33 | 33 | ||
34 | #include "internal.h" | 34 | #include "internal.h" |
@@ -57,13 +57,11 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | |||
57 | }; | 57 | }; |
58 | 58 | ||
59 | static const unsigned int REGULAR_JOB_CONTEXT=0x1; | 59 | static const unsigned int REGULAR_JOB_CONTEXT=0x1; |
60 | static const unsigned int IF_EXP_CONTEXT=0x2; | 60 | static const unsigned int IF_TRUE_CONTEXT=0x2; |
61 | static const unsigned int THEN_EXP_CONTEXT=0x4; | 61 | static const unsigned int IF_FALSE_CONTEXT=0x4; |
62 | static const unsigned int ELSE_EXP_CONTEXT=0x8; | 62 | static const unsigned int THEN_EXP_CONTEXT=0x8; |
63 | 63 | static const unsigned int ELSE_EXP_CONTEXT=0x10; | |
64 | 64 | ||
65 | enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT | ||
66 | }; | ||
67 | 65 | ||
68 | struct jobSet { | 66 | struct jobSet { |
69 | struct job *head; /* head of list of running jobs */ | 67 | struct job *head; /* head of list of running jobs */ |
@@ -128,8 +126,7 @@ static int builtin_fi(struct job *cmd, struct jobSet *junk); | |||
128 | /* function prototypes for shell stuff */ | 126 | /* function prototypes for shell stuff */ |
129 | static void checkJobs(struct jobSet *jobList); | 127 | static void checkJobs(struct jobSet *jobList); |
130 | static int getCommand(FILE * source, char *command); | 128 | static int getCommand(FILE * source, char *command); |
131 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg); | 129 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg); |
132 | static int setupRedirections(struct childProgram *prog); | ||
133 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); | 130 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); |
134 | static int busy_loop(FILE * input); | 131 | static int busy_loop(FILE * input); |
135 | 132 | ||
@@ -146,6 +143,12 @@ static struct builtInCommand bltins[] = { | |||
146 | {"export", "Set environment variable", builtin_export}, | 143 | {"export", "Set environment variable", builtin_export}, |
147 | {"unset", "Unset environment variable", builtin_unset}, | 144 | {"unset", "Unset environment variable", builtin_unset}, |
148 | {"read", "Input environment variable", builtin_read}, | 145 | {"read", "Input environment variable", builtin_read}, |
146 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
147 | {"if", NULL, builtin_if}, | ||
148 | {"then", NULL, builtin_then}, | ||
149 | {"else", NULL, builtin_else}, | ||
150 | {"fi", NULL, builtin_fi}, | ||
151 | #endif | ||
149 | {NULL, NULL, NULL} | 152 | {NULL, NULL, NULL} |
150 | }; | 153 | }; |
151 | 154 | ||
@@ -154,12 +157,6 @@ static struct builtInCommand bltins[] = { | |||
154 | static struct builtInCommand bltins_forking[] = { | 157 | static struct builtInCommand bltins_forking[] = { |
155 | {"env", "Print all environment variables", builtin_env}, | 158 | {"env", "Print all environment variables", builtin_env}, |
156 | {"pwd", "Print current directory", builtin_pwd}, | 159 | {"pwd", "Print current directory", builtin_pwd}, |
157 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
158 | {"if", NULL, builtin_if}, | ||
159 | {"then", NULL, builtin_then}, | ||
160 | {"else", NULL, builtin_else}, | ||
161 | {"fi", NULL, builtin_fi}, | ||
162 | #endif | ||
163 | {".", "Source-in and run commands in a file", builtin_source}, | 160 | {".", "Source-in and run commands in a file", builtin_source}, |
164 | {"help", "List shell built-in commands", builtin_help}, | 161 | {"help", "List shell built-in commands", builtin_help}, |
165 | {NULL, NULL, NULL} | 162 | {NULL, NULL, NULL} |
@@ -170,6 +167,13 @@ static char *cwd; | |||
170 | static char *local_pending_command = NULL; | 167 | static char *local_pending_command = NULL; |
171 | static char *promptStr = NULL; | 168 | static char *promptStr = NULL; |
172 | static struct jobSet jobList = { NULL, NULL }; | 169 | static struct jobSet jobList = { NULL, NULL }; |
170 | static int argc; | ||
171 | static char **argv; | ||
172 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
173 | static int lastBgPid=-1; | ||
174 | static int lastReturnCode=-1; | ||
175 | #endif | ||
176 | |||
173 | 177 | ||
174 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 178 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
175 | void win_changed(int junk) | 179 | void win_changed(int junk) |
@@ -369,38 +373,91 @@ static int builtin_read(struct job *cmd, struct jobSet *junk) | |||
369 | 373 | ||
370 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | 374 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS |
371 | /* Built-in handler for 'if' commands */ | 375 | /* Built-in handler for 'if' commands */ |
372 | static int builtin_if(struct job *cmd, struct jobSet *junk) | 376 | static int builtin_if(struct job *cmd, struct jobSet *jobList) |
373 | { | 377 | { |
374 | cmd->jobContext |= IF_EXP_CONTEXT; | 378 | int status; |
375 | printf("Hit an if -- jobContext=%d\n", cmd->jobContext); | 379 | char* charptr1=cmd->text+3; /* skip over the leading 'if ' */ |
376 | return TRUE; | 380 | |
381 | /* Now run the 'if' command */ | ||
382 | status=strlen(charptr1); | ||
383 | local_pending_command = xmalloc(status+1); | ||
384 | strncpy(local_pending_command, charptr1, status); | ||
385 | printf("'if' now running '%s'\n", charptr1); | ||
386 | status = busy_loop(NULL); /* Frees local_pending_command */ | ||
387 | printf("if test returned "); | ||
388 | if (status == 0) { | ||
389 | printf("TRUE\n"); | ||
390 | cmd->jobContext |= IF_TRUE_CONTEXT; | ||
391 | } else { | ||
392 | printf("FALSE\n"); | ||
393 | cmd->jobContext |= IF_FALSE_CONTEXT; | ||
394 | } | ||
395 | |||
396 | return status; | ||
377 | } | 397 | } |
378 | 398 | ||
379 | /* Built-in handler for 'then' (part of the 'if' command) */ | 399 | /* Built-in handler for 'then' (part of the 'if' command) */ |
380 | static int builtin_then(struct job *cmd, struct jobSet *junk) | 400 | static int builtin_then(struct job *cmd, struct jobSet *junk) |
381 | { | 401 | { |
382 | if (cmd->jobContext & IF_EXP_CONTEXT) { | 402 | int status; |
383 | fprintf(stderr, "unexpected token `then'\n"); | 403 | char* charptr1=cmd->text+5; /* skip over the leading 'then ' */ |
384 | fflush(stderr); | 404 | |
405 | if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { | ||
406 | errorMsg("unexpected token `then'\n"); | ||
385 | return FALSE; | 407 | return FALSE; |
386 | } | 408 | } |
409 | /* If the if result was FALSE, skip the 'then' stuff */ | ||
410 | if (cmd->jobContext & IF_TRUE_CONTEXT) { | ||
411 | return TRUE; | ||
412 | } | ||
413 | |||
387 | cmd->jobContext |= THEN_EXP_CONTEXT; | 414 | cmd->jobContext |= THEN_EXP_CONTEXT; |
388 | printf("Hit an then -- jobContext=%d\n", cmd->jobContext); | 415 | //printf("Hit an then -- jobContext=%d\n", cmd->jobContext); |
389 | return TRUE; | 416 | |
417 | /* Now run the 'then' command */ | ||
418 | status=strlen(charptr1); | ||
419 | local_pending_command = xmalloc(status+1); | ||
420 | strncpy(local_pending_command, charptr1, status); | ||
421 | printf("'then' now running '%s'\n", charptr1); | ||
422 | return( busy_loop(NULL)); | ||
390 | } | 423 | } |
391 | 424 | ||
392 | /* Built-in handler for 'else' (part of the 'if' command) */ | 425 | /* Built-in handler for 'else' (part of the 'if' command) */ |
393 | static int builtin_else(struct job *cmd, struct jobSet *junk) | 426 | static int builtin_else(struct job *cmd, struct jobSet *junk) |
394 | { | 427 | { |
395 | printf("Hit an else\n"); | 428 | int status; |
429 | char* charptr1=cmd->text+5; /* skip over the leading 'else ' */ | ||
430 | |||
431 | if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { | ||
432 | errorMsg("unexpected token `else'\n"); | ||
433 | return FALSE; | ||
434 | } | ||
435 | /* If the if result was TRUE, skip the 'else' stuff */ | ||
436 | if (cmd->jobContext & IF_FALSE_CONTEXT) { | ||
437 | return TRUE; | ||
438 | } | ||
439 | |||
396 | cmd->jobContext |= ELSE_EXP_CONTEXT; | 440 | cmd->jobContext |= ELSE_EXP_CONTEXT; |
397 | return TRUE; | 441 | //printf("Hit an else -- jobContext=%d\n", cmd->jobContext); |
442 | |||
443 | /* Now run the 'else' command */ | ||
444 | status=strlen(charptr1); | ||
445 | local_pending_command = xmalloc(status+1); | ||
446 | strncpy(local_pending_command, charptr1, status); | ||
447 | printf("'else' now running '%s'\n", charptr1); | ||
448 | return( busy_loop(NULL)); | ||
398 | } | 449 | } |
399 | 450 | ||
400 | /* Built-in handler for 'fi' (part of the 'if' command) */ | 451 | /* Built-in handler for 'fi' (part of the 'if' command) */ |
401 | static int builtin_fi(struct job *cmd, struct jobSet *junk) | 452 | static int builtin_fi(struct job *cmd, struct jobSet *junk) |
402 | { | 453 | { |
403 | printf("Hit an fi\n"); | 454 | if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { |
455 | errorMsg("unexpected token `fi'\n"); | ||
456 | return FALSE; | ||
457 | } | ||
458 | /* Clear out the if and then context bits */ | ||
459 | cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); | ||
460 | printf("Hit an fi -- jobContext=%d\n", cmd->jobContext); | ||
404 | return TRUE; | 461 | return TRUE; |
405 | } | 462 | } |
406 | #endif | 463 | #endif |
@@ -521,6 +578,45 @@ static void checkJobs(struct jobSet *jobList) | |||
521 | perror("waitpid"); | 578 | perror("waitpid"); |
522 | } | 579 | } |
523 | 580 | ||
581 | static int setupRedirections(struct childProgram *prog) | ||
582 | { | ||
583 | int i; | ||
584 | int openfd; | ||
585 | int mode = O_RDONLY; | ||
586 | struct redirectionSpecifier *redir = prog->redirections; | ||
587 | |||
588 | for (i = 0; i < prog->numRedirections; i++, redir++) { | ||
589 | switch (redir->type) { | ||
590 | case REDIRECT_INPUT: | ||
591 | mode = O_RDONLY; | ||
592 | break; | ||
593 | case REDIRECT_OVERWRITE: | ||
594 | mode = O_RDWR | O_CREAT | O_TRUNC; | ||
595 | break; | ||
596 | case REDIRECT_APPEND: | ||
597 | mode = O_RDWR | O_CREAT | O_APPEND; | ||
598 | break; | ||
599 | } | ||
600 | |||
601 | openfd = open(redir->filename, mode, 0666); | ||
602 | if (openfd < 0) { | ||
603 | /* this could get lost if stderr has been redirected, but | ||
604 | bash and ash both lose it as well (though zsh doesn't!) */ | ||
605 | errorMsg("error opening %s: %s\n", redir->filename, | ||
606 | strerror(errno)); | ||
607 | return 1; | ||
608 | } | ||
609 | |||
610 | if (openfd != redir->fd) { | ||
611 | dup2(openfd, redir->fd); | ||
612 | close(openfd); | ||
613 | } | ||
614 | } | ||
615 | |||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | |||
524 | static int getCommand(FILE * source, char *command) | 620 | static int getCommand(FILE * source, char *command) |
525 | { | 621 | { |
526 | if (source == NULL) { | 622 | if (source == NULL) { |
@@ -562,17 +658,40 @@ static int getCommand(FILE * source, char *command) | |||
562 | return 0; | 658 | return 0; |
563 | } | 659 | } |
564 | 660 | ||
661 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
662 | #define __MAX_INT_CHARS 7 | ||
663 | static char* itoa(register int i) | ||
664 | { | ||
665 | static char a[__MAX_INT_CHARS]; | ||
666 | register char *b = a + sizeof(a) - 1; | ||
667 | int sign = (i < 0); | ||
668 | |||
669 | if (sign) | ||
670 | i = -i; | ||
671 | *b = 0; | ||
672 | do | ||
673 | { | ||
674 | *--b = '0' + (i % 10); | ||
675 | i /= 10; | ||
676 | } | ||
677 | while (i); | ||
678 | if (sign) | ||
679 | *--b = '-'; | ||
680 | return b; | ||
681 | } | ||
682 | #endif | ||
683 | |||
565 | static void globLastArgument(struct childProgram *prog, int *argcPtr, | 684 | static void globLastArgument(struct childProgram *prog, int *argcPtr, |
566 | int *argcAllocedPtr) | 685 | int *argcAllocedPtr) |
567 | { | 686 | { |
568 | int argc = *argcPtr; | 687 | int argc_l = *argcPtr; |
569 | int argcAlloced = *argcAllocedPtr; | 688 | int argcAlloced = *argcAllocedPtr; |
570 | int rc; | 689 | int rc; |
571 | int flags; | 690 | int flags; |
572 | int i; | 691 | int i; |
573 | char *src, *dst, *var; | 692 | char *src, *dst, *var; |
574 | 693 | ||
575 | if (argc > 1) { /* cmd->globResult is already initialized */ | 694 | if (argc_l > 1) { /* cmd->globResult is already initialized */ |
576 | flags = GLOB_APPEND; | 695 | flags = GLOB_APPEND; |
577 | i = prog->globResult.gl_pathc; | 696 | i = prog->globResult.gl_pathc; |
578 | } else { | 697 | } else { |
@@ -581,19 +700,54 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr, | |||
581 | i = 0; | 700 | i = 0; |
582 | } | 701 | } |
583 | /* do shell variable substitution */ | 702 | /* do shell variable substitution */ |
584 | if(*prog->argv[argc - 1] == '$' && (var = getenv(prog->argv[argc - 1] + 1))) | 703 | if(*prog->argv[argc_l - 1] == '$') { |
585 | prog->argv[argc - 1] = var; | 704 | if ((var = getenv(prog->argv[argc_l - 1] + 1))) { |
705 | prog->argv[argc_l - 1] = var; | ||
706 | } | ||
707 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
708 | else { | ||
709 | switch(*(prog->argv[argc_l - 1] + 1)) { | ||
710 | case '?': | ||
711 | prog->argv[argc_l - 1] = itoa(lastReturnCode); | ||
712 | break; | ||
713 | case '$': | ||
714 | prog->argv[argc_l - 1] = itoa(getpid()); | ||
715 | break; | ||
716 | case '#': | ||
717 | prog->argv[argc_l - 1] = itoa(argc-1); | ||
718 | break; | ||
719 | case '!': | ||
720 | if (lastBgPid==-1) | ||
721 | *(prog->argv[argc_l - 1])='\0'; | ||
722 | else | ||
723 | prog->argv[argc_l - 1] = itoa(lastBgPid); | ||
724 | break; | ||
725 | case '0':case '1':case '2':case '3':case '4': | ||
726 | case '5':case '6':case '7':case '8':case '9': | ||
727 | { | ||
728 | int index=*(prog->argv[argc_l - 1] + 1)-48; | ||
729 | if (index >= argc) { | ||
730 | *(prog->argv[argc_l - 1])='\0'; | ||
731 | } else { | ||
732 | prog->argv[argc_l - 1] = argv[index]; | ||
733 | } | ||
734 | } | ||
735 | break; | ||
736 | } | ||
737 | } | ||
738 | #endif | ||
739 | } | ||
586 | 740 | ||
587 | rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult); | 741 | rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult); |
588 | if (rc == GLOB_NOSPACE) { | 742 | if (rc == GLOB_NOSPACE) { |
589 | errorMsg("out of space during glob operation\n"); | 743 | errorMsg("out of space during glob operation\n"); |
590 | return; | 744 | return; |
591 | } else if (rc == GLOB_NOMATCH || | 745 | } else if (rc == GLOB_NOMATCH || |
592 | (!rc && (prog->globResult.gl_pathc - i) == 1 && | 746 | (!rc && (prog->globResult.gl_pathc - i) == 1 && |
593 | strcmp(prog->argv[argc - 1], | 747 | strcmp(prog->argv[argc_l - 1], |
594 | prog->globResult.gl_pathv[i]) == 0)) { | 748 | prog->globResult.gl_pathv[i]) == 0)) { |
595 | /* we need to remove whatever \ quoting is still present */ | 749 | /* we need to remove whatever \ quoting is still present */ |
596 | src = dst = prog->argv[argc - 1]; | 750 | src = dst = prog->argv[argc_l - 1]; |
597 | while (*src) { | 751 | while (*src) { |
598 | if (*src != '\\') | 752 | if (*src != '\\') |
599 | *dst++ = *src; | 753 | *dst++ = *src; |
@@ -604,13 +758,13 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr, | |||
604 | argcAlloced += (prog->globResult.gl_pathc - i); | 758 | argcAlloced += (prog->globResult.gl_pathc - i); |
605 | prog->argv = | 759 | prog->argv = |
606 | realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); | 760 | realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); |
607 | memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, | 761 | memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i, |
608 | sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); | 762 | sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); |
609 | argc += (prog->globResult.gl_pathc - i - 1); | 763 | argc_l += (prog->globResult.gl_pathc - i - 1); |
610 | } | 764 | } |
611 | 765 | ||
612 | *argcAllocedPtr = argcAlloced; | 766 | *argcAllocedPtr = argcAlloced; |
613 | *argcPtr = argc; | 767 | *argcPtr = argc_l; |
614 | } | 768 | } |
615 | 769 | ||
616 | /* Return cmd->numProgs as 0 if no command is present (e.g. an empty | 770 | /* Return cmd->numProgs as 0 if no command is present (e.g. an empty |
@@ -618,12 +772,12 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr, | |||
618 | the beginning of the next command (if the original command had more | 772 | the beginning of the next command (if the original command had more |
619 | then one job associated with it) or NULL if no more commands are | 773 | then one job associated with it) or NULL if no more commands are |
620 | present. */ | 774 | present. */ |
621 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg) | 775 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg) |
622 | { | 776 | { |
623 | char *command; | 777 | char *command; |
624 | char *returnCommand = NULL; | 778 | char *returnCommand = NULL; |
625 | char *src, *buf, *chptr; | 779 | char *src, *buf, *chptr; |
626 | int argc = 0; | 780 | int argc_l = 0; |
627 | int done = 0; | 781 | int done = 0; |
628 | int argvAlloced; | 782 | int argvAlloced; |
629 | int i; | 783 | int i; |
@@ -641,7 +795,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
641 | return 0; | 795 | return 0; |
642 | } | 796 | } |
643 | 797 | ||
644 | *isBg = 0; | 798 | *inBg = 0; |
645 | job->numProgs = 1; | 799 | job->numProgs = 1; |
646 | job->progs = xmalloc(sizeof(*job->progs)); | 800 | job->progs = xmalloc(sizeof(*job->progs)); |
647 | 801 | ||
@@ -654,7 +808,6 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
654 | cleaner (though it is, admittedly, a tad less efficient) */ | 808 | cleaner (though it is, admittedly, a tad less efficient) */ |
655 | job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); | 809 | job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); |
656 | job->text = NULL; | 810 | job->text = NULL; |
657 | job->jobContext = REGULAR_JOB_CONTEXT; | ||
658 | 811 | ||
659 | prog = job->progs; | 812 | prog = job->progs; |
660 | prog->numRedirections = 0; | 813 | prog->numRedirections = 0; |
@@ -687,17 +840,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
687 | *src == ']') *buf++ = '\\'; | 840 | *src == ']') *buf++ = '\\'; |
688 | *buf++ = *src; | 841 | *buf++ = *src; |
689 | } else if (isspace(*src)) { | 842 | } else if (isspace(*src)) { |
690 | if (*prog->argv[argc]) { | 843 | if (*prog->argv[argc_l]) { |
691 | buf++, argc++; | 844 | buf++, argc_l++; |
692 | /* +1 here leaves room for the NULL which ends argv */ | 845 | /* +1 here leaves room for the NULL which ends argv */ |
693 | if ((argc + 1) == argvAlloced) { | 846 | if ((argc_l + 1) == argvAlloced) { |
694 | argvAlloced += 5; | 847 | argvAlloced += 5; |
695 | prog->argv = realloc(prog->argv, | 848 | prog->argv = realloc(prog->argv, |
696 | sizeof(*prog->argv) * | 849 | sizeof(*prog->argv) * |
697 | argvAlloced); | 850 | argvAlloced); |
698 | } | 851 | } |
699 | globLastArgument(prog, &argc, &argvAlloced); | 852 | globLastArgument(prog, &argc_l, &argvAlloced); |
700 | prog->argv[argc] = buf; | 853 | prog->argv[argc_l] = buf; |
701 | } | 854 | } |
702 | } else | 855 | } else |
703 | switch (*src) { | 856 | switch (*src) { |
@@ -707,7 +860,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
707 | break; | 860 | break; |
708 | 861 | ||
709 | case '#': /* comment */ | 862 | case '#': /* comment */ |
710 | done = 1; | 863 | if (*(src-1)== '$') |
864 | *buf++ = *src; | ||
865 | else | ||
866 | done = 1; | ||
711 | break; | 867 | break; |
712 | 868 | ||
713 | case '>': /* redirections */ | 869 | case '>': /* redirections */ |
@@ -718,16 +874,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
718 | (i + 1)); | 874 | (i + 1)); |
719 | 875 | ||
720 | prog->redirections[i].fd = -1; | 876 | prog->redirections[i].fd = -1; |
721 | if (buf != prog->argv[argc]) { | 877 | if (buf != prog->argv[argc_l]) { |
722 | /* the stuff before this character may be the file number | 878 | /* the stuff before this character may be the file number |
723 | being redirected */ | 879 | being redirected */ |
724 | prog->redirections[i].fd = | 880 | prog->redirections[i].fd = |
725 | strtol(prog->argv[argc], &chptr, 10); | 881 | strtol(prog->argv[argc_l], &chptr, 10); |
726 | 882 | ||
727 | if (*chptr && *prog->argv[argc]) { | 883 | if (*chptr && *prog->argv[argc_l]) { |
728 | buf++, argc++; | 884 | buf++, argc_l++; |
729 | globLastArgument(prog, &argc, &argvAlloced); | 885 | globLastArgument(prog, &argc_l, &argvAlloced); |
730 | prog->argv[argc] = buf; | 886 | prog->argv[argc_l] = buf; |
731 | } | 887 | } |
732 | } | 888 | } |
733 | 889 | ||
@@ -765,20 +921,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
765 | *buf++ = *chptr++; | 921 | *buf++ = *chptr++; |
766 | 922 | ||
767 | src = chptr - 1; /* we src++ later */ | 923 | src = chptr - 1; /* we src++ later */ |
768 | prog->argv[argc] = ++buf; | 924 | prog->argv[argc_l] = ++buf; |
769 | break; | 925 | break; |
770 | 926 | ||
771 | case '|': /* pipe */ | 927 | case '|': /* pipe */ |
772 | /* finish this command */ | 928 | /* finish this command */ |
773 | if (*prog->argv[argc]) | 929 | if (*prog->argv[argc_l]) |
774 | argc++; | 930 | argc_l++; |
775 | if (!argc) { | 931 | if (!argc_l) { |
776 | errorMsg("empty command in pipe\n"); | 932 | errorMsg("empty command in pipe\n"); |
777 | freeJob(job); | 933 | freeJob(job); |
778 | job->numProgs=0; | 934 | job->numProgs=0; |
779 | return 1; | 935 | return 1; |
780 | } | 936 | } |
781 | prog->argv[argc] = NULL; | 937 | prog->argv[argc_l] = NULL; |
782 | 938 | ||
783 | /* and start the next */ | 939 | /* and start the next */ |
784 | job->numProgs++; | 940 | job->numProgs++; |
@@ -788,7 +944,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
788 | prog->numRedirections = 0; | 944 | prog->numRedirections = 0; |
789 | prog->redirections = NULL; | 945 | prog->redirections = NULL; |
790 | prog->freeGlob = 0; | 946 | prog->freeGlob = 0; |
791 | argc = 0; | 947 | argc_l = 0; |
792 | 948 | ||
793 | argvAlloced = 5; | 949 | argvAlloced = 5; |
794 | prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); | 950 | prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); |
@@ -809,7 +965,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
809 | break; | 965 | break; |
810 | 966 | ||
811 | case '&': /* background */ | 967 | case '&': /* background */ |
812 | *isBg = 1; | 968 | *inBg = 1; |
813 | case ';': /* multiple commands */ | 969 | case ';': /* multiple commands */ |
814 | done = 1; | 970 | done = 1; |
815 | returnCommand = *commandPtr + (src - *commandPtr) + 1; | 971 | returnCommand = *commandPtr + (src - *commandPtr) + 1; |
@@ -848,7 +1004,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
848 | snprintf(charptr1, 1+ptr-src, src); | 1004 | snprintf(charptr1, 1+ptr-src, src); |
849 | newJob = xmalloc(sizeof(struct job)); | 1005 | newJob = xmalloc(sizeof(struct job)); |
850 | /* Now parse and run the backticked command */ | 1006 | /* Now parse and run the backticked command */ |
851 | if (!parseCommand(&charptr1, newJob, &njobList, isBg) | 1007 | if (!parseCommand(&charptr1, newJob, &njobList, inBg) |
852 | && newJob->numProgs) { | 1008 | && newJob->numProgs) { |
853 | pipe(pipefd); | 1009 | pipe(pipefd); |
854 | runCommand(newJob, &njobList, 0, pipefd); | 1010 | runCommand(newJob, &njobList, 0, pipefd); |
@@ -890,7 +1046,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
890 | * and improved version of the command line with the backtick | 1046 | * and improved version of the command line with the backtick |
891 | * results expanded in place... */ | 1047 | * results expanded in place... */ |
892 | freeJob(job); | 1048 | freeJob(job); |
893 | return(parseCommand(commandPtr, job, jobList, isBg)); | 1049 | return(parseCommand(commandPtr, job, jobList, inBg)); |
894 | } | 1050 | } |
895 | break; | 1051 | break; |
896 | #endif // BB_FEATURE_SH_BACKTICKS | 1052 | #endif // BB_FEATURE_SH_BACKTICKS |
@@ -901,15 +1057,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
901 | src++; | 1057 | src++; |
902 | } | 1058 | } |
903 | 1059 | ||
904 | if (*prog->argv[argc]) { | 1060 | if (*prog->argv[argc_l]) { |
905 | argc++; | 1061 | argc_l++; |
906 | globLastArgument(prog, &argc, &argvAlloced); | 1062 | globLastArgument(prog, &argc_l, &argvAlloced); |
907 | } | 1063 | } |
908 | if (!argc) { | 1064 | if (!argc_l) { |
909 | freeJob(job); | 1065 | freeJob(job); |
910 | return 0; | 1066 | return 0; |
911 | } | 1067 | } |
912 | prog->argv[argc] = NULL; | 1068 | prog->argv[argc_l] = NULL; |
913 | 1069 | ||
914 | if (!returnCommand) { | 1070 | if (!returnCommand) { |
915 | job->text = xmalloc(strlen(*commandPtr) + 1); | 1071 | job->text = xmalloc(strlen(*commandPtr) + 1); |
@@ -991,17 +1147,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
991 | * works, but '/bin/cat' doesn't ) */ | 1147 | * works, but '/bin/cat' doesn't ) */ |
992 | while (a->name != 0) { | 1148 | while (a->name != 0) { |
993 | if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { | 1149 | if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { |
994 | int argc; | 1150 | int argc_l; |
995 | char** argv=newJob->progs[i].argv; | 1151 | char** argv=newJob->progs[i].argv; |
996 | for(argc=0;*argv!=NULL; argv++, argc++); | 1152 | for(argc_l=0;*argv!=NULL; argv++, argc_l++); |
997 | exit((*(a->main)) (argc, newJob->progs[i].argv)); | 1153 | exit((*(a->main)) (argc_l, newJob->progs[i].argv)); |
998 | } | 1154 | } |
999 | a++; | 1155 | a++; |
1000 | } | 1156 | } |
1001 | #endif | 1157 | #endif |
1002 | 1158 | ||
1003 | execvp(newJob->progs[i].argv[0], newJob->progs[i].argv); | 1159 | execvp(newJob->progs[i].argv[0], newJob->progs[i].argv); |
1004 | fatalError("sh: %s: %s\n", newJob->progs[i].argv[0], | 1160 | fatalError("%s: %s\n", newJob->progs[i].argv[0], |
1005 | strerror(errno)); | 1161 | strerror(errno)); |
1006 | } | 1162 | } |
1007 | if (outPipe[1]!=-1) { | 1163 | if (outPipe[1]!=-1) { |
@@ -1048,6 +1204,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1048 | to the list of backgrounded theJobs and leave it alone */ | 1204 | to the list of backgrounded theJobs and leave it alone */ |
1049 | printf("[%d] %d\n", theJob->jobId, | 1205 | printf("[%d] %d\n", theJob->jobId, |
1050 | newJob->progs[newJob->numProgs - 1].pid); | 1206 | newJob->progs[newJob->numProgs - 1].pid); |
1207 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1208 | lastBgPid=newJob->progs[newJob->numProgs - 1].pid; | ||
1209 | #endif | ||
1051 | } else { | 1210 | } else { |
1052 | jobList->fg = theJob; | 1211 | jobList->fg = theJob; |
1053 | 1212 | ||
@@ -1060,45 +1219,6 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1060 | return 0; | 1219 | return 0; |
1061 | } | 1220 | } |
1062 | 1221 | ||
1063 | static int setupRedirections(struct childProgram *prog) | ||
1064 | { | ||
1065 | int i; | ||
1066 | int openfd; | ||
1067 | int mode = O_RDONLY; | ||
1068 | struct redirectionSpecifier *redir = prog->redirections; | ||
1069 | |||
1070 | for (i = 0; i < prog->numRedirections; i++, redir++) { | ||
1071 | switch (redir->type) { | ||
1072 | case REDIRECT_INPUT: | ||
1073 | mode = O_RDONLY; | ||
1074 | break; | ||
1075 | case REDIRECT_OVERWRITE: | ||
1076 | mode = O_RDWR | O_CREAT | O_TRUNC; | ||
1077 | break; | ||
1078 | case REDIRECT_APPEND: | ||
1079 | mode = O_RDWR | O_CREAT | O_APPEND; | ||
1080 | break; | ||
1081 | } | ||
1082 | |||
1083 | openfd = open(redir->filename, mode, 0666); | ||
1084 | if (openfd < 0) { | ||
1085 | /* this could get lost if stderr has been redirected, but | ||
1086 | bash and ash both lose it as well (though zsh doesn't!) */ | ||
1087 | errorMsg("error opening %s: %s\n", redir->filename, | ||
1088 | strerror(errno)); | ||
1089 | return 1; | ||
1090 | } | ||
1091 | |||
1092 | if (openfd != redir->fd) { | ||
1093 | dup2(openfd, redir->fd); | ||
1094 | close(openfd); | ||
1095 | } | ||
1096 | } | ||
1097 | |||
1098 | return 0; | ||
1099 | } | ||
1100 | |||
1101 | |||
1102 | static int busy_loop(FILE * input) | 1222 | static int busy_loop(FILE * input) |
1103 | { | 1223 | { |
1104 | char *command; | 1224 | char *command; |
@@ -1106,8 +1226,9 @@ static int busy_loop(FILE * input) | |||
1106 | struct job newJob; | 1226 | struct job newJob; |
1107 | pid_t parent_pgrp; | 1227 | pid_t parent_pgrp; |
1108 | int i; | 1228 | int i; |
1109 | int status; | ||
1110 | int inBg; | 1229 | int inBg; |
1230 | int status; | ||
1231 | newJob.jobContext = REGULAR_JOB_CONTEXT; | ||
1111 | 1232 | ||
1112 | /* save current owner of TTY so we can restore it on exit */ | 1233 | /* save current owner of TTY so we can restore it on exit */ |
1113 | parent_pgrp = tcgetpgrp(0); | 1234 | parent_pgrp = tcgetpgrp(0); |
@@ -1160,6 +1281,9 @@ static int busy_loop(FILE * input) | |||
1160 | removeJob(&jobList, jobList.fg); | 1281 | removeJob(&jobList, jobList.fg); |
1161 | jobList.fg = NULL; | 1282 | jobList.fg = NULL; |
1162 | } | 1283 | } |
1284 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1285 | lastReturnCode=WEXITSTATUS(status); | ||
1286 | #endif | ||
1163 | } else { | 1287 | } else { |
1164 | /* the child was stopped */ | 1288 | /* the child was stopped */ |
1165 | jobList.fg->stoppedProgs++; | 1289 | jobList.fg->stoppedProgs++; |
@@ -1211,9 +1335,11 @@ void free_memory(void) | |||
1211 | #endif | 1335 | #endif |
1212 | 1336 | ||
1213 | 1337 | ||
1214 | int shell_main(int argc, char **argv) | 1338 | int shell_main(int argc_l, char **argv_l) |
1215 | { | 1339 | { |
1216 | FILE *input = stdin; | 1340 | FILE *input = stdin; |
1341 | argc = argc_l; | ||
1342 | argv = argv_l; | ||
1217 | 1343 | ||
1218 | /* initialize the cwd -- this is never freed...*/ | 1344 | /* initialize the cwd -- this is never freed...*/ |
1219 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); | 1345 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); |
@@ -26,9 +26,9 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | 28 | ||
29 | #define BB_FEATURE_SH_BACKTICKS | 29 | //#define BB_FEATURE_SH_BACKTICKS |
30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS | 30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS |
31 | 31 | //#define BB_FEATURE_SH_ENVIRONMENT | |
32 | 32 | ||
33 | 33 | ||
34 | #include "internal.h" | 34 | #include "internal.h" |
@@ -57,13 +57,11 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | |||
57 | }; | 57 | }; |
58 | 58 | ||
59 | static const unsigned int REGULAR_JOB_CONTEXT=0x1; | 59 | static const unsigned int REGULAR_JOB_CONTEXT=0x1; |
60 | static const unsigned int IF_EXP_CONTEXT=0x2; | 60 | static const unsigned int IF_TRUE_CONTEXT=0x2; |
61 | static const unsigned int THEN_EXP_CONTEXT=0x4; | 61 | static const unsigned int IF_FALSE_CONTEXT=0x4; |
62 | static const unsigned int ELSE_EXP_CONTEXT=0x8; | 62 | static const unsigned int THEN_EXP_CONTEXT=0x8; |
63 | 63 | static const unsigned int ELSE_EXP_CONTEXT=0x10; | |
64 | 64 | ||
65 | enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT | ||
66 | }; | ||
67 | 65 | ||
68 | struct jobSet { | 66 | struct jobSet { |
69 | struct job *head; /* head of list of running jobs */ | 67 | struct job *head; /* head of list of running jobs */ |
@@ -128,8 +126,7 @@ static int builtin_fi(struct job *cmd, struct jobSet *junk); | |||
128 | /* function prototypes for shell stuff */ | 126 | /* function prototypes for shell stuff */ |
129 | static void checkJobs(struct jobSet *jobList); | 127 | static void checkJobs(struct jobSet *jobList); |
130 | static int getCommand(FILE * source, char *command); | 128 | static int getCommand(FILE * source, char *command); |
131 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg); | 129 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg); |
132 | static int setupRedirections(struct childProgram *prog); | ||
133 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); | 130 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); |
134 | static int busy_loop(FILE * input); | 131 | static int busy_loop(FILE * input); |
135 | 132 | ||
@@ -146,6 +143,12 @@ static struct builtInCommand bltins[] = { | |||
146 | {"export", "Set environment variable", builtin_export}, | 143 | {"export", "Set environment variable", builtin_export}, |
147 | {"unset", "Unset environment variable", builtin_unset}, | 144 | {"unset", "Unset environment variable", builtin_unset}, |
148 | {"read", "Input environment variable", builtin_read}, | 145 | {"read", "Input environment variable", builtin_read}, |
146 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
147 | {"if", NULL, builtin_if}, | ||
148 | {"then", NULL, builtin_then}, | ||
149 | {"else", NULL, builtin_else}, | ||
150 | {"fi", NULL, builtin_fi}, | ||
151 | #endif | ||
149 | {NULL, NULL, NULL} | 152 | {NULL, NULL, NULL} |
150 | }; | 153 | }; |
151 | 154 | ||
@@ -154,12 +157,6 @@ static struct builtInCommand bltins[] = { | |||
154 | static struct builtInCommand bltins_forking[] = { | 157 | static struct builtInCommand bltins_forking[] = { |
155 | {"env", "Print all environment variables", builtin_env}, | 158 | {"env", "Print all environment variables", builtin_env}, |
156 | {"pwd", "Print current directory", builtin_pwd}, | 159 | {"pwd", "Print current directory", builtin_pwd}, |
157 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
158 | {"if", NULL, builtin_if}, | ||
159 | {"then", NULL, builtin_then}, | ||
160 | {"else", NULL, builtin_else}, | ||
161 | {"fi", NULL, builtin_fi}, | ||
162 | #endif | ||
163 | {".", "Source-in and run commands in a file", builtin_source}, | 160 | {".", "Source-in and run commands in a file", builtin_source}, |
164 | {"help", "List shell built-in commands", builtin_help}, | 161 | {"help", "List shell built-in commands", builtin_help}, |
165 | {NULL, NULL, NULL} | 162 | {NULL, NULL, NULL} |
@@ -170,6 +167,13 @@ static char *cwd; | |||
170 | static char *local_pending_command = NULL; | 167 | static char *local_pending_command = NULL; |
171 | static char *promptStr = NULL; | 168 | static char *promptStr = NULL; |
172 | static struct jobSet jobList = { NULL, NULL }; | 169 | static struct jobSet jobList = { NULL, NULL }; |
170 | static int argc; | ||
171 | static char **argv; | ||
172 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
173 | static int lastBgPid=-1; | ||
174 | static int lastReturnCode=-1; | ||
175 | #endif | ||
176 | |||
173 | 177 | ||
174 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 178 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
175 | void win_changed(int junk) | 179 | void win_changed(int junk) |
@@ -369,38 +373,91 @@ static int builtin_read(struct job *cmd, struct jobSet *junk) | |||
369 | 373 | ||
370 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | 374 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS |
371 | /* Built-in handler for 'if' commands */ | 375 | /* Built-in handler for 'if' commands */ |
372 | static int builtin_if(struct job *cmd, struct jobSet *junk) | 376 | static int builtin_if(struct job *cmd, struct jobSet *jobList) |
373 | { | 377 | { |
374 | cmd->jobContext |= IF_EXP_CONTEXT; | 378 | int status; |
375 | printf("Hit an if -- jobContext=%d\n", cmd->jobContext); | 379 | char* charptr1=cmd->text+3; /* skip over the leading 'if ' */ |
376 | return TRUE; | 380 | |
381 | /* Now run the 'if' command */ | ||
382 | status=strlen(charptr1); | ||
383 | local_pending_command = xmalloc(status+1); | ||
384 | strncpy(local_pending_command, charptr1, status); | ||
385 | printf("'if' now running '%s'\n", charptr1); | ||
386 | status = busy_loop(NULL); /* Frees local_pending_command */ | ||
387 | printf("if test returned "); | ||
388 | if (status == 0) { | ||
389 | printf("TRUE\n"); | ||
390 | cmd->jobContext |= IF_TRUE_CONTEXT; | ||
391 | } else { | ||
392 | printf("FALSE\n"); | ||
393 | cmd->jobContext |= IF_FALSE_CONTEXT; | ||
394 | } | ||
395 | |||
396 | return status; | ||
377 | } | 397 | } |
378 | 398 | ||
379 | /* Built-in handler for 'then' (part of the 'if' command) */ | 399 | /* Built-in handler for 'then' (part of the 'if' command) */ |
380 | static int builtin_then(struct job *cmd, struct jobSet *junk) | 400 | static int builtin_then(struct job *cmd, struct jobSet *junk) |
381 | { | 401 | { |
382 | if (cmd->jobContext & IF_EXP_CONTEXT) { | 402 | int status; |
383 | fprintf(stderr, "unexpected token `then'\n"); | 403 | char* charptr1=cmd->text+5; /* skip over the leading 'then ' */ |
384 | fflush(stderr); | 404 | |
405 | if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { | ||
406 | errorMsg("unexpected token `then'\n"); | ||
385 | return FALSE; | 407 | return FALSE; |
386 | } | 408 | } |
409 | /* If the if result was FALSE, skip the 'then' stuff */ | ||
410 | if (cmd->jobContext & IF_TRUE_CONTEXT) { | ||
411 | return TRUE; | ||
412 | } | ||
413 | |||
387 | cmd->jobContext |= THEN_EXP_CONTEXT; | 414 | cmd->jobContext |= THEN_EXP_CONTEXT; |
388 | printf("Hit an then -- jobContext=%d\n", cmd->jobContext); | 415 | //printf("Hit an then -- jobContext=%d\n", cmd->jobContext); |
389 | return TRUE; | 416 | |
417 | /* Now run the 'then' command */ | ||
418 | status=strlen(charptr1); | ||
419 | local_pending_command = xmalloc(status+1); | ||
420 | strncpy(local_pending_command, charptr1, status); | ||
421 | printf("'then' now running '%s'\n", charptr1); | ||
422 | return( busy_loop(NULL)); | ||
390 | } | 423 | } |
391 | 424 | ||
392 | /* Built-in handler for 'else' (part of the 'if' command) */ | 425 | /* Built-in handler for 'else' (part of the 'if' command) */ |
393 | static int builtin_else(struct job *cmd, struct jobSet *junk) | 426 | static int builtin_else(struct job *cmd, struct jobSet *junk) |
394 | { | 427 | { |
395 | printf("Hit an else\n"); | 428 | int status; |
429 | char* charptr1=cmd->text+5; /* skip over the leading 'else ' */ | ||
430 | |||
431 | if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { | ||
432 | errorMsg("unexpected token `else'\n"); | ||
433 | return FALSE; | ||
434 | } | ||
435 | /* If the if result was TRUE, skip the 'else' stuff */ | ||
436 | if (cmd->jobContext & IF_FALSE_CONTEXT) { | ||
437 | return TRUE; | ||
438 | } | ||
439 | |||
396 | cmd->jobContext |= ELSE_EXP_CONTEXT; | 440 | cmd->jobContext |= ELSE_EXP_CONTEXT; |
397 | return TRUE; | 441 | //printf("Hit an else -- jobContext=%d\n", cmd->jobContext); |
442 | |||
443 | /* Now run the 'else' command */ | ||
444 | status=strlen(charptr1); | ||
445 | local_pending_command = xmalloc(status+1); | ||
446 | strncpy(local_pending_command, charptr1, status); | ||
447 | printf("'else' now running '%s'\n", charptr1); | ||
448 | return( busy_loop(NULL)); | ||
398 | } | 449 | } |
399 | 450 | ||
400 | /* Built-in handler for 'fi' (part of the 'if' command) */ | 451 | /* Built-in handler for 'fi' (part of the 'if' command) */ |
401 | static int builtin_fi(struct job *cmd, struct jobSet *junk) | 452 | static int builtin_fi(struct job *cmd, struct jobSet *junk) |
402 | { | 453 | { |
403 | printf("Hit an fi\n"); | 454 | if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { |
455 | errorMsg("unexpected token `fi'\n"); | ||
456 | return FALSE; | ||
457 | } | ||
458 | /* Clear out the if and then context bits */ | ||
459 | cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); | ||
460 | printf("Hit an fi -- jobContext=%d\n", cmd->jobContext); | ||
404 | return TRUE; | 461 | return TRUE; |
405 | } | 462 | } |
406 | #endif | 463 | #endif |
@@ -521,6 +578,45 @@ static void checkJobs(struct jobSet *jobList) | |||
521 | perror("waitpid"); | 578 | perror("waitpid"); |
522 | } | 579 | } |
523 | 580 | ||
581 | static int setupRedirections(struct childProgram *prog) | ||
582 | { | ||
583 | int i; | ||
584 | int openfd; | ||
585 | int mode = O_RDONLY; | ||
586 | struct redirectionSpecifier *redir = prog->redirections; | ||
587 | |||
588 | for (i = 0; i < prog->numRedirections; i++, redir++) { | ||
589 | switch (redir->type) { | ||
590 | case REDIRECT_INPUT: | ||
591 | mode = O_RDONLY; | ||
592 | break; | ||
593 | case REDIRECT_OVERWRITE: | ||
594 | mode = O_RDWR | O_CREAT | O_TRUNC; | ||
595 | break; | ||
596 | case REDIRECT_APPEND: | ||
597 | mode = O_RDWR | O_CREAT | O_APPEND; | ||
598 | break; | ||
599 | } | ||
600 | |||
601 | openfd = open(redir->filename, mode, 0666); | ||
602 | if (openfd < 0) { | ||
603 | /* this could get lost if stderr has been redirected, but | ||
604 | bash and ash both lose it as well (though zsh doesn't!) */ | ||
605 | errorMsg("error opening %s: %s\n", redir->filename, | ||
606 | strerror(errno)); | ||
607 | return 1; | ||
608 | } | ||
609 | |||
610 | if (openfd != redir->fd) { | ||
611 | dup2(openfd, redir->fd); | ||
612 | close(openfd); | ||
613 | } | ||
614 | } | ||
615 | |||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | |||
524 | static int getCommand(FILE * source, char *command) | 620 | static int getCommand(FILE * source, char *command) |
525 | { | 621 | { |
526 | if (source == NULL) { | 622 | if (source == NULL) { |
@@ -562,17 +658,40 @@ static int getCommand(FILE * source, char *command) | |||
562 | return 0; | 658 | return 0; |
563 | } | 659 | } |
564 | 660 | ||
661 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
662 | #define __MAX_INT_CHARS 7 | ||
663 | static char* itoa(register int i) | ||
664 | { | ||
665 | static char a[__MAX_INT_CHARS]; | ||
666 | register char *b = a + sizeof(a) - 1; | ||
667 | int sign = (i < 0); | ||
668 | |||
669 | if (sign) | ||
670 | i = -i; | ||
671 | *b = 0; | ||
672 | do | ||
673 | { | ||
674 | *--b = '0' + (i % 10); | ||
675 | i /= 10; | ||
676 | } | ||
677 | while (i); | ||
678 | if (sign) | ||
679 | *--b = '-'; | ||
680 | return b; | ||
681 | } | ||
682 | #endif | ||
683 | |||
565 | static void globLastArgument(struct childProgram *prog, int *argcPtr, | 684 | static void globLastArgument(struct childProgram *prog, int *argcPtr, |
566 | int *argcAllocedPtr) | 685 | int *argcAllocedPtr) |
567 | { | 686 | { |
568 | int argc = *argcPtr; | 687 | int argc_l = *argcPtr; |
569 | int argcAlloced = *argcAllocedPtr; | 688 | int argcAlloced = *argcAllocedPtr; |
570 | int rc; | 689 | int rc; |
571 | int flags; | 690 | int flags; |
572 | int i; | 691 | int i; |
573 | char *src, *dst, *var; | 692 | char *src, *dst, *var; |
574 | 693 | ||
575 | if (argc > 1) { /* cmd->globResult is already initialized */ | 694 | if (argc_l > 1) { /* cmd->globResult is already initialized */ |
576 | flags = GLOB_APPEND; | 695 | flags = GLOB_APPEND; |
577 | i = prog->globResult.gl_pathc; | 696 | i = prog->globResult.gl_pathc; |
578 | } else { | 697 | } else { |
@@ -581,19 +700,54 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr, | |||
581 | i = 0; | 700 | i = 0; |
582 | } | 701 | } |
583 | /* do shell variable substitution */ | 702 | /* do shell variable substitution */ |
584 | if(*prog->argv[argc - 1] == '$' && (var = getenv(prog->argv[argc - 1] + 1))) | 703 | if(*prog->argv[argc_l - 1] == '$') { |
585 | prog->argv[argc - 1] = var; | 704 | if ((var = getenv(prog->argv[argc_l - 1] + 1))) { |
705 | prog->argv[argc_l - 1] = var; | ||
706 | } | ||
707 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
708 | else { | ||
709 | switch(*(prog->argv[argc_l - 1] + 1)) { | ||
710 | case '?': | ||
711 | prog->argv[argc_l - 1] = itoa(lastReturnCode); | ||
712 | break; | ||
713 | case '$': | ||
714 | prog->argv[argc_l - 1] = itoa(getpid()); | ||
715 | break; | ||
716 | case '#': | ||
717 | prog->argv[argc_l - 1] = itoa(argc-1); | ||
718 | break; | ||
719 | case '!': | ||
720 | if (lastBgPid==-1) | ||
721 | *(prog->argv[argc_l - 1])='\0'; | ||
722 | else | ||
723 | prog->argv[argc_l - 1] = itoa(lastBgPid); | ||
724 | break; | ||
725 | case '0':case '1':case '2':case '3':case '4': | ||
726 | case '5':case '6':case '7':case '8':case '9': | ||
727 | { | ||
728 | int index=*(prog->argv[argc_l - 1] + 1)-48; | ||
729 | if (index >= argc) { | ||
730 | *(prog->argv[argc_l - 1])='\0'; | ||
731 | } else { | ||
732 | prog->argv[argc_l - 1] = argv[index]; | ||
733 | } | ||
734 | } | ||
735 | break; | ||
736 | } | ||
737 | } | ||
738 | #endif | ||
739 | } | ||
586 | 740 | ||
587 | rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult); | 741 | rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult); |
588 | if (rc == GLOB_NOSPACE) { | 742 | if (rc == GLOB_NOSPACE) { |
589 | errorMsg("out of space during glob operation\n"); | 743 | errorMsg("out of space during glob operation\n"); |
590 | return; | 744 | return; |
591 | } else if (rc == GLOB_NOMATCH || | 745 | } else if (rc == GLOB_NOMATCH || |
592 | (!rc && (prog->globResult.gl_pathc - i) == 1 && | 746 | (!rc && (prog->globResult.gl_pathc - i) == 1 && |
593 | strcmp(prog->argv[argc - 1], | 747 | strcmp(prog->argv[argc_l - 1], |
594 | prog->globResult.gl_pathv[i]) == 0)) { | 748 | prog->globResult.gl_pathv[i]) == 0)) { |
595 | /* we need to remove whatever \ quoting is still present */ | 749 | /* we need to remove whatever \ quoting is still present */ |
596 | src = dst = prog->argv[argc - 1]; | 750 | src = dst = prog->argv[argc_l - 1]; |
597 | while (*src) { | 751 | while (*src) { |
598 | if (*src != '\\') | 752 | if (*src != '\\') |
599 | *dst++ = *src; | 753 | *dst++ = *src; |
@@ -604,13 +758,13 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr, | |||
604 | argcAlloced += (prog->globResult.gl_pathc - i); | 758 | argcAlloced += (prog->globResult.gl_pathc - i); |
605 | prog->argv = | 759 | prog->argv = |
606 | realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); | 760 | realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); |
607 | memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, | 761 | memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i, |
608 | sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); | 762 | sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); |
609 | argc += (prog->globResult.gl_pathc - i - 1); | 763 | argc_l += (prog->globResult.gl_pathc - i - 1); |
610 | } | 764 | } |
611 | 765 | ||
612 | *argcAllocedPtr = argcAlloced; | 766 | *argcAllocedPtr = argcAlloced; |
613 | *argcPtr = argc; | 767 | *argcPtr = argc_l; |
614 | } | 768 | } |
615 | 769 | ||
616 | /* Return cmd->numProgs as 0 if no command is present (e.g. an empty | 770 | /* Return cmd->numProgs as 0 if no command is present (e.g. an empty |
@@ -618,12 +772,12 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr, | |||
618 | the beginning of the next command (if the original command had more | 772 | the beginning of the next command (if the original command had more |
619 | then one job associated with it) or NULL if no more commands are | 773 | then one job associated with it) or NULL if no more commands are |
620 | present. */ | 774 | present. */ |
621 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg) | 775 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg) |
622 | { | 776 | { |
623 | char *command; | 777 | char *command; |
624 | char *returnCommand = NULL; | 778 | char *returnCommand = NULL; |
625 | char *src, *buf, *chptr; | 779 | char *src, *buf, *chptr; |
626 | int argc = 0; | 780 | int argc_l = 0; |
627 | int done = 0; | 781 | int done = 0; |
628 | int argvAlloced; | 782 | int argvAlloced; |
629 | int i; | 783 | int i; |
@@ -641,7 +795,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
641 | return 0; | 795 | return 0; |
642 | } | 796 | } |
643 | 797 | ||
644 | *isBg = 0; | 798 | *inBg = 0; |
645 | job->numProgs = 1; | 799 | job->numProgs = 1; |
646 | job->progs = xmalloc(sizeof(*job->progs)); | 800 | job->progs = xmalloc(sizeof(*job->progs)); |
647 | 801 | ||
@@ -654,7 +808,6 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
654 | cleaner (though it is, admittedly, a tad less efficient) */ | 808 | cleaner (though it is, admittedly, a tad less efficient) */ |
655 | job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); | 809 | job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); |
656 | job->text = NULL; | 810 | job->text = NULL; |
657 | job->jobContext = REGULAR_JOB_CONTEXT; | ||
658 | 811 | ||
659 | prog = job->progs; | 812 | prog = job->progs; |
660 | prog->numRedirections = 0; | 813 | prog->numRedirections = 0; |
@@ -687,17 +840,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
687 | *src == ']') *buf++ = '\\'; | 840 | *src == ']') *buf++ = '\\'; |
688 | *buf++ = *src; | 841 | *buf++ = *src; |
689 | } else if (isspace(*src)) { | 842 | } else if (isspace(*src)) { |
690 | if (*prog->argv[argc]) { | 843 | if (*prog->argv[argc_l]) { |
691 | buf++, argc++; | 844 | buf++, argc_l++; |
692 | /* +1 here leaves room for the NULL which ends argv */ | 845 | /* +1 here leaves room for the NULL which ends argv */ |
693 | if ((argc + 1) == argvAlloced) { | 846 | if ((argc_l + 1) == argvAlloced) { |
694 | argvAlloced += 5; | 847 | argvAlloced += 5; |
695 | prog->argv = realloc(prog->argv, | 848 | prog->argv = realloc(prog->argv, |
696 | sizeof(*prog->argv) * | 849 | sizeof(*prog->argv) * |
697 | argvAlloced); | 850 | argvAlloced); |
698 | } | 851 | } |
699 | globLastArgument(prog, &argc, &argvAlloced); | 852 | globLastArgument(prog, &argc_l, &argvAlloced); |
700 | prog->argv[argc] = buf; | 853 | prog->argv[argc_l] = buf; |
701 | } | 854 | } |
702 | } else | 855 | } else |
703 | switch (*src) { | 856 | switch (*src) { |
@@ -707,7 +860,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
707 | break; | 860 | break; |
708 | 861 | ||
709 | case '#': /* comment */ | 862 | case '#': /* comment */ |
710 | done = 1; | 863 | if (*(src-1)== '$') |
864 | *buf++ = *src; | ||
865 | else | ||
866 | done = 1; | ||
711 | break; | 867 | break; |
712 | 868 | ||
713 | case '>': /* redirections */ | 869 | case '>': /* redirections */ |
@@ -718,16 +874,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
718 | (i + 1)); | 874 | (i + 1)); |
719 | 875 | ||
720 | prog->redirections[i].fd = -1; | 876 | prog->redirections[i].fd = -1; |
721 | if (buf != prog->argv[argc]) { | 877 | if (buf != prog->argv[argc_l]) { |
722 | /* the stuff before this character may be the file number | 878 | /* the stuff before this character may be the file number |
723 | being redirected */ | 879 | being redirected */ |
724 | prog->redirections[i].fd = | 880 | prog->redirections[i].fd = |
725 | strtol(prog->argv[argc], &chptr, 10); | 881 | strtol(prog->argv[argc_l], &chptr, 10); |
726 | 882 | ||
727 | if (*chptr && *prog->argv[argc]) { | 883 | if (*chptr && *prog->argv[argc_l]) { |
728 | buf++, argc++; | 884 | buf++, argc_l++; |
729 | globLastArgument(prog, &argc, &argvAlloced); | 885 | globLastArgument(prog, &argc_l, &argvAlloced); |
730 | prog->argv[argc] = buf; | 886 | prog->argv[argc_l] = buf; |
731 | } | 887 | } |
732 | } | 888 | } |
733 | 889 | ||
@@ -765,20 +921,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
765 | *buf++ = *chptr++; | 921 | *buf++ = *chptr++; |
766 | 922 | ||
767 | src = chptr - 1; /* we src++ later */ | 923 | src = chptr - 1; /* we src++ later */ |
768 | prog->argv[argc] = ++buf; | 924 | prog->argv[argc_l] = ++buf; |
769 | break; | 925 | break; |
770 | 926 | ||
771 | case '|': /* pipe */ | 927 | case '|': /* pipe */ |
772 | /* finish this command */ | 928 | /* finish this command */ |
773 | if (*prog->argv[argc]) | 929 | if (*prog->argv[argc_l]) |
774 | argc++; | 930 | argc_l++; |
775 | if (!argc) { | 931 | if (!argc_l) { |
776 | errorMsg("empty command in pipe\n"); | 932 | errorMsg("empty command in pipe\n"); |
777 | freeJob(job); | 933 | freeJob(job); |
778 | job->numProgs=0; | 934 | job->numProgs=0; |
779 | return 1; | 935 | return 1; |
780 | } | 936 | } |
781 | prog->argv[argc] = NULL; | 937 | prog->argv[argc_l] = NULL; |
782 | 938 | ||
783 | /* and start the next */ | 939 | /* and start the next */ |
784 | job->numProgs++; | 940 | job->numProgs++; |
@@ -788,7 +944,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
788 | prog->numRedirections = 0; | 944 | prog->numRedirections = 0; |
789 | prog->redirections = NULL; | 945 | prog->redirections = NULL; |
790 | prog->freeGlob = 0; | 946 | prog->freeGlob = 0; |
791 | argc = 0; | 947 | argc_l = 0; |
792 | 948 | ||
793 | argvAlloced = 5; | 949 | argvAlloced = 5; |
794 | prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); | 950 | prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); |
@@ -809,7 +965,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
809 | break; | 965 | break; |
810 | 966 | ||
811 | case '&': /* background */ | 967 | case '&': /* background */ |
812 | *isBg = 1; | 968 | *inBg = 1; |
813 | case ';': /* multiple commands */ | 969 | case ';': /* multiple commands */ |
814 | done = 1; | 970 | done = 1; |
815 | returnCommand = *commandPtr + (src - *commandPtr) + 1; | 971 | returnCommand = *commandPtr + (src - *commandPtr) + 1; |
@@ -848,7 +1004,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
848 | snprintf(charptr1, 1+ptr-src, src); | 1004 | snprintf(charptr1, 1+ptr-src, src); |
849 | newJob = xmalloc(sizeof(struct job)); | 1005 | newJob = xmalloc(sizeof(struct job)); |
850 | /* Now parse and run the backticked command */ | 1006 | /* Now parse and run the backticked command */ |
851 | if (!parseCommand(&charptr1, newJob, &njobList, isBg) | 1007 | if (!parseCommand(&charptr1, newJob, &njobList, inBg) |
852 | && newJob->numProgs) { | 1008 | && newJob->numProgs) { |
853 | pipe(pipefd); | 1009 | pipe(pipefd); |
854 | runCommand(newJob, &njobList, 0, pipefd); | 1010 | runCommand(newJob, &njobList, 0, pipefd); |
@@ -890,7 +1046,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
890 | * and improved version of the command line with the backtick | 1046 | * and improved version of the command line with the backtick |
891 | * results expanded in place... */ | 1047 | * results expanded in place... */ |
892 | freeJob(job); | 1048 | freeJob(job); |
893 | return(parseCommand(commandPtr, job, jobList, isBg)); | 1049 | return(parseCommand(commandPtr, job, jobList, inBg)); |
894 | } | 1050 | } |
895 | break; | 1051 | break; |
896 | #endif // BB_FEATURE_SH_BACKTICKS | 1052 | #endif // BB_FEATURE_SH_BACKTICKS |
@@ -901,15 +1057,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
901 | src++; | 1057 | src++; |
902 | } | 1058 | } |
903 | 1059 | ||
904 | if (*prog->argv[argc]) { | 1060 | if (*prog->argv[argc_l]) { |
905 | argc++; | 1061 | argc_l++; |
906 | globLastArgument(prog, &argc, &argvAlloced); | 1062 | globLastArgument(prog, &argc_l, &argvAlloced); |
907 | } | 1063 | } |
908 | if (!argc) { | 1064 | if (!argc_l) { |
909 | freeJob(job); | 1065 | freeJob(job); |
910 | return 0; | 1066 | return 0; |
911 | } | 1067 | } |
912 | prog->argv[argc] = NULL; | 1068 | prog->argv[argc_l] = NULL; |
913 | 1069 | ||
914 | if (!returnCommand) { | 1070 | if (!returnCommand) { |
915 | job->text = xmalloc(strlen(*commandPtr) + 1); | 1071 | job->text = xmalloc(strlen(*commandPtr) + 1); |
@@ -991,17 +1147,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
991 | * works, but '/bin/cat' doesn't ) */ | 1147 | * works, but '/bin/cat' doesn't ) */ |
992 | while (a->name != 0) { | 1148 | while (a->name != 0) { |
993 | if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { | 1149 | if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { |
994 | int argc; | 1150 | int argc_l; |
995 | char** argv=newJob->progs[i].argv; | 1151 | char** argv=newJob->progs[i].argv; |
996 | for(argc=0;*argv!=NULL; argv++, argc++); | 1152 | for(argc_l=0;*argv!=NULL; argv++, argc_l++); |
997 | exit((*(a->main)) (argc, newJob->progs[i].argv)); | 1153 | exit((*(a->main)) (argc_l, newJob->progs[i].argv)); |
998 | } | 1154 | } |
999 | a++; | 1155 | a++; |
1000 | } | 1156 | } |
1001 | #endif | 1157 | #endif |
1002 | 1158 | ||
1003 | execvp(newJob->progs[i].argv[0], newJob->progs[i].argv); | 1159 | execvp(newJob->progs[i].argv[0], newJob->progs[i].argv); |
1004 | fatalError("sh: %s: %s\n", newJob->progs[i].argv[0], | 1160 | fatalError("%s: %s\n", newJob->progs[i].argv[0], |
1005 | strerror(errno)); | 1161 | strerror(errno)); |
1006 | } | 1162 | } |
1007 | if (outPipe[1]!=-1) { | 1163 | if (outPipe[1]!=-1) { |
@@ -1048,6 +1204,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1048 | to the list of backgrounded theJobs and leave it alone */ | 1204 | to the list of backgrounded theJobs and leave it alone */ |
1049 | printf("[%d] %d\n", theJob->jobId, | 1205 | printf("[%d] %d\n", theJob->jobId, |
1050 | newJob->progs[newJob->numProgs - 1].pid); | 1206 | newJob->progs[newJob->numProgs - 1].pid); |
1207 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1208 | lastBgPid=newJob->progs[newJob->numProgs - 1].pid; | ||
1209 | #endif | ||
1051 | } else { | 1210 | } else { |
1052 | jobList->fg = theJob; | 1211 | jobList->fg = theJob; |
1053 | 1212 | ||
@@ -1060,45 +1219,6 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1060 | return 0; | 1219 | return 0; |
1061 | } | 1220 | } |
1062 | 1221 | ||
1063 | static int setupRedirections(struct childProgram *prog) | ||
1064 | { | ||
1065 | int i; | ||
1066 | int openfd; | ||
1067 | int mode = O_RDONLY; | ||
1068 | struct redirectionSpecifier *redir = prog->redirections; | ||
1069 | |||
1070 | for (i = 0; i < prog->numRedirections; i++, redir++) { | ||
1071 | switch (redir->type) { | ||
1072 | case REDIRECT_INPUT: | ||
1073 | mode = O_RDONLY; | ||
1074 | break; | ||
1075 | case REDIRECT_OVERWRITE: | ||
1076 | mode = O_RDWR | O_CREAT | O_TRUNC; | ||
1077 | break; | ||
1078 | case REDIRECT_APPEND: | ||
1079 | mode = O_RDWR | O_CREAT | O_APPEND; | ||
1080 | break; | ||
1081 | } | ||
1082 | |||
1083 | openfd = open(redir->filename, mode, 0666); | ||
1084 | if (openfd < 0) { | ||
1085 | /* this could get lost if stderr has been redirected, but | ||
1086 | bash and ash both lose it as well (though zsh doesn't!) */ | ||
1087 | errorMsg("error opening %s: %s\n", redir->filename, | ||
1088 | strerror(errno)); | ||
1089 | return 1; | ||
1090 | } | ||
1091 | |||
1092 | if (openfd != redir->fd) { | ||
1093 | dup2(openfd, redir->fd); | ||
1094 | close(openfd); | ||
1095 | } | ||
1096 | } | ||
1097 | |||
1098 | return 0; | ||
1099 | } | ||
1100 | |||
1101 | |||
1102 | static int busy_loop(FILE * input) | 1222 | static int busy_loop(FILE * input) |
1103 | { | 1223 | { |
1104 | char *command; | 1224 | char *command; |
@@ -1106,8 +1226,9 @@ static int busy_loop(FILE * input) | |||
1106 | struct job newJob; | 1226 | struct job newJob; |
1107 | pid_t parent_pgrp; | 1227 | pid_t parent_pgrp; |
1108 | int i; | 1228 | int i; |
1109 | int status; | ||
1110 | int inBg; | 1229 | int inBg; |
1230 | int status; | ||
1231 | newJob.jobContext = REGULAR_JOB_CONTEXT; | ||
1111 | 1232 | ||
1112 | /* save current owner of TTY so we can restore it on exit */ | 1233 | /* save current owner of TTY so we can restore it on exit */ |
1113 | parent_pgrp = tcgetpgrp(0); | 1234 | parent_pgrp = tcgetpgrp(0); |
@@ -1160,6 +1281,9 @@ static int busy_loop(FILE * input) | |||
1160 | removeJob(&jobList, jobList.fg); | 1281 | removeJob(&jobList, jobList.fg); |
1161 | jobList.fg = NULL; | 1282 | jobList.fg = NULL; |
1162 | } | 1283 | } |
1284 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1285 | lastReturnCode=WEXITSTATUS(status); | ||
1286 | #endif | ||
1163 | } else { | 1287 | } else { |
1164 | /* the child was stopped */ | 1288 | /* the child was stopped */ |
1165 | jobList.fg->stoppedProgs++; | 1289 | jobList.fg->stoppedProgs++; |
@@ -1211,9 +1335,11 @@ void free_memory(void) | |||
1211 | #endif | 1335 | #endif |
1212 | 1336 | ||
1213 | 1337 | ||
1214 | int shell_main(int argc, char **argv) | 1338 | int shell_main(int argc_l, char **argv_l) |
1215 | { | 1339 | { |
1216 | FILE *input = stdin; | 1340 | FILE *input = stdin; |
1341 | argc = argc_l; | ||
1342 | argv = argv_l; | ||
1217 | 1343 | ||
1218 | /* initialize the cwd -- this is never freed...*/ | 1344 | /* initialize the cwd -- this is never freed...*/ |
1219 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); | 1345 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); |
diff --git a/shell/lash.c b/shell/lash.c index f746757d8..e57567608 100644 --- a/shell/lash.c +++ b/shell/lash.c | |||
@@ -26,9 +26,9 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | 28 | ||
29 | #define BB_FEATURE_SH_BACKTICKS | 29 | //#define BB_FEATURE_SH_BACKTICKS |
30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS | 30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS |
31 | 31 | //#define BB_FEATURE_SH_ENVIRONMENT | |
32 | 32 | ||
33 | 33 | ||
34 | #include "internal.h" | 34 | #include "internal.h" |
@@ -57,13 +57,11 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | |||
57 | }; | 57 | }; |
58 | 58 | ||
59 | static const unsigned int REGULAR_JOB_CONTEXT=0x1; | 59 | static const unsigned int REGULAR_JOB_CONTEXT=0x1; |
60 | static const unsigned int IF_EXP_CONTEXT=0x2; | 60 | static const unsigned int IF_TRUE_CONTEXT=0x2; |
61 | static const unsigned int THEN_EXP_CONTEXT=0x4; | 61 | static const unsigned int IF_FALSE_CONTEXT=0x4; |
62 | static const unsigned int ELSE_EXP_CONTEXT=0x8; | 62 | static const unsigned int THEN_EXP_CONTEXT=0x8; |
63 | 63 | static const unsigned int ELSE_EXP_CONTEXT=0x10; | |
64 | 64 | ||
65 | enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT | ||
66 | }; | ||
67 | 65 | ||
68 | struct jobSet { | 66 | struct jobSet { |
69 | struct job *head; /* head of list of running jobs */ | 67 | struct job *head; /* head of list of running jobs */ |
@@ -128,8 +126,7 @@ static int builtin_fi(struct job *cmd, struct jobSet *junk); | |||
128 | /* function prototypes for shell stuff */ | 126 | /* function prototypes for shell stuff */ |
129 | static void checkJobs(struct jobSet *jobList); | 127 | static void checkJobs(struct jobSet *jobList); |
130 | static int getCommand(FILE * source, char *command); | 128 | static int getCommand(FILE * source, char *command); |
131 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg); | 129 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg); |
132 | static int setupRedirections(struct childProgram *prog); | ||
133 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); | 130 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); |
134 | static int busy_loop(FILE * input); | 131 | static int busy_loop(FILE * input); |
135 | 132 | ||
@@ -146,6 +143,12 @@ static struct builtInCommand bltins[] = { | |||
146 | {"export", "Set environment variable", builtin_export}, | 143 | {"export", "Set environment variable", builtin_export}, |
147 | {"unset", "Unset environment variable", builtin_unset}, | 144 | {"unset", "Unset environment variable", builtin_unset}, |
148 | {"read", "Input environment variable", builtin_read}, | 145 | {"read", "Input environment variable", builtin_read}, |
146 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
147 | {"if", NULL, builtin_if}, | ||
148 | {"then", NULL, builtin_then}, | ||
149 | {"else", NULL, builtin_else}, | ||
150 | {"fi", NULL, builtin_fi}, | ||
151 | #endif | ||
149 | {NULL, NULL, NULL} | 152 | {NULL, NULL, NULL} |
150 | }; | 153 | }; |
151 | 154 | ||
@@ -154,12 +157,6 @@ static struct builtInCommand bltins[] = { | |||
154 | static struct builtInCommand bltins_forking[] = { | 157 | static struct builtInCommand bltins_forking[] = { |
155 | {"env", "Print all environment variables", builtin_env}, | 158 | {"env", "Print all environment variables", builtin_env}, |
156 | {"pwd", "Print current directory", builtin_pwd}, | 159 | {"pwd", "Print current directory", builtin_pwd}, |
157 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
158 | {"if", NULL, builtin_if}, | ||
159 | {"then", NULL, builtin_then}, | ||
160 | {"else", NULL, builtin_else}, | ||
161 | {"fi", NULL, builtin_fi}, | ||
162 | #endif | ||
163 | {".", "Source-in and run commands in a file", builtin_source}, | 160 | {".", "Source-in and run commands in a file", builtin_source}, |
164 | {"help", "List shell built-in commands", builtin_help}, | 161 | {"help", "List shell built-in commands", builtin_help}, |
165 | {NULL, NULL, NULL} | 162 | {NULL, NULL, NULL} |
@@ -170,6 +167,13 @@ static char *cwd; | |||
170 | static char *local_pending_command = NULL; | 167 | static char *local_pending_command = NULL; |
171 | static char *promptStr = NULL; | 168 | static char *promptStr = NULL; |
172 | static struct jobSet jobList = { NULL, NULL }; | 169 | static struct jobSet jobList = { NULL, NULL }; |
170 | static int argc; | ||
171 | static char **argv; | ||
172 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
173 | static int lastBgPid=-1; | ||
174 | static int lastReturnCode=-1; | ||
175 | #endif | ||
176 | |||
173 | 177 | ||
174 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 178 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
175 | void win_changed(int junk) | 179 | void win_changed(int junk) |
@@ -369,38 +373,91 @@ static int builtin_read(struct job *cmd, struct jobSet *junk) | |||
369 | 373 | ||
370 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | 374 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS |
371 | /* Built-in handler for 'if' commands */ | 375 | /* Built-in handler for 'if' commands */ |
372 | static int builtin_if(struct job *cmd, struct jobSet *junk) | 376 | static int builtin_if(struct job *cmd, struct jobSet *jobList) |
373 | { | 377 | { |
374 | cmd->jobContext |= IF_EXP_CONTEXT; | 378 | int status; |
375 | printf("Hit an if -- jobContext=%d\n", cmd->jobContext); | 379 | char* charptr1=cmd->text+3; /* skip over the leading 'if ' */ |
376 | return TRUE; | 380 | |
381 | /* Now run the 'if' command */ | ||
382 | status=strlen(charptr1); | ||
383 | local_pending_command = xmalloc(status+1); | ||
384 | strncpy(local_pending_command, charptr1, status); | ||
385 | printf("'if' now running '%s'\n", charptr1); | ||
386 | status = busy_loop(NULL); /* Frees local_pending_command */ | ||
387 | printf("if test returned "); | ||
388 | if (status == 0) { | ||
389 | printf("TRUE\n"); | ||
390 | cmd->jobContext |= IF_TRUE_CONTEXT; | ||
391 | } else { | ||
392 | printf("FALSE\n"); | ||
393 | cmd->jobContext |= IF_FALSE_CONTEXT; | ||
394 | } | ||
395 | |||
396 | return status; | ||
377 | } | 397 | } |
378 | 398 | ||
379 | /* Built-in handler for 'then' (part of the 'if' command) */ | 399 | /* Built-in handler for 'then' (part of the 'if' command) */ |
380 | static int builtin_then(struct job *cmd, struct jobSet *junk) | 400 | static int builtin_then(struct job *cmd, struct jobSet *junk) |
381 | { | 401 | { |
382 | if (cmd->jobContext & IF_EXP_CONTEXT) { | 402 | int status; |
383 | fprintf(stderr, "unexpected token `then'\n"); | 403 | char* charptr1=cmd->text+5; /* skip over the leading 'then ' */ |
384 | fflush(stderr); | 404 | |
405 | if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { | ||
406 | errorMsg("unexpected token `then'\n"); | ||
385 | return FALSE; | 407 | return FALSE; |
386 | } | 408 | } |
409 | /* If the if result was FALSE, skip the 'then' stuff */ | ||
410 | if (cmd->jobContext & IF_TRUE_CONTEXT) { | ||
411 | return TRUE; | ||
412 | } | ||
413 | |||
387 | cmd->jobContext |= THEN_EXP_CONTEXT; | 414 | cmd->jobContext |= THEN_EXP_CONTEXT; |
388 | printf("Hit an then -- jobContext=%d\n", cmd->jobContext); | 415 | //printf("Hit an then -- jobContext=%d\n", cmd->jobContext); |
389 | return TRUE; | 416 | |
417 | /* Now run the 'then' command */ | ||
418 | status=strlen(charptr1); | ||
419 | local_pending_command = xmalloc(status+1); | ||
420 | strncpy(local_pending_command, charptr1, status); | ||
421 | printf("'then' now running '%s'\n", charptr1); | ||
422 | return( busy_loop(NULL)); | ||
390 | } | 423 | } |
391 | 424 | ||
392 | /* Built-in handler for 'else' (part of the 'if' command) */ | 425 | /* Built-in handler for 'else' (part of the 'if' command) */ |
393 | static int builtin_else(struct job *cmd, struct jobSet *junk) | 426 | static int builtin_else(struct job *cmd, struct jobSet *junk) |
394 | { | 427 | { |
395 | printf("Hit an else\n"); | 428 | int status; |
429 | char* charptr1=cmd->text+5; /* skip over the leading 'else ' */ | ||
430 | |||
431 | if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { | ||
432 | errorMsg("unexpected token `else'\n"); | ||
433 | return FALSE; | ||
434 | } | ||
435 | /* If the if result was TRUE, skip the 'else' stuff */ | ||
436 | if (cmd->jobContext & IF_FALSE_CONTEXT) { | ||
437 | return TRUE; | ||
438 | } | ||
439 | |||
396 | cmd->jobContext |= ELSE_EXP_CONTEXT; | 440 | cmd->jobContext |= ELSE_EXP_CONTEXT; |
397 | return TRUE; | 441 | //printf("Hit an else -- jobContext=%d\n", cmd->jobContext); |
442 | |||
443 | /* Now run the 'else' command */ | ||
444 | status=strlen(charptr1); | ||
445 | local_pending_command = xmalloc(status+1); | ||
446 | strncpy(local_pending_command, charptr1, status); | ||
447 | printf("'else' now running '%s'\n", charptr1); | ||
448 | return( busy_loop(NULL)); | ||
398 | } | 449 | } |
399 | 450 | ||
400 | /* Built-in handler for 'fi' (part of the 'if' command) */ | 451 | /* Built-in handler for 'fi' (part of the 'if' command) */ |
401 | static int builtin_fi(struct job *cmd, struct jobSet *junk) | 452 | static int builtin_fi(struct job *cmd, struct jobSet *junk) |
402 | { | 453 | { |
403 | printf("Hit an fi\n"); | 454 | if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { |
455 | errorMsg("unexpected token `fi'\n"); | ||
456 | return FALSE; | ||
457 | } | ||
458 | /* Clear out the if and then context bits */ | ||
459 | cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); | ||
460 | printf("Hit an fi -- jobContext=%d\n", cmd->jobContext); | ||
404 | return TRUE; | 461 | return TRUE; |
405 | } | 462 | } |
406 | #endif | 463 | #endif |
@@ -521,6 +578,45 @@ static void checkJobs(struct jobSet *jobList) | |||
521 | perror("waitpid"); | 578 | perror("waitpid"); |
522 | } | 579 | } |
523 | 580 | ||
581 | static int setupRedirections(struct childProgram *prog) | ||
582 | { | ||
583 | int i; | ||
584 | int openfd; | ||
585 | int mode = O_RDONLY; | ||
586 | struct redirectionSpecifier *redir = prog->redirections; | ||
587 | |||
588 | for (i = 0; i < prog->numRedirections; i++, redir++) { | ||
589 | switch (redir->type) { | ||
590 | case REDIRECT_INPUT: | ||
591 | mode = O_RDONLY; | ||
592 | break; | ||
593 | case REDIRECT_OVERWRITE: | ||
594 | mode = O_RDWR | O_CREAT | O_TRUNC; | ||
595 | break; | ||
596 | case REDIRECT_APPEND: | ||
597 | mode = O_RDWR | O_CREAT | O_APPEND; | ||
598 | break; | ||
599 | } | ||
600 | |||
601 | openfd = open(redir->filename, mode, 0666); | ||
602 | if (openfd < 0) { | ||
603 | /* this could get lost if stderr has been redirected, but | ||
604 | bash and ash both lose it as well (though zsh doesn't!) */ | ||
605 | errorMsg("error opening %s: %s\n", redir->filename, | ||
606 | strerror(errno)); | ||
607 | return 1; | ||
608 | } | ||
609 | |||
610 | if (openfd != redir->fd) { | ||
611 | dup2(openfd, redir->fd); | ||
612 | close(openfd); | ||
613 | } | ||
614 | } | ||
615 | |||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | |||
524 | static int getCommand(FILE * source, char *command) | 620 | static int getCommand(FILE * source, char *command) |
525 | { | 621 | { |
526 | if (source == NULL) { | 622 | if (source == NULL) { |
@@ -562,17 +658,40 @@ static int getCommand(FILE * source, char *command) | |||
562 | return 0; | 658 | return 0; |
563 | } | 659 | } |
564 | 660 | ||
661 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
662 | #define __MAX_INT_CHARS 7 | ||
663 | static char* itoa(register int i) | ||
664 | { | ||
665 | static char a[__MAX_INT_CHARS]; | ||
666 | register char *b = a + sizeof(a) - 1; | ||
667 | int sign = (i < 0); | ||
668 | |||
669 | if (sign) | ||
670 | i = -i; | ||
671 | *b = 0; | ||
672 | do | ||
673 | { | ||
674 | *--b = '0' + (i % 10); | ||
675 | i /= 10; | ||
676 | } | ||
677 | while (i); | ||
678 | if (sign) | ||
679 | *--b = '-'; | ||
680 | return b; | ||
681 | } | ||
682 | #endif | ||
683 | |||
565 | static void globLastArgument(struct childProgram *prog, int *argcPtr, | 684 | static void globLastArgument(struct childProgram *prog, int *argcPtr, |
566 | int *argcAllocedPtr) | 685 | int *argcAllocedPtr) |
567 | { | 686 | { |
568 | int argc = *argcPtr; | 687 | int argc_l = *argcPtr; |
569 | int argcAlloced = *argcAllocedPtr; | 688 | int argcAlloced = *argcAllocedPtr; |
570 | int rc; | 689 | int rc; |
571 | int flags; | 690 | int flags; |
572 | int i; | 691 | int i; |
573 | char *src, *dst, *var; | 692 | char *src, *dst, *var; |
574 | 693 | ||
575 | if (argc > 1) { /* cmd->globResult is already initialized */ | 694 | if (argc_l > 1) { /* cmd->globResult is already initialized */ |
576 | flags = GLOB_APPEND; | 695 | flags = GLOB_APPEND; |
577 | i = prog->globResult.gl_pathc; | 696 | i = prog->globResult.gl_pathc; |
578 | } else { | 697 | } else { |
@@ -581,19 +700,54 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr, | |||
581 | i = 0; | 700 | i = 0; |
582 | } | 701 | } |
583 | /* do shell variable substitution */ | 702 | /* do shell variable substitution */ |
584 | if(*prog->argv[argc - 1] == '$' && (var = getenv(prog->argv[argc - 1] + 1))) | 703 | if(*prog->argv[argc_l - 1] == '$') { |
585 | prog->argv[argc - 1] = var; | 704 | if ((var = getenv(prog->argv[argc_l - 1] + 1))) { |
705 | prog->argv[argc_l - 1] = var; | ||
706 | } | ||
707 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
708 | else { | ||
709 | switch(*(prog->argv[argc_l - 1] + 1)) { | ||
710 | case '?': | ||
711 | prog->argv[argc_l - 1] = itoa(lastReturnCode); | ||
712 | break; | ||
713 | case '$': | ||
714 | prog->argv[argc_l - 1] = itoa(getpid()); | ||
715 | break; | ||
716 | case '#': | ||
717 | prog->argv[argc_l - 1] = itoa(argc-1); | ||
718 | break; | ||
719 | case '!': | ||
720 | if (lastBgPid==-1) | ||
721 | *(prog->argv[argc_l - 1])='\0'; | ||
722 | else | ||
723 | prog->argv[argc_l - 1] = itoa(lastBgPid); | ||
724 | break; | ||
725 | case '0':case '1':case '2':case '3':case '4': | ||
726 | case '5':case '6':case '7':case '8':case '9': | ||
727 | { | ||
728 | int index=*(prog->argv[argc_l - 1] + 1)-48; | ||
729 | if (index >= argc) { | ||
730 | *(prog->argv[argc_l - 1])='\0'; | ||
731 | } else { | ||
732 | prog->argv[argc_l - 1] = argv[index]; | ||
733 | } | ||
734 | } | ||
735 | break; | ||
736 | } | ||
737 | } | ||
738 | #endif | ||
739 | } | ||
586 | 740 | ||
587 | rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult); | 741 | rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult); |
588 | if (rc == GLOB_NOSPACE) { | 742 | if (rc == GLOB_NOSPACE) { |
589 | errorMsg("out of space during glob operation\n"); | 743 | errorMsg("out of space during glob operation\n"); |
590 | return; | 744 | return; |
591 | } else if (rc == GLOB_NOMATCH || | 745 | } else if (rc == GLOB_NOMATCH || |
592 | (!rc && (prog->globResult.gl_pathc - i) == 1 && | 746 | (!rc && (prog->globResult.gl_pathc - i) == 1 && |
593 | strcmp(prog->argv[argc - 1], | 747 | strcmp(prog->argv[argc_l - 1], |
594 | prog->globResult.gl_pathv[i]) == 0)) { | 748 | prog->globResult.gl_pathv[i]) == 0)) { |
595 | /* we need to remove whatever \ quoting is still present */ | 749 | /* we need to remove whatever \ quoting is still present */ |
596 | src = dst = prog->argv[argc - 1]; | 750 | src = dst = prog->argv[argc_l - 1]; |
597 | while (*src) { | 751 | while (*src) { |
598 | if (*src != '\\') | 752 | if (*src != '\\') |
599 | *dst++ = *src; | 753 | *dst++ = *src; |
@@ -604,13 +758,13 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr, | |||
604 | argcAlloced += (prog->globResult.gl_pathc - i); | 758 | argcAlloced += (prog->globResult.gl_pathc - i); |
605 | prog->argv = | 759 | prog->argv = |
606 | realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); | 760 | realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); |
607 | memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, | 761 | memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i, |
608 | sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); | 762 | sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); |
609 | argc += (prog->globResult.gl_pathc - i - 1); | 763 | argc_l += (prog->globResult.gl_pathc - i - 1); |
610 | } | 764 | } |
611 | 765 | ||
612 | *argcAllocedPtr = argcAlloced; | 766 | *argcAllocedPtr = argcAlloced; |
613 | *argcPtr = argc; | 767 | *argcPtr = argc_l; |
614 | } | 768 | } |
615 | 769 | ||
616 | /* Return cmd->numProgs as 0 if no command is present (e.g. an empty | 770 | /* Return cmd->numProgs as 0 if no command is present (e.g. an empty |
@@ -618,12 +772,12 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr, | |||
618 | the beginning of the next command (if the original command had more | 772 | the beginning of the next command (if the original command had more |
619 | then one job associated with it) or NULL if no more commands are | 773 | then one job associated with it) or NULL if no more commands are |
620 | present. */ | 774 | present. */ |
621 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg) | 775 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg) |
622 | { | 776 | { |
623 | char *command; | 777 | char *command; |
624 | char *returnCommand = NULL; | 778 | char *returnCommand = NULL; |
625 | char *src, *buf, *chptr; | 779 | char *src, *buf, *chptr; |
626 | int argc = 0; | 780 | int argc_l = 0; |
627 | int done = 0; | 781 | int done = 0; |
628 | int argvAlloced; | 782 | int argvAlloced; |
629 | int i; | 783 | int i; |
@@ -641,7 +795,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
641 | return 0; | 795 | return 0; |
642 | } | 796 | } |
643 | 797 | ||
644 | *isBg = 0; | 798 | *inBg = 0; |
645 | job->numProgs = 1; | 799 | job->numProgs = 1; |
646 | job->progs = xmalloc(sizeof(*job->progs)); | 800 | job->progs = xmalloc(sizeof(*job->progs)); |
647 | 801 | ||
@@ -654,7 +808,6 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
654 | cleaner (though it is, admittedly, a tad less efficient) */ | 808 | cleaner (though it is, admittedly, a tad less efficient) */ |
655 | job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); | 809 | job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); |
656 | job->text = NULL; | 810 | job->text = NULL; |
657 | job->jobContext = REGULAR_JOB_CONTEXT; | ||
658 | 811 | ||
659 | prog = job->progs; | 812 | prog = job->progs; |
660 | prog->numRedirections = 0; | 813 | prog->numRedirections = 0; |
@@ -687,17 +840,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
687 | *src == ']') *buf++ = '\\'; | 840 | *src == ']') *buf++ = '\\'; |
688 | *buf++ = *src; | 841 | *buf++ = *src; |
689 | } else if (isspace(*src)) { | 842 | } else if (isspace(*src)) { |
690 | if (*prog->argv[argc]) { | 843 | if (*prog->argv[argc_l]) { |
691 | buf++, argc++; | 844 | buf++, argc_l++; |
692 | /* +1 here leaves room for the NULL which ends argv */ | 845 | /* +1 here leaves room for the NULL which ends argv */ |
693 | if ((argc + 1) == argvAlloced) { | 846 | if ((argc_l + 1) == argvAlloced) { |
694 | argvAlloced += 5; | 847 | argvAlloced += 5; |
695 | prog->argv = realloc(prog->argv, | 848 | prog->argv = realloc(prog->argv, |
696 | sizeof(*prog->argv) * | 849 | sizeof(*prog->argv) * |
697 | argvAlloced); | 850 | argvAlloced); |
698 | } | 851 | } |
699 | globLastArgument(prog, &argc, &argvAlloced); | 852 | globLastArgument(prog, &argc_l, &argvAlloced); |
700 | prog->argv[argc] = buf; | 853 | prog->argv[argc_l] = buf; |
701 | } | 854 | } |
702 | } else | 855 | } else |
703 | switch (*src) { | 856 | switch (*src) { |
@@ -707,7 +860,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
707 | break; | 860 | break; |
708 | 861 | ||
709 | case '#': /* comment */ | 862 | case '#': /* comment */ |
710 | done = 1; | 863 | if (*(src-1)== '$') |
864 | *buf++ = *src; | ||
865 | else | ||
866 | done = 1; | ||
711 | break; | 867 | break; |
712 | 868 | ||
713 | case '>': /* redirections */ | 869 | case '>': /* redirections */ |
@@ -718,16 +874,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
718 | (i + 1)); | 874 | (i + 1)); |
719 | 875 | ||
720 | prog->redirections[i].fd = -1; | 876 | prog->redirections[i].fd = -1; |
721 | if (buf != prog->argv[argc]) { | 877 | if (buf != prog->argv[argc_l]) { |
722 | /* the stuff before this character may be the file number | 878 | /* the stuff before this character may be the file number |
723 | being redirected */ | 879 | being redirected */ |
724 | prog->redirections[i].fd = | 880 | prog->redirections[i].fd = |
725 | strtol(prog->argv[argc], &chptr, 10); | 881 | strtol(prog->argv[argc_l], &chptr, 10); |
726 | 882 | ||
727 | if (*chptr && *prog->argv[argc]) { | 883 | if (*chptr && *prog->argv[argc_l]) { |
728 | buf++, argc++; | 884 | buf++, argc_l++; |
729 | globLastArgument(prog, &argc, &argvAlloced); | 885 | globLastArgument(prog, &argc_l, &argvAlloced); |
730 | prog->argv[argc] = buf; | 886 | prog->argv[argc_l] = buf; |
731 | } | 887 | } |
732 | } | 888 | } |
733 | 889 | ||
@@ -765,20 +921,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
765 | *buf++ = *chptr++; | 921 | *buf++ = *chptr++; |
766 | 922 | ||
767 | src = chptr - 1; /* we src++ later */ | 923 | src = chptr - 1; /* we src++ later */ |
768 | prog->argv[argc] = ++buf; | 924 | prog->argv[argc_l] = ++buf; |
769 | break; | 925 | break; |
770 | 926 | ||
771 | case '|': /* pipe */ | 927 | case '|': /* pipe */ |
772 | /* finish this command */ | 928 | /* finish this command */ |
773 | if (*prog->argv[argc]) | 929 | if (*prog->argv[argc_l]) |
774 | argc++; | 930 | argc_l++; |
775 | if (!argc) { | 931 | if (!argc_l) { |
776 | errorMsg("empty command in pipe\n"); | 932 | errorMsg("empty command in pipe\n"); |
777 | freeJob(job); | 933 | freeJob(job); |
778 | job->numProgs=0; | 934 | job->numProgs=0; |
779 | return 1; | 935 | return 1; |
780 | } | 936 | } |
781 | prog->argv[argc] = NULL; | 937 | prog->argv[argc_l] = NULL; |
782 | 938 | ||
783 | /* and start the next */ | 939 | /* and start the next */ |
784 | job->numProgs++; | 940 | job->numProgs++; |
@@ -788,7 +944,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
788 | prog->numRedirections = 0; | 944 | prog->numRedirections = 0; |
789 | prog->redirections = NULL; | 945 | prog->redirections = NULL; |
790 | prog->freeGlob = 0; | 946 | prog->freeGlob = 0; |
791 | argc = 0; | 947 | argc_l = 0; |
792 | 948 | ||
793 | argvAlloced = 5; | 949 | argvAlloced = 5; |
794 | prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); | 950 | prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); |
@@ -809,7 +965,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
809 | break; | 965 | break; |
810 | 966 | ||
811 | case '&': /* background */ | 967 | case '&': /* background */ |
812 | *isBg = 1; | 968 | *inBg = 1; |
813 | case ';': /* multiple commands */ | 969 | case ';': /* multiple commands */ |
814 | done = 1; | 970 | done = 1; |
815 | returnCommand = *commandPtr + (src - *commandPtr) + 1; | 971 | returnCommand = *commandPtr + (src - *commandPtr) + 1; |
@@ -848,7 +1004,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
848 | snprintf(charptr1, 1+ptr-src, src); | 1004 | snprintf(charptr1, 1+ptr-src, src); |
849 | newJob = xmalloc(sizeof(struct job)); | 1005 | newJob = xmalloc(sizeof(struct job)); |
850 | /* Now parse and run the backticked command */ | 1006 | /* Now parse and run the backticked command */ |
851 | if (!parseCommand(&charptr1, newJob, &njobList, isBg) | 1007 | if (!parseCommand(&charptr1, newJob, &njobList, inBg) |
852 | && newJob->numProgs) { | 1008 | && newJob->numProgs) { |
853 | pipe(pipefd); | 1009 | pipe(pipefd); |
854 | runCommand(newJob, &njobList, 0, pipefd); | 1010 | runCommand(newJob, &njobList, 0, pipefd); |
@@ -890,7 +1046,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
890 | * and improved version of the command line with the backtick | 1046 | * and improved version of the command line with the backtick |
891 | * results expanded in place... */ | 1047 | * results expanded in place... */ |
892 | freeJob(job); | 1048 | freeJob(job); |
893 | return(parseCommand(commandPtr, job, jobList, isBg)); | 1049 | return(parseCommand(commandPtr, job, jobList, inBg)); |
894 | } | 1050 | } |
895 | break; | 1051 | break; |
896 | #endif // BB_FEATURE_SH_BACKTICKS | 1052 | #endif // BB_FEATURE_SH_BACKTICKS |
@@ -901,15 +1057,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
901 | src++; | 1057 | src++; |
902 | } | 1058 | } |
903 | 1059 | ||
904 | if (*prog->argv[argc]) { | 1060 | if (*prog->argv[argc_l]) { |
905 | argc++; | 1061 | argc_l++; |
906 | globLastArgument(prog, &argc, &argvAlloced); | 1062 | globLastArgument(prog, &argc_l, &argvAlloced); |
907 | } | 1063 | } |
908 | if (!argc) { | 1064 | if (!argc_l) { |
909 | freeJob(job); | 1065 | freeJob(job); |
910 | return 0; | 1066 | return 0; |
911 | } | 1067 | } |
912 | prog->argv[argc] = NULL; | 1068 | prog->argv[argc_l] = NULL; |
913 | 1069 | ||
914 | if (!returnCommand) { | 1070 | if (!returnCommand) { |
915 | job->text = xmalloc(strlen(*commandPtr) + 1); | 1071 | job->text = xmalloc(strlen(*commandPtr) + 1); |
@@ -991,17 +1147,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
991 | * works, but '/bin/cat' doesn't ) */ | 1147 | * works, but '/bin/cat' doesn't ) */ |
992 | while (a->name != 0) { | 1148 | while (a->name != 0) { |
993 | if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { | 1149 | if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { |
994 | int argc; | 1150 | int argc_l; |
995 | char** argv=newJob->progs[i].argv; | 1151 | char** argv=newJob->progs[i].argv; |
996 | for(argc=0;*argv!=NULL; argv++, argc++); | 1152 | for(argc_l=0;*argv!=NULL; argv++, argc_l++); |
997 | exit((*(a->main)) (argc, newJob->progs[i].argv)); | 1153 | exit((*(a->main)) (argc_l, newJob->progs[i].argv)); |
998 | } | 1154 | } |
999 | a++; | 1155 | a++; |
1000 | } | 1156 | } |
1001 | #endif | 1157 | #endif |
1002 | 1158 | ||
1003 | execvp(newJob->progs[i].argv[0], newJob->progs[i].argv); | 1159 | execvp(newJob->progs[i].argv[0], newJob->progs[i].argv); |
1004 | fatalError("sh: %s: %s\n", newJob->progs[i].argv[0], | 1160 | fatalError("%s: %s\n", newJob->progs[i].argv[0], |
1005 | strerror(errno)); | 1161 | strerror(errno)); |
1006 | } | 1162 | } |
1007 | if (outPipe[1]!=-1) { | 1163 | if (outPipe[1]!=-1) { |
@@ -1048,6 +1204,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1048 | to the list of backgrounded theJobs and leave it alone */ | 1204 | to the list of backgrounded theJobs and leave it alone */ |
1049 | printf("[%d] %d\n", theJob->jobId, | 1205 | printf("[%d] %d\n", theJob->jobId, |
1050 | newJob->progs[newJob->numProgs - 1].pid); | 1206 | newJob->progs[newJob->numProgs - 1].pid); |
1207 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1208 | lastBgPid=newJob->progs[newJob->numProgs - 1].pid; | ||
1209 | #endif | ||
1051 | } else { | 1210 | } else { |
1052 | jobList->fg = theJob; | 1211 | jobList->fg = theJob; |
1053 | 1212 | ||
@@ -1060,45 +1219,6 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1060 | return 0; | 1219 | return 0; |
1061 | } | 1220 | } |
1062 | 1221 | ||
1063 | static int setupRedirections(struct childProgram *prog) | ||
1064 | { | ||
1065 | int i; | ||
1066 | int openfd; | ||
1067 | int mode = O_RDONLY; | ||
1068 | struct redirectionSpecifier *redir = prog->redirections; | ||
1069 | |||
1070 | for (i = 0; i < prog->numRedirections; i++, redir++) { | ||
1071 | switch (redir->type) { | ||
1072 | case REDIRECT_INPUT: | ||
1073 | mode = O_RDONLY; | ||
1074 | break; | ||
1075 | case REDIRECT_OVERWRITE: | ||
1076 | mode = O_RDWR | O_CREAT | O_TRUNC; | ||
1077 | break; | ||
1078 | case REDIRECT_APPEND: | ||
1079 | mode = O_RDWR | O_CREAT | O_APPEND; | ||
1080 | break; | ||
1081 | } | ||
1082 | |||
1083 | openfd = open(redir->filename, mode, 0666); | ||
1084 | if (openfd < 0) { | ||
1085 | /* this could get lost if stderr has been redirected, but | ||
1086 | bash and ash both lose it as well (though zsh doesn't!) */ | ||
1087 | errorMsg("error opening %s: %s\n", redir->filename, | ||
1088 | strerror(errno)); | ||
1089 | return 1; | ||
1090 | } | ||
1091 | |||
1092 | if (openfd != redir->fd) { | ||
1093 | dup2(openfd, redir->fd); | ||
1094 | close(openfd); | ||
1095 | } | ||
1096 | } | ||
1097 | |||
1098 | return 0; | ||
1099 | } | ||
1100 | |||
1101 | |||
1102 | static int busy_loop(FILE * input) | 1222 | static int busy_loop(FILE * input) |
1103 | { | 1223 | { |
1104 | char *command; | 1224 | char *command; |
@@ -1106,8 +1226,9 @@ static int busy_loop(FILE * input) | |||
1106 | struct job newJob; | 1226 | struct job newJob; |
1107 | pid_t parent_pgrp; | 1227 | pid_t parent_pgrp; |
1108 | int i; | 1228 | int i; |
1109 | int status; | ||
1110 | int inBg; | 1229 | int inBg; |
1230 | int status; | ||
1231 | newJob.jobContext = REGULAR_JOB_CONTEXT; | ||
1111 | 1232 | ||
1112 | /* save current owner of TTY so we can restore it on exit */ | 1233 | /* save current owner of TTY so we can restore it on exit */ |
1113 | parent_pgrp = tcgetpgrp(0); | 1234 | parent_pgrp = tcgetpgrp(0); |
@@ -1160,6 +1281,9 @@ static int busy_loop(FILE * input) | |||
1160 | removeJob(&jobList, jobList.fg); | 1281 | removeJob(&jobList, jobList.fg); |
1161 | jobList.fg = NULL; | 1282 | jobList.fg = NULL; |
1162 | } | 1283 | } |
1284 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1285 | lastReturnCode=WEXITSTATUS(status); | ||
1286 | #endif | ||
1163 | } else { | 1287 | } else { |
1164 | /* the child was stopped */ | 1288 | /* the child was stopped */ |
1165 | jobList.fg->stoppedProgs++; | 1289 | jobList.fg->stoppedProgs++; |
@@ -1211,9 +1335,11 @@ void free_memory(void) | |||
1211 | #endif | 1335 | #endif |
1212 | 1336 | ||
1213 | 1337 | ||
1214 | int shell_main(int argc, char **argv) | 1338 | int shell_main(int argc_l, char **argv_l) |
1215 | { | 1339 | { |
1216 | FILE *input = stdin; | 1340 | FILE *input = stdin; |
1341 | argc = argc_l; | ||
1342 | argv = argv_l; | ||
1217 | 1343 | ||
1218 | /* initialize the cwd -- this is never freed...*/ | 1344 | /* initialize the cwd -- this is never freed...*/ |
1219 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); | 1345 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); |