summaryrefslogtreecommitdiff
path: root/Src/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/exec.c')
-rw-r--r--Src/exec.c425
1 files changed, 251 insertions, 174 deletions
diff --git a/Src/exec.c b/Src/exec.c
index 216057aa7..615a5086f 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -174,6 +174,11 @@ mod_export int zleactive;
/**/
pid_t cmdoutpid;
+/* pid of last process started by <(...), >(...) */
+
+/**/
+mod_export pid_t procsubstpid;
+
/* exit status of process undergoing 'process substitution' */
/**/
@@ -698,7 +703,7 @@ execute(LinkList args, int flags, int defpath)
* Note that we don't close fd's attached to process substitution
* here, which should be visible to external processes.
*/
- closem(FDT_XTRACE);
+ closem(FDT_XTRACE, 0);
#ifndef FD_CLOEXEC
if (SHTTY != -1) {
close(SHTTY);
@@ -1878,8 +1883,6 @@ static void
execpline2(Estate state, wordcode pcode,
int how, int input, int output, int last1)
{
- pid_t pid;
- int pipes[2];
struct execcmd_params eparams;
if (breaks || retflag)
@@ -1900,65 +1903,21 @@ execpline2(Estate state, wordcode pcode,
}
if (WC_PIPE_TYPE(pcode) == WC_PIPE_END) {
execcmd_analyse(state, &eparams);
- execcmd_exec(state, &eparams, input, output, how, last1 ? 1 : 2);
+ execcmd_exec(state, &eparams, input, output, how, last1 ? 1 : 2, -1);
} else {
+ int pipes[2];
int old_list_pipe = list_pipe;
- int subsh_close = -1;
- Wordcode next = state->pc + (*state->pc), start_pc;
+ Wordcode next = state->pc + (*state->pc);
- start_pc = ++state->pc;
+ ++state->pc;
execcmd_analyse(state, &eparams);
if (mpipe(pipes) < 0) {
/* FIXME */
}
- /* if we are doing "foo | bar" where foo is a current *
- * shell command, do foo in a subshell and do the *
- * rest of the pipeline in the current shell. */
- if ((eparams.type >= WC_CURSH || !eparams.args)
- && (how & Z_SYNC)) {
- int synch[2];
- struct timeval bgtime;
-
- if (pipe(synch) < 0) {
- zerr("pipe failed: %e", errno);
- lastval = 1;
- errflag |= ERRFLAG_ERROR;
- return;
- } else if ((pid = zfork(&bgtime)) == -1) {
- close(synch[0]);
- close(synch[1]);
- lastval = 1;
- errflag |= ERRFLAG_ERROR;
- return;
- } else if (pid) {
- char dummy, *text;
-
- text = getjobtext(state->prog, start_pc);
- addproc(pid, text, 0, &bgtime);
- close(synch[1]);
- read_loop(synch[0], &dummy, 1);
- close(synch[0]);
- } else {
- zclose(pipes[0]);
- close(synch[0]);
- entersubsh(((how & Z_ASYNC) ? ESUB_ASYNC : 0)
- | ESUB_PGRP | ESUB_KEEPTRAP);
- close(synch[1]);
- if (sigtrapped[SIGEXIT])
- {
- unsettrap(SIGEXIT);
- }
- execcmd_exec(state, &eparams, input, pipes[1], how, 1);
- _exit(lastval);
- }
- } else {
- /* otherwise just do the pipeline normally. */
- addfilelist(NULL, pipes[0]);
- subsh_close = pipes[0];
- execcmd_exec(state, &eparams, input, pipes[1], how, 0);
- }
+ addfilelist(NULL, pipes[0]);
+ execcmd_exec(state, &eparams, input, pipes[1], how, 0, pipes[0]);
zclose(pipes[1]);
state->pc = next;
@@ -1969,8 +1928,6 @@ execpline2(Estate state, wordcode pcode,
execpline2(state, *state->pc++, how, pipes[0], output, last1);
list_pipe = old_list_pipe;
cmdpop();
- if (subsh_close != pipes[0])
- zclose(pipes[0]);
}
}
@@ -2707,6 +2664,85 @@ static void execcmd_getargs(LinkList preargs, LinkList args, int expand)
}
}
+/**/
+static int
+execcmd_fork(Estate state, int how, int type, Wordcode varspc,
+ LinkList *filelistp, char *text, int oautocont,
+ int close_if_forked)
+{
+ pid_t pid;
+ int synch[2], flags;
+ char dummy;
+ struct timeval bgtime;
+
+ child_block();
+
+ if (pipe(synch) < 0) {
+ zerr("pipe failed: %e", errno);
+ return -1;
+ } else if ((pid = zfork(&bgtime)) == -1) {
+ close(synch[0]);
+ close(synch[1]);
+ lastval = 1;
+ errflag |= ERRFLAG_ERROR;
+ return -1;
+ }
+ if (pid) {
+ close(synch[1]);
+ read_loop(synch[0], &dummy, 1);
+ close(synch[0]);
+ if (how & Z_ASYNC) {
+ lastpid = (zlong) pid;
+ } else if (!jobtab[thisjob].stty_in_env && varspc) {
+ /* search for STTY=... */
+ Wordcode p = varspc;
+ wordcode ac;
+
+ while (wc_code(ac = *p) == WC_ASSIGN) {
+ if (!strcmp(ecrawstr(state->prog, p + 1, NULL), "STTY")) {
+ jobtab[thisjob].stty_in_env = 1;
+ break;
+ }
+ p += (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR ?
+ 3 : WC_ASSIGN_NUM(ac) + 2);
+ }
+ }
+ addproc(pid, text, 0, &bgtime);
+ if (oautocont >= 0)
+ opts[AUTOCONTINUE] = oautocont;
+ pipecleanfilelist(jobtab[thisjob].filelist, 1);
+ return pid;
+ }
+
+ /* pid == 0 */
+ close(synch[0]);
+ flags = ((how & Z_ASYNC) ? ESUB_ASYNC : 0) | ESUB_PGRP;
+ if ((type != WC_SUBSH) && !(how & Z_ASYNC))
+ flags |= ESUB_KEEPTRAP;
+ if (type == WC_SUBSH && !(how & Z_ASYNC))
+ flags |= ESUB_JOB_CONTROL;
+ *filelistp = jobtab[thisjob].filelist;
+ entersubsh(flags);
+ close(synch[1]);
+ zclose(close_if_forked);
+
+ if (sigtrapped[SIGINT] & ZSIG_IGNORED)
+ holdintr();
+ /*
+ * EXIT traps shouldn't be called even if we forked to run
+ * shell code as this isn't the main shell.
+ */
+ sigtrapped[SIGEXIT] = 0;
+#ifdef HAVE_NICE
+ /* Check if we should run background jobs at a lower priority. */
+ if ((how & Z_ASYNC) && isset(BGNICE))
+ if (nice(5) < 0)
+ zwarn("nice(5) failed: %e", errno);
+#endif /* HAVE_NICE */
+
+ return 0;
+}
+
/*
* Execute a command at the lowest level of the hierarchy.
*/
@@ -2714,7 +2750,7 @@ static void execcmd_getargs(LinkList preargs, LinkList args, int expand)
/**/
static void
execcmd_exec(Estate state, Execcmd_params eparams,
- int input, int output, int how, int last1)
+ int input, int output, int how, int last1, int close_if_forked)
{
HashNode hn = NULL;
LinkList filelist = NULL;
@@ -2724,7 +2760,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
char *text;
int save[10];
int fil, dfil, is_cursh, do_exec = 0, redir_err = 0, i;
- int nullexec = 0, magic_assign = 0, forked = 0;
+ int nullexec = 0, magic_assign = 0, forked = 0, old_lastval;
int is_shfunc = 0, is_builtin = 0, is_exec = 0, use_defpath = 0;
/* Various flags to the command. */
int cflags = 0, orig_cflags = 0, checked = 0, oautocont = -1;
@@ -2749,6 +2785,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
* If assignment but no command get the status from variable
* assignment.
*/
+ old_lastval = lastval;
if (!args && varspc)
lastval = errflag ? errflag : cmdoutval;
/*
@@ -2791,6 +2828,29 @@ execcmd_exec(Estate state, Execcmd_params eparams,
pushnode(args, dupstring("fg"));
}
+ if ((how & Z_ASYNC) || output) {
+ /*
+ * If running in the background, or not the last command in a
+ * pipeline, we don't need any of the rest of this function to
+ * affect the state in the main shell, so fork immediately.
+ *
+ * In other cases we may need to process the command line
+ * a bit further before we make the decision.
+ */
+ text = getjobtext(state->prog, eparams->beg);
+ switch (execcmd_fork(state, how, type, varspc, &filelist,
+ text, oautocont, close_if_forked)) {
+ case -1:
+ goto fatal;
+ case 0:
+ break;
+ default:
+ return;
+ }
+ last1 = forked = 1;
+ } else
+ text = NULL;
+
/* Check if it's a builtin needing automatic MAGIC_EQUALS_SUBST *
* handling. Things like typeset need this. We can't detect the *
* command if it contains some tokens (e.g. x=ex; ${x}port), so this *
@@ -2799,7 +2859,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if ((type == WC_SIMPLE || type == WC_TYPESET) && args) {
/*
* preargs contains args that have been expanded by prefork.
- * Running execcmd_getargs() causes the any argument available
+ * Running execcmd_getargs() causes any argument available
* in args to be exanded where necessary and transferred to
* preargs. We call execcmd_getargs() every time we need to
* analyse an argument not available in preargs, though there is
@@ -2846,8 +2906,11 @@ execcmd_exec(Estate state, Execcmd_params eparams,
is_builtin = 1;
/* autoload the builtin if necessary */
- if (!(hn = resolvebuiltin(cmdarg, hn)))
+ if (!(hn = resolvebuiltin(cmdarg, hn))) {
+ if (forked)
+ _exit(lastval);
return;
+ }
if (type != WC_TYPESET)
magic_assign = (hn->flags & BINF_MAGICEQUALS);
break;
@@ -3025,6 +3088,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
zerr("unknown exec flag -%c", *cmdopt);
lastval = 1;
errflag |= ERRFLAG_ERROR;
+ if (forked)
+ _exit(lastval);
return;
}
}
@@ -3074,6 +3139,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
esprefork = (magic_assign ||
(isset(MAGICEQUALSUBST) && type != WC_TYPESET)) ?
PREFORK_TYPESET : 0;
+
if (args) {
if (eparams->htok)
prefork(args, esprefork, NULL);
@@ -3117,6 +3183,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
zerr("redirection with no command");
lastval = 1;
errflag |= ERRFLAG_ERROR;
+ if (forked)
+ _exit(lastval);
return;
} else if (!nullcmd || !*nullcmd || opts[SHNULLCMD]) {
if (!args)
@@ -3135,6 +3203,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
}
} else if ((cflags & BINF_PREFIX) && (cflags & BINF_COMMAND)) {
lastval = 0;
+ if (forked)
+ _exit(lastval);
return;
} else {
/*
@@ -3145,11 +3215,16 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if (badcshglob == 1) {
zerr("no match");
lastval = 1;
+ if (forked)
+ _exit(lastval);
return;
}
cmdoutval = use_cmdoutval ? lastval : 0;
- if (varspc)
+ if (varspc) {
+ /* Make sure $? is still correct for assignment */
+ lastval = old_lastval;
addvars(state, varspc, 0);
+ }
if (errflag)
lastval = 1;
else
@@ -3158,12 +3233,16 @@ execcmd_exec(Estate state, Execcmd_params eparams,
fputc('\n', xtrerr);
fflush(xtrerr);
}
+ if (forked)
+ _exit(lastval);
return;
}
} else if (isset(RESTRICTED) && (cflags & BINF_EXEC) && do_exec) {
zerrnam("exec", "%s: restricted",
(char *) getdata(firstnode(args)));
lastval = 1;
+ if (forked)
+ _exit(lastval);
return;
}
@@ -3198,6 +3277,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
+ if (forked)
+ _exit(lastval);
return;
}
break;
@@ -3206,8 +3287,11 @@ execcmd_exec(Estate state, Execcmd_params eparams,
is_builtin = 1;
/* autoload the builtin if necessary */
- if (!(hn = resolvebuiltin(cmdarg, hn)))
+ if (!(hn = resolvebuiltin(cmdarg, hn))) {
+ if (forked)
+ _exit(lastval);
return;
+ }
break;
}
cflags &= ~BINF_BUILTIN & ~BINF_COMMAND;
@@ -3222,15 +3306,15 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
+ if (forked)
+ _exit(lastval);
return;
}
/* Get the text associated with this command. */
- if ((how & Z_ASYNC) ||
+ if (!text &&
(!sfcontext && (jobbing || (how & Z_TIMED))))
text = getjobtext(state->prog, eparams->beg);
- else
- text = NULL;
/*
* Set up special parameter $_
@@ -3301,6 +3385,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
+ if (forked)
+ _exit(lastval);
return;
}
}
@@ -3329,6 +3415,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
+ if (forked)
+ _exit(lastval);
return;
}
@@ -3378,7 +3466,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
/**************************************************************************
* Do we need to fork? We need to fork if: *
- * 1) The command is supposed to run in the background. (or) *
+ * 1) The command is supposed to run in the background. This *
+ * case is now handled above (forked = 1 here). (or) *
* 2) There is no `exec' flag, and either: *
* a) This is a builtin or shell function with output piped somewhere. *
* b) This is an external command and we can't do a `fake exec'. *
@@ -3397,99 +3486,45 @@ execcmd_exec(Estate state, Execcmd_params eparams,
* current shell. *
**************************************************************************/
- if ((how & Z_ASYNC) ||
- (!do_exec &&
- (((is_builtin || is_shfunc) && output) ||
- (!is_cursh && (last1 != 1 || nsigtrapped || havefiles() ||
- fdtable_flocks))))) {
-
- pid_t pid;
- int synch[2], flags;
- char dummy;
- struct timeval bgtime;
-
- child_block();
-
- if (pipe(synch) < 0) {
- zerr("pipe failed: %e", errno);
- goto fatal;
- } else if ((pid = zfork(&bgtime)) == -1) {
- close(synch[0]);
- close(synch[1]);
- lastval = 1;
- errflag |= ERRFLAG_ERROR;
- goto fatal;
- }
- if (pid) {
-
- close(synch[1]);
- read_loop(synch[0], &dummy, 1);
- close(synch[0]);
- if (how & Z_ASYNC) {
- lastpid = (zlong) pid;
- } else if (!jobtab[thisjob].stty_in_env && varspc) {
- /* search for STTY=... */
- Wordcode p = varspc;
- wordcode ac;
-
- while (wc_code(ac = *p) == WC_ASSIGN) {
- if (!strcmp(ecrawstr(state->prog, p + 1, NULL), "STTY")) {
- jobtab[thisjob].stty_in_env = 1;
- break;
- }
- p += (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR ?
- 3 : WC_ASSIGN_NUM(ac) + 2);
- }
+ if (!forked) {
+ if (!do_exec &&
+ (((is_builtin || is_shfunc) && output) ||
+ (!is_cursh && (last1 != 1 || nsigtrapped || havefiles() ||
+ fdtable_flocks)))) {
+ switch (execcmd_fork(state, how, type, varspc, &filelist,
+ text, oautocont, close_if_forked)) {
+ case -1:
+ goto fatal;
+ case 0:
+ break;
+ default:
+ return;
}
- addproc(pid, text, 0, &bgtime);
- if (oautocont >= 0)
- opts[AUTOCONTINUE] = oautocont;
- pipecleanfilelist(jobtab[thisjob].filelist, 1);
- return;
- }
- /* pid == 0 */
- close(synch[0]);
- flags = ((how & Z_ASYNC) ? ESUB_ASYNC : 0) | ESUB_PGRP;
- if ((type != WC_SUBSH) && !(how & Z_ASYNC))
- flags |= ESUB_KEEPTRAP;
- if (type == WC_SUBSH && !(how & Z_ASYNC))
- flags |= ESUB_JOB_CONTROL;
- filelist = jobtab[thisjob].filelist;
- entersubsh(flags);
- close(synch[1]);
- forked = 1;
- if (sigtrapped[SIGINT] & ZSIG_IGNORED)
- holdintr();
-#ifdef HAVE_NICE
- /* Check if we should run background jobs at a lower priority. */
- if ((how & Z_ASYNC) && isset(BGNICE))
- if (nice(5) < 0)
- zwarn("nice(5) failed: %e", errno);
-#endif /* HAVE_NICE */
-
- } else if (is_cursh) {
- /* This is a current shell procedure that didn't need to fork. *
- * This includes current shell procedures that are being exec'ed, *
- * as well as null execs. */
- jobtab[thisjob].stat |= STAT_CURSH;
- if (!jobtab[thisjob].procs)
- jobtab[thisjob].stat |= STAT_NOPRINT;
- if (is_builtin)
- jobtab[thisjob].stat |= STAT_BUILTIN;
- } else {
- /* This is an exec (real or fake) for an external command. *
- * Note that any form of exec means that the subshell is fake *
- * (but we may be in a subshell already). */
- is_exec = 1;
- /*
- * If we are in a subshell environment anyway, say we're forked,
- * even if we're actually not forked because we know the
- * subshell is exiting. This ensures SHLVL reflects the current
- * shell, and also optimises out any save/restore we'd need to
- * do if we were returning to the main shell.
- */
- if (type == WC_SUBSH)
forked = 1;
+ } else if (is_cursh) {
+ /* This is a current shell procedure that didn't need to fork. *
+ * This includes current shell procedures that are being exec'ed, *
+ * as well as null execs. */
+ jobtab[thisjob].stat |= STAT_CURSH;
+ if (!jobtab[thisjob].procs)
+ jobtab[thisjob].stat |= STAT_NOPRINT;
+ if (is_builtin)
+ jobtab[thisjob].stat |= STAT_BUILTIN;
+ } else {
+ /* This is an exec (real or fake) for an external command. *
+ * Note that any form of exec means that the subshell is fake *
+ * (but we may be in a subshell already). */
+ is_exec = 1;
+ /*
+ * If we are in a subshell environment anyway, say we're forked,
+ * even if we're actually not forked because we know the
+ * subshell is exiting. This ensures SHLVL reflects the current
+ * shell, and also optimises out any save/restore we'd need to
+ * do if we were returning to the main shell.
+ */
+ if (type == WC_SUBSH)
+ forked = 1;
+ }
}
if ((esglob = !(cflags & BINF_NOGLOB)) && args && eparams->htok) {
@@ -3903,7 +3938,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
LinkList assigns = (LinkList)0;
int postassigns = eparams->postassigns;
if (forked)
- closem(FDT_INTERNAL);
+ closem(FDT_INTERNAL, 0);
if (postassigns) {
Wordcode opc = state->pc;
state->pc = eparams->assignspc;
@@ -4089,7 +4124,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if (errflag)
_exit(1);
}
- closem(FDT_INTERNAL);
+ closem(FDT_INTERNAL, 0);
if (coprocin != -1) {
zclose(coprocin);
coprocin = -1;
@@ -4151,7 +4186,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
for (i = 0; i < 10; i++)
if (fdtable[i] != FDT_UNUSED)
close(i);
- closem(FDT_UNUSED);
+ closem(FDT_UNUSED, 1);
if (thisjob != -1)
waitjobs();
_exit(lastval);
@@ -4327,16 +4362,24 @@ fixfds(int *save)
*
* Close any that are marked as used if "how" is FDT_UNUSED, else
* close any with the value "how".
+ *
+ * If "all" is zero, we'll skip cases where we need the file
+ * descriptor to be visible externally.
*/
/**/
mod_export void
-closem(int how)
+closem(int how, int all)
{
int i;
for (i = 10; i <= max_zsh_fd; i++)
if (fdtable[i] != FDT_UNUSED &&
+ /*
+ * Process substitution needs to be visible to user;
+ * fd's are explicitly cleaned up by filelist handling.
+ */
+ (all || fdtable[i] != FDT_PROC_SUBST) &&
(how == FDT_UNUSED || (fdtable[i] & FDT_TYPE_MASK) == how)) {
if (i == SHTTY)
SHTTY = -1;
@@ -4375,7 +4418,9 @@ gethere(char **strp, int typ)
while ((c = hgetc()) == '\t' && strip)
;
for (;;) {
- if (bptr == buf + bsiz) {
+ if (bptr >= buf + bsiz - 2) {
+ ptrdiff_t toff = t - buf;
+ ptrdiff_t bptroff = bptr - buf;
char *newbuf = realloc(buf, 2 * bsiz);
if (!newbuf) {
/* out of memory */
@@ -4383,20 +4428,20 @@ gethere(char **strp, int typ)
return NULL;
}
buf = newbuf;
- t = buf + bsiz - (bptr - t);
- bptr = buf + bsiz;
+ t = buf + toff;
+ bptr = buf + bptroff;
bsiz *= 2;
}
- if (lexstop)
+ if (lexstop || c == '\n')
break;
- if (c == '\n') {
- if (!qt && bptr > t && *(bptr - 1) == '\\') {
- /* line continuation */
+ if (!qt && c == '\\') {
+ *bptr++ = c;
+ c = hgetc();
+ if (c == '\n') {
bptr--;
c = hgetc();
continue;
- } else
- break;
+ }
}
*bptr++ = c;
c = hgetc();
@@ -4576,10 +4621,20 @@ readoutput(int in, int qt, int *readerror)
char *buf, *ptr;
int bsiz, c, cnt = 0;
FILE *fin;
+ int q = queue_signal_level();
fin = fdopen(in, "r");
ret = newlinklist();
ptr = buf = (char *) hcalloc(bsiz = 64);
+ /*
+ * We need to be sensitive to SIGCHLD else we can be
+ * stuck forever with important processes unreaped.
+ * The case that triggered this was where the exiting
+ * process is group leader of the foreground process and we need
+ * to reclaim the terminal else ^C doesn't work.
+ */
+ dont_queue_signals();
+ child_unblock();
while ((c = fgetc(fin)) != EOF || errno == EINTR) {
if (c == EOF) {
errno = 0;
@@ -4592,13 +4647,18 @@ readoutput(int in, int qt, int *readerror)
cnt++;
}
if (++cnt >= bsiz) {
- char *pp = (char *) hcalloc(bsiz *= 2);
+ char *pp;
+ queue_signals();
+ pp = (char *) hcalloc(bsiz *= 2);
+ dont_queue_signals();
memcpy(pp, buf, cnt - 1);
ptr = (buf = pp) + cnt - 1;
}
*ptr++ = c;
}
+ child_block();
+ restore_queue_signals(q);
if (readerror)
*readerror = ferror(fin) ? errno : 0;
fclose(fin);
@@ -4802,9 +4862,10 @@ getproc(char *cmd, char **eptr)
return NULL;
if (!out)
addproc(pid, NULL, 1, &bgtime);
+ procsubstpid = pid;
return pnam;
}
- closem(FDT_UNUSED);
+ closem(FDT_UNUSED, 0);
fd = open(pnam, out ? O_WRONLY | O_NOCTTY : O_RDONLY | O_NOCTTY);
if (fd == -1) {
zerr("can't open %s: %e", pnam, errno);
@@ -4819,7 +4880,7 @@ getproc(char *cmd, char **eptr)
zerr("process substitution %s cannot be used here", cmd);
return NULL;
}
- pnam = hcalloc(strlen(PATH_DEV_FD) + 6);
+ pnam = zhalloc(strlen(PATH_DEV_FD) + 1 + DIGBUFSIZE);
if (!(prog = parsecmd(cmd, eptr)))
return NULL;
if (mpipe(pipes) < 0)
@@ -4839,11 +4900,12 @@ getproc(char *cmd, char **eptr)
{
addproc(pid, NULL, 1, &bgtime);
}
+ procsubstpid = pid;
return pnam;
}
entersubsh(ESUB_ASYNC|ESUB_PGRP);
redup(pipes[out], out);
- closem(FDT_UNUSED); /* this closes pipes[!out] as well */
+ closem(FDT_UNUSED, 0); /* this closes pipes[!out] as well */
#endif /* PATH_DEV_FD */
cmdpush(CS_CMDSUBST);
@@ -4889,11 +4951,12 @@ getpipe(char *cmd, int nullexec)
}
if (!nullexec)
addproc(pid, NULL, 1, &bgtime);
+ procsubstpid = pid;
return pipes[!out];
}
entersubsh(ESUB_PGRP);
redup(pipes[out], out);
- closem(FDT_UNUSED); /* this closes pipes[!out] as well */
+ closem(FDT_UNUSED, 0); /* this closes pipes[!out] as well */
cmdpush(CS_CMDSUBST);
execode(prog, 0, 1, out ? "outsubst" : "insubst");
cmdpop();
@@ -5736,7 +5799,19 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
undoshfunc:
--funcdepth;
if (retflag) {
+ /*
+ * This function is forced to return.
+ */
retflag = 0;
+ /*
+ * The calling function isn't necessarily forced to return,
+ * but it should be made sensitive to ERR_EXIT and
+ * ERR_RETURN as the assumptions we made at the end of
+ * constructs within this function no longer apply. If
+ * there are cases where this is not true, they need adding
+ * to C03traps.ztst.
+ */
+ this_noerrexit = 0;
breaks = funcsave->breaks;
}
freearray(pparams);
@@ -6124,6 +6199,7 @@ execsave(void)
es->cmdoutpid = cmdoutpid;
es->cmdoutval = cmdoutval;
es->use_cmdoutval = use_cmdoutval;
+ es->procsubstpid = procsubstpid;
es->trap_return = trap_return;
es->trap_state = trap_state;
es->trapisfunc = trapisfunc;
@@ -6159,6 +6235,7 @@ execrestore(void)
cmdoutpid = en->cmdoutpid;
cmdoutval = en->cmdoutval;
use_cmdoutval = en->use_cmdoutval;
+ procsubstpid = en->procsubstpid;
trap_return = en->trap_return;
trap_state = en->trap_state;
trapisfunc = en->trapisfunc;