diff options
| author | Ron Yorston <rmy@pobox.com> | 2016-10-26 10:32:18 +0100 |
|---|---|---|
| committer | Ron Yorston <rmy@pobox.com> | 2016-10-26 10:32:18 +0100 |
| commit | 94eac583b29d56a28bf18d41f56ecb2a9d0bd336 (patch) | |
| tree | ff7f398db61a851d5e0af51a92004207707acfab /shell | |
| parent | 418f43bea899493bb70a6eec6429b3de412be6e7 (diff) | |
| parent | a513bf3c3ce0756c991b21c0ca271e24fedcdb51 (diff) | |
| download | busybox-w32-94eac583b29d56a28bf18d41f56ecb2a9d0bd336.tar.gz busybox-w32-94eac583b29d56a28bf18d41f56ecb2a9d0bd336.tar.bz2 busybox-w32-94eac583b29d56a28bf18d41f56ecb2a9d0bd336.zip | |
Merge branch 'busybox' into merge
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/ash.c | 178 | ||||
| -rw-r--r-- | shell/hush.c | 2 |
2 files changed, 85 insertions, 95 deletions
diff --git a/shell/ash.c b/shell/ash.c index 1485a35c9..a7b65ffc7 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
| @@ -367,8 +367,6 @@ struct globals_misc { | |||
| 367 | /* exceptions */ | 367 | /* exceptions */ |
| 368 | #define EXINT 0 /* SIGINT received */ | 368 | #define EXINT 0 /* SIGINT received */ |
| 369 | #define EXERROR 1 /* a generic error */ | 369 | #define EXERROR 1 /* a generic error */ |
| 370 | #define EXSHELLPROC 2 /* execute a shell procedure */ | ||
| 371 | #define EXEXEC 3 /* command execution failed */ | ||
| 372 | #define EXEXIT 4 /* exit the shell */ | 370 | #define EXEXIT 4 /* exit the shell */ |
| 373 | #define EXSIG 5 /* trapped signal in wait(1) */ | 371 | #define EXSIG 5 /* trapped signal in wait(1) */ |
| 374 | 372 | ||
| @@ -1471,7 +1469,6 @@ struct globals_memstack { | |||
| 1471 | char *g_stacknxt; // = stackbase.space; | 1469 | char *g_stacknxt; // = stackbase.space; |
| 1472 | char *sstrend; // = stackbase.space + MINSIZE; | 1470 | char *sstrend; // = stackbase.space + MINSIZE; |
| 1473 | size_t g_stacknleft; // = MINSIZE; | 1471 | size_t g_stacknleft; // = MINSIZE; |
| 1474 | int herefd; // = -1; | ||
| 1475 | struct stack_block stackbase; | 1472 | struct stack_block stackbase; |
| 1476 | }; | 1473 | }; |
| 1477 | extern struct globals_memstack *const ash_ptr_to_globals_memstack; | 1474 | extern struct globals_memstack *const ash_ptr_to_globals_memstack; |
| @@ -1480,7 +1477,6 @@ extern struct globals_memstack *const ash_ptr_to_globals_memstack; | |||
| 1480 | #define g_stacknxt (G_memstack.g_stacknxt ) | 1477 | #define g_stacknxt (G_memstack.g_stacknxt ) |
| 1481 | #define sstrend (G_memstack.sstrend ) | 1478 | #define sstrend (G_memstack.sstrend ) |
| 1482 | #define g_stacknleft (G_memstack.g_stacknleft) | 1479 | #define g_stacknleft (G_memstack.g_stacknleft) |
| 1483 | #define herefd (G_memstack.herefd ) | ||
| 1484 | #define stackbase (G_memstack.stackbase ) | 1480 | #define stackbase (G_memstack.stackbase ) |
| 1485 | #define INIT_G_memstack() do { \ | 1481 | #define INIT_G_memstack() do { \ |
| 1486 | (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \ | 1482 | (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \ |
| @@ -1489,7 +1485,6 @@ extern struct globals_memstack *const ash_ptr_to_globals_memstack; | |||
| 1489 | g_stacknxt = stackbase.space; \ | 1485 | g_stacknxt = stackbase.space; \ |
| 1490 | g_stacknleft = MINSIZE; \ | 1486 | g_stacknleft = MINSIZE; \ |
| 1491 | sstrend = stackbase.space + MINSIZE; \ | 1487 | sstrend = stackbase.space + MINSIZE; \ |
| 1492 | herefd = -1; \ | ||
| 1493 | } while (0) | 1488 | } while (0) |
| 1494 | 1489 | ||
| 1495 | 1490 | ||
| @@ -1677,10 +1672,6 @@ static void * | |||
| 1677 | growstackstr(void) | 1672 | growstackstr(void) |
| 1678 | { | 1673 | { |
| 1679 | size_t len = stackblocksize(); | 1674 | size_t len = stackblocksize(); |
| 1680 | if (herefd >= 0 && len >= 1024) { | ||
| 1681 | full_write(herefd, stackblock(), len); | ||
| 1682 | return stackblock(); | ||
| 1683 | } | ||
| 1684 | growstackblock(); | 1675 | growstackblock(); |
| 1685 | return (char *)stackblock() + len; | 1676 | return (char *)stackblock() + len; |
| 1686 | } | 1677 | } |
| @@ -2030,7 +2021,6 @@ struct redirtab; | |||
| 2030 | struct globals_var { | 2021 | struct globals_var { |
| 2031 | struct shparam shellparam; /* $@ current positional parameters */ | 2022 | struct shparam shellparam; /* $@ current positional parameters */ |
| 2032 | struct redirtab *redirlist; | 2023 | struct redirtab *redirlist; |
| 2033 | int g_nullredirs; | ||
| 2034 | int preverrout_fd; /* save fd2 before print debug if xflag is set. */ | 2024 | int preverrout_fd; /* save fd2 before print debug if xflag is set. */ |
| 2035 | struct var *vartab[VTABSIZE]; | 2025 | struct var *vartab[VTABSIZE]; |
| 2036 | struct var varinit[ARRAY_SIZE(varinit_data)]; | 2026 | struct var varinit[ARRAY_SIZE(varinit_data)]; |
| @@ -2039,7 +2029,6 @@ extern struct globals_var *const ash_ptr_to_globals_var; | |||
| 2039 | #define G_var (*ash_ptr_to_globals_var) | 2029 | #define G_var (*ash_ptr_to_globals_var) |
| 2040 | #define shellparam (G_var.shellparam ) | 2030 | #define shellparam (G_var.shellparam ) |
| 2041 | //#define redirlist (G_var.redirlist ) | 2031 | //#define redirlist (G_var.redirlist ) |
| 2042 | #define g_nullredirs (G_var.g_nullredirs ) | ||
| 2043 | #define preverrout_fd (G_var.preverrout_fd) | 2032 | #define preverrout_fd (G_var.preverrout_fd) |
| 2044 | #define vartab (G_var.vartab ) | 2033 | #define vartab (G_var.vartab ) |
| 2045 | #define varinit (G_var.varinit ) | 2034 | #define varinit (G_var.varinit ) |
| @@ -2100,7 +2089,7 @@ extern struct globals_var *const ash_ptr_to_globals_var; | |||
| 2100 | static void FAST_FUNC | 2089 | static void FAST_FUNC |
| 2101 | getoptsreset(const char *value) | 2090 | getoptsreset(const char *value) |
| 2102 | { | 2091 | { |
| 2103 | shellparam.optind = number(value); | 2092 | shellparam.optind = number(value) ?: 1; |
| 2104 | shellparam.optoff = -1; | 2093 | shellparam.optoff = -1; |
| 2105 | } | 2094 | } |
| 2106 | #endif | 2095 | #endif |
| @@ -4963,8 +4952,7 @@ commandtext(union node *n) | |||
| 4963 | STARTSTACKSTR(cmdnextc); | 4952 | STARTSTACKSTR(cmdnextc); |
| 4964 | cmdtxt(n); | 4953 | cmdtxt(n); |
| 4965 | name = stackblock(); | 4954 | name = stackblock(); |
| 4966 | TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n", | 4955 | TRACE(("commandtext: name %p, end %p\n", name, cmdnextc)); |
| 4967 | name, cmdnextc, cmdnextc)); | ||
| 4968 | return ckstrdup(name); | 4956 | return ckstrdup(name); |
| 4969 | } | 4957 | } |
| 4970 | #endif /* JOBS */ | 4958 | #endif /* JOBS */ |
| @@ -5539,9 +5527,7 @@ openredirect(union node *redir) | |||
| 5539 | } | 5527 | } |
| 5540 | 5528 | ||
| 5541 | /* | 5529 | /* |
| 5542 | * Copy a file descriptor to be >= to. Returns -1 | 5530 | * Copy a file descriptor to be >= to. Throws exception on error. |
| 5543 | * if the source file descriptor is closed, EMPTY if there are no unused | ||
| 5544 | * file descriptors left. | ||
| 5545 | */ | 5531 | */ |
| 5546 | /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD). | 5532 | /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD). |
| 5547 | * old code was doing close(to) prior to copyfd() to achieve the same */ | 5533 | * old code was doing close(to) prior to copyfd() to achieve the same */ |
| @@ -5562,8 +5548,6 @@ copyfd(int from, int to) | |||
| 5562 | newfd = fcntl(from, F_DUPFD, to); | 5548 | newfd = fcntl(from, F_DUPFD, to); |
| 5563 | } | 5549 | } |
| 5564 | if (newfd < 0) { | 5550 | if (newfd < 0) { |
| 5565 | if (errno == EMFILE) | ||
| 5566 | return EMPTY; | ||
| 5567 | /* Happens when source fd is not open: try "echo >&99" */ | 5551 | /* Happens when source fd is not open: try "echo >&99" */ |
| 5568 | ash_msg_and_raise_error("%d: %m", from); | 5552 | ash_msg_and_raise_error("%d: %m", from); |
| 5569 | } | 5553 | } |
| @@ -5576,7 +5560,6 @@ struct two_fd_t { | |||
| 5576 | }; | 5560 | }; |
| 5577 | struct redirtab { | 5561 | struct redirtab { |
| 5578 | struct redirtab *next; | 5562 | struct redirtab *next; |
| 5579 | int nullredirs; | ||
| 5580 | int pair_count; | 5563 | int pair_count; |
| 5581 | struct two_fd_t two_fd[]; | 5564 | struct two_fd_t two_fd[]; |
| 5582 | }; | 5565 | }; |
| @@ -5655,7 +5638,6 @@ redirect(union node *redir, int flags) | |||
| 5655 | int newfd; | 5638 | int newfd; |
| 5656 | int copied_fd2 = -1; | 5639 | int copied_fd2 = -1; |
| 5657 | 5640 | ||
| 5658 | g_nullredirs++; | ||
| 5659 | if (!redir) { | 5641 | if (!redir) { |
| 5660 | return; | 5642 | return; |
| 5661 | } | 5643 | } |
| @@ -5677,8 +5659,6 @@ redirect(union node *redir, int flags) | |||
| 5677 | sv->next = redirlist; | 5659 | sv->next = redirlist; |
| 5678 | sv->pair_count = sv_pos; | 5660 | sv->pair_count = sv_pos; |
| 5679 | redirlist = sv; | 5661 | redirlist = sv; |
| 5680 | sv->nullredirs = g_nullredirs - 1; | ||
| 5681 | g_nullredirs = 0; | ||
| 5682 | while (sv_pos > 0) { | 5662 | while (sv_pos > 0) { |
| 5683 | sv_pos--; | 5663 | sv_pos--; |
| 5684 | sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY; | 5664 | sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY; |
| @@ -5790,7 +5770,7 @@ popredir(int drop, int restore) | |||
| 5790 | struct redirtab *rp; | 5770 | struct redirtab *rp; |
| 5791 | int i; | 5771 | int i; |
| 5792 | 5772 | ||
| 5793 | if (--g_nullredirs >= 0 || redirlist == NULL) | 5773 | if (redirlist == NULL) |
| 5794 | return; | 5774 | return; |
| 5795 | INT_OFF; | 5775 | INT_OFF; |
| 5796 | rp = redirlist; | 5776 | rp = redirlist; |
| @@ -5812,7 +5792,6 @@ popredir(int drop, int restore) | |||
| 5812 | } | 5792 | } |
| 5813 | } | 5793 | } |
| 5814 | redirlist = rp->next; | 5794 | redirlist = rp->next; |
| 5815 | g_nullredirs = rp->nullredirs; | ||
| 5816 | free(rp); | 5795 | free(rp); |
| 5817 | INT_ON; | 5796 | INT_ON; |
| 5818 | } | 5797 | } |
| @@ -5827,12 +5806,8 @@ popredir(int drop, int restore) | |||
| 5827 | static void | 5806 | static void |
| 5828 | clearredir(int drop) | 5807 | clearredir(int drop) |
| 5829 | { | 5808 | { |
| 5830 | for (;;) { | 5809 | while (redirlist) |
| 5831 | g_nullredirs = 0; | ||
| 5832 | if (!redirlist) | ||
| 5833 | break; | ||
| 5834 | popredir(drop, /*restore:*/ 0); | 5810 | popredir(drop, /*restore:*/ 0); |
| 5835 | } | ||
| 5836 | } | 5811 | } |
| 5837 | 5812 | ||
| 5838 | static int | 5813 | static int |
| @@ -5891,6 +5866,17 @@ ash_arith(const char *s) | |||
| 5891 | #define EXP_TILDE 0x2 /* do normal tilde expansion */ | 5866 | #define EXP_TILDE 0x2 /* do normal tilde expansion */ |
| 5892 | #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ | 5867 | #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ |
| 5893 | #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ | 5868 | #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ |
| 5869 | /* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt" | ||
| 5870 | * POSIX says for this case: | ||
| 5871 | * Pathname expansion shall not be performed on the word by a | ||
| 5872 | * non-interactive shell; an interactive shell may perform it, but shall | ||
| 5873 | * do so only when the expansion would result in one word. | ||
| 5874 | * Currently, our code complies to the above rule by never globbing | ||
| 5875 | * redirection filenames. | ||
| 5876 | * Bash performs globbing, unless it is non-interactive and in POSIX mode. | ||
| 5877 | * (this means that on a typical Linux distro, bash almost always | ||
| 5878 | * performs globbing, and thus diverges from what we do). | ||
| 5879 | */ | ||
| 5894 | #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ | 5880 | #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ |
| 5895 | #define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */ | 5881 | #define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */ |
| 5896 | #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ | 5882 | #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ |
| @@ -6236,52 +6222,54 @@ static int evaltree(union node *, int); | |||
| 6236 | static void FAST_FUNC | 6222 | static void FAST_FUNC |
| 6237 | evalbackcmd(union node *n, struct backcmd *result) | 6223 | evalbackcmd(union node *n, struct backcmd *result) |
| 6238 | { | 6224 | { |
| 6239 | int saveherefd; | 6225 | int pip[2]; |
| 6226 | struct job *jp; | ||
| 6240 | 6227 | ||
| 6241 | result->fd = -1; | 6228 | result->fd = -1; |
| 6242 | result->buf = NULL; | 6229 | result->buf = NULL; |
| 6243 | result->nleft = 0; | 6230 | result->nleft = 0; |
| 6244 | IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs))); | 6231 | IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs))); |
| 6245 | result->jp = NULL; | 6232 | result->jp = NULL; |
| 6246 | if (n == NULL) | 6233 | if (n == NULL) { |
| 6247 | goto out; | 6234 | goto out; |
| 6235 | } | ||
| 6248 | 6236 | ||
| 6249 | saveherefd = herefd; | 6237 | if (pipe(pip) < 0) |
| 6250 | herefd = -1; | 6238 | ash_msg_and_raise_error("pipe call failed"); |
| 6251 | 6239 | jp = makejob(/*n,*/ 1); | |
| 6252 | { | ||
| 6253 | int pip[2]; | ||
| 6254 | struct job *jp; | ||
| 6255 | |||
| 6256 | if (pipe(pip) < 0) | ||
| 6257 | ash_msg_and_raise_error("pipe call failed"); | ||
| 6258 | jp = makejob(/*n,*/ 1); | ||
| 6259 | #if ENABLE_PLATFORM_MINGW32 | 6240 | #if ENABLE_PLATFORM_MINGW32 |
| 6260 | result->fs.fpid = FS_EVALBACKCMD; | 6241 | result->fs.fpid = FS_EVALBACKCMD; |
| 6261 | result->fs.n = n; | 6242 | result->fs.n = n; |
| 6262 | result->fs.fd[0] = pip[0]; | 6243 | result->fs.fd[0] = pip[0]; |
| 6263 | result->fs.fd[1] = pip[1]; | 6244 | result->fs.fd[1] = pip[1]; |
| 6264 | if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0) | 6245 | if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0) |
| 6265 | ash_msg_and_raise_error("unable to spawn shell"); | 6246 | ash_msg_and_raise_error("unable to spawn shell"); |
| 6266 | #else | 6247 | #else |
| 6267 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 6248 | if (forkshell(jp, n, FORK_NOJOB) == 0) { |
| 6268 | FORCE_INT_ON; | 6249 | FORCE_INT_ON; |
| 6269 | close(pip[0]); | 6250 | close(pip[0]); |
| 6270 | if (pip[1] != 1) { | 6251 | if (pip[1] != 1) { |
| 6271 | /*close(1);*/ | 6252 | /*close(1);*/ |
| 6272 | copyfd(pip[1], 1 | COPYFD_EXACT); | 6253 | copyfd(pip[1], 1 | COPYFD_EXACT); |
| 6273 | close(pip[1]); | 6254 | close(pip[1]); |
| 6274 | } | ||
| 6275 | eflag = 0; | ||
| 6276 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | ||
| 6277 | /* NOTREACHED */ | ||
| 6278 | } | 6255 | } |
| 6279 | #endif | 6256 | /* TODO: eflag clearing makes the following not abort: |
| 6280 | close(pip[1]); | 6257 | * ash -c 'set -e; z=$(false;echo foo); echo $z' |
| 6281 | result->fd = pip[0]; | 6258 | * which is what bash does (unless it is in POSIX mode). |
| 6282 | result->jp = jp; | 6259 | * dash deleted "eflag = 0" line in the commit |
| 6260 | * Date: Mon, 28 Jun 2010 17:11:58 +1000 | ||
| 6261 | * [EVAL] Don't clear eflag in evalbackcmd | ||
| 6262 | * For now, preserve bash-like behavior, it seems to be somewhat more useful: | ||
| 6263 | */ | ||
| 6264 | eflag = 0; | ||
| 6265 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | ||
| 6266 | /* NOTREACHED */ | ||
| 6283 | } | 6267 | } |
| 6284 | herefd = saveherefd; | 6268 | #endif |
| 6269 | close(pip[1]); | ||
| 6270 | result->fd = pip[0]; | ||
| 6271 | result->jp = jp; | ||
| 6272 | |||
| 6285 | out: | 6273 | out: |
| 6286 | TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", | 6274 | TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", |
| 6287 | result->fd, result->buf, result->nleft, result->jp)); | 6275 | result->fd, result->buf, result->nleft, result->jp)); |
| @@ -6689,7 +6677,6 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
| 6689 | char *str; | 6677 | char *str; |
| 6690 | IF_ASH_BASH_COMPAT(char *repl = NULL;) | 6678 | IF_ASH_BASH_COMPAT(char *repl = NULL;) |
| 6691 | IF_ASH_BASH_COMPAT(int pos, len, orig_len;) | 6679 | IF_ASH_BASH_COMPAT(int pos, len, orig_len;) |
| 6692 | int saveherefd = herefd; | ||
| 6693 | int amount, resetloc; | 6680 | int amount, resetloc; |
| 6694 | IF_ASH_BASH_COMPAT(int workloc;) | 6681 | IF_ASH_BASH_COMPAT(int workloc;) |
| 6695 | int zero; | 6682 | int zero; |
| @@ -6698,12 +6685,10 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
| 6698 | //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", | 6685 | //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", |
| 6699 | // p, varname, strloc, subtype, startloc, varflags, quotes); | 6686 | // p, varname, strloc, subtype, startloc, varflags, quotes); |
| 6700 | 6687 | ||
| 6701 | herefd = -1; | ||
| 6702 | argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? | 6688 | argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? |
| 6703 | (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0), | 6689 | (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0), |
| 6704 | var_str_list); | 6690 | var_str_list); |
| 6705 | STPUTC('\0', expdest); | 6691 | STPUTC('\0', expdest); |
| 6706 | herefd = saveherefd; | ||
| 6707 | argbackq = saveargbackq; | 6692 | argbackq = saveargbackq; |
| 6708 | startp = (char *)stackblock() + startloc; | 6693 | startp = (char *)stackblock() + startloc; |
| 6709 | 6694 | ||
| @@ -7125,6 +7110,10 @@ evalvar(char *p, int flag, struct strlist *var_str_list) | |||
| 7125 | 7110 | ||
| 7126 | varflags = (unsigned char) *p++; | 7111 | varflags = (unsigned char) *p++; |
| 7127 | subtype = varflags & VSTYPE; | 7112 | subtype = varflags & VSTYPE; |
| 7113 | |||
| 7114 | if (!subtype) | ||
| 7115 | raise_error_syntax("bad substitution"); | ||
| 7116 | |||
| 7128 | quoted = flag & EXP_QUOTED; | 7117 | quoted = flag & EXP_QUOTED; |
| 7129 | var = p; | 7118 | var = p; |
| 7130 | easy = (!quoted || (*var == '@' && shellparam.nparam)); | 7119 | easy = (!quoted || (*var == '@' && shellparam.nparam)); |
| @@ -7737,7 +7726,6 @@ expandarg(union node *arg, struct arglist *arglist, int flag) | |||
| 7737 | static void | 7726 | static void |
| 7738 | expandhere(union node *arg, int fd) | 7727 | expandhere(union node *arg, int fd) |
| 7739 | { | 7728 | { |
| 7740 | herefd = fd; | ||
| 7741 | expandarg(arg, (struct arglist *)NULL, EXP_QUOTED); | 7729 | expandarg(arg, (struct arglist *)NULL, EXP_QUOTED); |
| 7742 | full_write(fd, stackblock(), expdest - (char *)stackblock()); | 7730 | full_write(fd, stackblock(), expdest - (char *)stackblock()); |
| 7743 | } | 7731 | } |
| @@ -7970,7 +7958,7 @@ shellexec(char **argv, const char *path, int idx) | |||
| 7970 | exitstatus = exerrno; | 7958 | exitstatus = exerrno; |
| 7971 | TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n", | 7959 | TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n", |
| 7972 | argv[0], e, suppress_int)); | 7960 | argv[0], e, suppress_int)); |
| 7973 | ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found")); | 7961 | ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found")); |
| 7974 | /* NOTREACHED */ | 7962 | /* NOTREACHED */ |
| 7975 | } | 7963 | } |
| 7976 | 7964 | ||
| @@ -8850,14 +8838,14 @@ copyfunc(union node *n) | |||
| 8850 | * Define a shell function. | 8838 | * Define a shell function. |
| 8851 | */ | 8839 | */ |
| 8852 | static void | 8840 | static void |
| 8853 | defun(char *name, union node *func) | 8841 | defun(union node *func) |
| 8854 | { | 8842 | { |
| 8855 | struct cmdentry entry; | 8843 | struct cmdentry entry; |
| 8856 | 8844 | ||
| 8857 | INT_OFF; | 8845 | INT_OFF; |
| 8858 | entry.cmdtype = CMDFUNCTION; | 8846 | entry.cmdtype = CMDFUNCTION; |
| 8859 | entry.u.func = copyfunc(func); | 8847 | entry.u.func = copyfunc(func); |
| 8860 | addcmdentry(name, &entry); | 8848 | addcmdentry(func->narg.text, &entry); |
| 8861 | INT_ON; | 8849 | INT_ON; |
| 8862 | } | 8850 | } |
| 8863 | 8851 | ||
| @@ -8991,7 +8979,8 @@ evaltree(union node *n, int flags) | |||
| 8991 | if (!status) { | 8979 | if (!status) { |
| 8992 | status = evaltree(n->nredir.n, flags & EV_TESTED); | 8980 | status = evaltree(n->nredir.n, flags & EV_TESTED); |
| 8993 | } | 8981 | } |
| 8994 | popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */); | 8982 | if (n->nredir.redirect) |
| 8983 | popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */); | ||
| 8995 | goto setstatus; | 8984 | goto setstatus; |
| 8996 | case NCMD: | 8985 | case NCMD: |
| 8997 | evalfn = evalcommand; | 8986 | evalfn = evalcommand; |
| @@ -9007,11 +8996,9 @@ evaltree(union node *n, int flags) | |||
| 9007 | evalfn = evalloop; | 8996 | evalfn = evalloop; |
| 9008 | goto calleval; | 8997 | goto calleval; |
| 9009 | case NSUBSHELL: | 8998 | case NSUBSHELL: |
| 9010 | evalfn = evalsubshell; | ||
| 9011 | goto checkexit; | ||
| 9012 | case NBACKGND: | 8999 | case NBACKGND: |
| 9013 | evalfn = evalsubshell; | 9000 | evalfn = evalsubshell; |
| 9014 | goto calleval; | 9001 | goto checkexit; |
| 9015 | case NPIPE: | 9002 | case NPIPE: |
| 9016 | evalfn = evalpipe; | 9003 | evalfn = evalpipe; |
| 9017 | goto checkexit; | 9004 | goto checkexit; |
| @@ -9057,7 +9044,7 @@ evaltree(union node *n, int flags) | |||
| 9057 | status = 0; | 9044 | status = 0; |
| 9058 | goto setstatus; | 9045 | goto setstatus; |
| 9059 | case NDEFUN: | 9046 | case NDEFUN: |
| 9060 | defun(n->narg.text, n->narg.next); | 9047 | defun(n); |
| 9061 | /* Not necessary. To test it: | 9048 | /* Not necessary. To test it: |
| 9062 | * "false; f() { qwerty; }; echo $?" should print 0. | 9049 | * "false; f() { qwerty; }; echo $?" should print 0. |
| 9063 | */ | 9050 | */ |
| @@ -9506,7 +9493,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
| 9506 | shellparam.optind = 1; | 9493 | shellparam.optind = 1; |
| 9507 | shellparam.optoff = -1; | 9494 | shellparam.optoff = -1; |
| 9508 | #endif | 9495 | #endif |
| 9509 | evaltree(&func->n, flags & EV_TESTED); | 9496 | evaltree(func->n.narg.next, flags & EV_TESTED); |
| 9510 | funcdone: | 9497 | funcdone: |
| 9511 | INT_OFF; | 9498 | INT_OFF; |
| 9512 | funcnest--; | 9499 | funcnest--; |
| @@ -10084,7 +10071,7 @@ evalcommand(union node *cmd, int flags) | |||
| 10084 | if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) { | 10071 | if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) { |
| 10085 | int exit_status; | 10072 | int exit_status; |
| 10086 | int i = exception_type; | 10073 | int i = exception_type; |
| 10087 | if (i == EXEXIT || i == EXEXEC) | 10074 | if (i == EXEXIT) |
| 10088 | goto raise; | 10075 | goto raise; |
| 10089 | exit_status = 2; | 10076 | exit_status = 2; |
| 10090 | if (i == EXINT) | 10077 | if (i == EXINT) |
| @@ -10112,7 +10099,8 @@ evalcommand(union node *cmd, int flags) | |||
| 10112 | } /* switch */ | 10099 | } /* switch */ |
| 10113 | 10100 | ||
| 10114 | out: | 10101 | out: |
| 10115 | popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec); | 10102 | if (cmd->ncmd.redirect) |
| 10103 | popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec); | ||
| 10116 | if (lastarg) { | 10104 | if (lastarg) { |
| 10117 | /* dsl: I think this is intended to be used to support | 10105 | /* dsl: I think this is intended to be used to support |
| 10118 | * '_' in 'vi' command mode during line editing... | 10106 | * '_' in 'vi' command mode during line editing... |
| @@ -10685,13 +10673,12 @@ setinputfile(const char *fname, int flags) | |||
| 10685 | if (fd < 0) { | 10673 | if (fd < 0) { |
| 10686 | if (flags & INPUT_NOFILE_OK) | 10674 | if (flags & INPUT_NOFILE_OK) |
| 10687 | goto out; | 10675 | goto out; |
| 10676 | exitstatus = 127; | ||
| 10688 | ash_msg_and_raise_error("can't open '%s'", fname); | 10677 | ash_msg_and_raise_error("can't open '%s'", fname); |
| 10689 | } | 10678 | } |
| 10690 | if (fd < 10) { | 10679 | if (fd < 10) { |
| 10691 | fd2 = copyfd(fd, 10); | 10680 | fd2 = copyfd(fd, 10); |
| 10692 | close(fd); | 10681 | close(fd); |
| 10693 | if (fd2 < 0) | ||
| 10694 | ash_msg_and_raise_error("out of file descriptors"); | ||
| 10695 | fd = fd2; | 10682 | fd = fd2; |
| 10696 | } | 10683 | } |
| 10697 | setinputfd(fd, flags & INPUT_PUSH_FILE); | 10684 | setinputfd(fd, flags & INPUT_PUSH_FILE); |
| @@ -11046,8 +11033,6 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt | |||
| 11046 | 11033 | ||
| 11047 | sbuf[1] = '\0'; | 11034 | sbuf[1] = '\0'; |
| 11048 | 11035 | ||
| 11049 | if (*param_optind < 1) | ||
| 11050 | return 1; | ||
| 11051 | optnext = optfirst + *param_optind - 1; | 11036 | optnext = optfirst + *param_optind - 1; |
| 11052 | 11037 | ||
| 11053 | if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff) | 11038 | if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff) |
| @@ -12178,7 +12163,7 @@ parseredir: { | |||
| 12178 | parsesub: { | 12163 | parsesub: { |
| 12179 | unsigned char subtype; | 12164 | unsigned char subtype; |
| 12180 | int typeloc; | 12165 | int typeloc; |
| 12181 | int flags; | 12166 | int flags = 0; |
| 12182 | 12167 | ||
| 12183 | c = pgetc_eatbnl(); | 12168 | c = pgetc_eatbnl(); |
| 12184 | if (c > 255 /* PEOA or PEOF */ | 12169 | if (c > 255 /* PEOA or PEOF */ |
| @@ -12238,15 +12223,13 @@ parsesub: { | |||
| 12238 | USTPUTC(c, out); | 12223 | USTPUTC(c, out); |
| 12239 | c = pgetc_eatbnl(); | 12224 | c = pgetc_eatbnl(); |
| 12240 | } else { | 12225 | } else { |
| 12241 | badsub: | 12226 | goto badsub; |
| 12242 | raise_error_syntax("bad substitution"); | ||
| 12243 | } | 12227 | } |
| 12244 | if (c != '}' && subtype == VSLENGTH) { | 12228 | if (c != '}' && subtype == VSLENGTH) { |
| 12245 | /* ${#VAR didn't end with } */ | 12229 | /* ${#VAR didn't end with } */ |
| 12246 | goto badsub; | 12230 | goto badsub; |
| 12247 | } | 12231 | } |
| 12248 | 12232 | ||
| 12249 | STPUTC('=', out); | ||
| 12250 | flags = 0; | 12233 | flags = 0; |
| 12251 | if (subtype == 0) { | 12234 | if (subtype == 0) { |
| 12252 | static const char types[] ALIGN1 = "}-+?="; | 12235 | static const char types[] ALIGN1 = "}-+?="; |
| @@ -12263,7 +12246,7 @@ parsesub: { | |||
| 12263 | if (!strchr(types, c)) { | 12246 | if (!strchr(types, c)) { |
| 12264 | subtype = VSSUBSTR; | 12247 | subtype = VSSUBSTR; |
| 12265 | pungetc(); | 12248 | pungetc(); |
| 12266 | break; /* "goto do_pungetc" is bigger (!) */ | 12249 | break; /* "goto badsub" is bigger (!) */ |
| 12267 | } | 12250 | } |
| 12268 | #endif | 12251 | #endif |
| 12269 | flags = VSNUL; | 12252 | flags = VSNUL; |
| @@ -12271,7 +12254,7 @@ parsesub: { | |||
| 12271 | default: { | 12254 | default: { |
| 12272 | const char *p = strchr(types, c); | 12255 | const char *p = strchr(types, c); |
| 12273 | if (p == NULL) | 12256 | if (p == NULL) |
| 12274 | goto badsub; | 12257 | break; |
| 12275 | subtype = p - types + VSNORMAL; | 12258 | subtype = p - types + VSNORMAL; |
| 12276 | break; | 12259 | break; |
| 12277 | } | 12260 | } |
| @@ -12281,7 +12264,7 @@ parsesub: { | |||
| 12281 | subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT); | 12264 | subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT); |
| 12282 | c = pgetc_eatbnl(); | 12265 | c = pgetc_eatbnl(); |
| 12283 | if (c != cc) | 12266 | if (c != cc) |
| 12284 | goto do_pungetc; | 12267 | goto badsub; |
| 12285 | subtype++; | 12268 | subtype++; |
| 12286 | break; | 12269 | break; |
| 12287 | } | 12270 | } |
| @@ -12293,13 +12276,13 @@ parsesub: { | |||
| 12293 | subtype = VSREPLACE; | 12276 | subtype = VSREPLACE; |
| 12294 | c = pgetc_eatbnl(); | 12277 | c = pgetc_eatbnl(); |
| 12295 | if (c != '/') | 12278 | if (c != '/') |
| 12296 | goto do_pungetc; | 12279 | goto badsub; |
| 12297 | subtype++; /* VSREPLACEALL */ | 12280 | subtype++; /* VSREPLACEALL */ |
| 12298 | break; | 12281 | break; |
| 12299 | #endif | 12282 | #endif |
| 12300 | } | 12283 | } |
| 12301 | } else { | 12284 | } else { |
| 12302 | do_pungetc: | 12285 | badsub: |
| 12303 | pungetc(); | 12286 | pungetc(); |
| 12304 | } | 12287 | } |
| 12305 | ((unsigned char *)stackblock())[typeloc] = subtype | flags; | 12288 | ((unsigned char *)stackblock())[typeloc] = subtype | flags; |
| @@ -12309,6 +12292,7 @@ parsesub: { | |||
| 12309 | dqvarnest++; | 12292 | dqvarnest++; |
| 12310 | } | 12293 | } |
| 12311 | } | 12294 | } |
| 12295 | STPUTC('=', out); | ||
| 12312 | } | 12296 | } |
| 12313 | goto parsesub_return; | 12297 | goto parsesub_return; |
| 12314 | } | 12298 | } |
| @@ -12746,11 +12730,17 @@ static const char * | |||
| 12746 | expandstr(const char *ps) | 12730 | expandstr(const char *ps) |
| 12747 | { | 12731 | { |
| 12748 | union node n; | 12732 | union node n; |
| 12733 | int saveprompt; | ||
| 12749 | 12734 | ||
| 12750 | /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value, | 12735 | /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value, |
| 12751 | * and token processing _can_ alter it (delete NULs etc). */ | 12736 | * and token processing _can_ alter it (delete NULs etc). */ |
| 12752 | setinputstring((char *)ps); | 12737 | setinputstring((char *)ps); |
| 12738 | |||
| 12739 | saveprompt = doprompt; | ||
| 12740 | doprompt = 0; | ||
| 12753 | readtoken1(pgetc(), PSSYNTAX, nullstr, 0); | 12741 | readtoken1(pgetc(), PSSYNTAX, nullstr, 0); |
| 12742 | doprompt = saveprompt; | ||
| 12743 | |||
| 12754 | popfile(); | 12744 | popfile(); |
| 12755 | 12745 | ||
| 12756 | n.narg.type = NARG; | 12746 | n.narg.type = NARG; |
| @@ -13680,12 +13670,12 @@ exitshell(void) | |||
| 13680 | evalstring(p, 0); | 13670 | evalstring(p, 0); |
| 13681 | /*free(p); - we'll exit soon */ | 13671 | /*free(p); - we'll exit soon */ |
| 13682 | } | 13672 | } |
| 13683 | flush_stdout_stderr(); | ||
| 13684 | out: | 13673 | out: |
| 13685 | /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". | 13674 | /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". |
| 13686 | * our setjobctl(0) does not panic if tcsetpgrp fails inside it. | 13675 | * our setjobctl(0) does not panic if tcsetpgrp fails inside it. |
| 13687 | */ | 13676 | */ |
| 13688 | setjobctl(0); | 13677 | setjobctl(0); |
| 13678 | flush_stdout_stderr(); | ||
| 13689 | _exit(status); | 13679 | _exit(status); |
| 13690 | /* NOTREACHED */ | 13680 | /* NOTREACHED */ |
| 13691 | } | 13681 | } |
| @@ -13978,8 +13968,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 13978 | reset(); | 13968 | reset(); |
| 13979 | 13969 | ||
| 13980 | e = exception_type; | 13970 | e = exception_type; |
| 13981 | if (e == EXERROR) | ||
| 13982 | exitstatus = 2; | ||
| 13983 | s = state; | 13971 | s = state; |
| 13984 | if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) { | 13972 | if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) { |
| 13985 | exitshell(); | 13973 | exitshell(); |
diff --git a/shell/hush.c b/shell/hush.c index 9b51f389e..d7a0d761e 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -8409,7 +8409,9 @@ int hush_main(int argc, char **argv) | |||
| 8409 | G.global_argc--; | 8409 | G.global_argc--; |
| 8410 | G.global_argv++; | 8410 | G.global_argv++; |
| 8411 | debug_printf("running script '%s'\n", G.global_argv[0]); | 8411 | debug_printf("running script '%s'\n", G.global_argv[0]); |
| 8412 | xfunc_error_retval = 127; /* for "hush /does/not/exist" case */ | ||
| 8412 | input = xfopen_for_read(G.global_argv[0]); | 8413 | input = xfopen_for_read(G.global_argv[0]); |
| 8414 | xfunc_error_retval = 1; | ||
| 8413 | remember_FILE(input); | 8415 | remember_FILE(input); |
| 8414 | install_special_sighandlers(); | 8416 | install_special_sighandlers(); |
| 8415 | parse_and_run_file(input); | 8417 | parse_and_run_file(input); |
