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); |