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 /shell | |
| 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
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/lash.c | 352 |
1 files changed, 239 insertions, 113 deletions
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); |
