summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--Src/exec.c145
2 files changed, 71 insertions, 82 deletions
diff --git a/ChangeLog b/ChangeLog
index f93d3d654..8cbcc80bc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2018-05-01 Peter Stephenson <p.stephenson@samsung.com>
+
+ * from branch fork_early, c.f. 42702: Src/exec.c: Various changes
+ to make forking for a command work better. Move the fork even
+ earlier; add case of non-final pipeline elements; _exit when
+ forked; remove previous early fork in caller; replace fix for
+ leaked file descriptor in pipeline handling.
+
2018-04-29 Oliver Kiddle <okiddle@yahoo.co.uk>
* Matthew Martin: 42730: Completion/Unix/Command/_rmdir,
diff --git a/Src/exec.c b/Src/exec.c
index 64cf5ae46..08c4ea95a 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1878,8 +1878,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 +1898,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 +1923,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]);
}
}
@@ -2710,7 +2662,8 @@ 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)
+ LinkList *filelistp, char *text, int oautocont,
+ int close_if_forked)
{
pid_t pid;
int synch[2], flags;
@@ -2766,6 +2719,7 @@ execcmd_fork(Estate state, int how, int type, Wordcode varspc,
*filelistp = jobtab[thisjob].filelist;
entersubsh(flags);
close(synch[1]);
+ zclose(close_if_forked);
if (sigtrapped[SIGINT] & ZSIG_IGNORED)
holdintr();
@@ -2786,7 +2740,7 @@ execcmd_fork(Estate state, int how, int type, Wordcode varspc,
/**/
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;
@@ -2863,6 +2817,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 *
@@ -2871,7 +2848,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
@@ -2918,8 +2895,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;
@@ -3097,6 +3077,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
zerr("unknown exec flag -%c", *cmdopt);
lastval = 1;
errflag |= ERRFLAG_ERROR;
+ if (forked)
+ _exit(lastval);
return;
}
}
@@ -3146,28 +3128,6 @@ execcmd_exec(Estate state, Execcmd_params eparams,
esprefork = (magic_assign ||
(isset(MAGICEQUALSUBST) && type != WC_TYPESET)) ?
PREFORK_TYPESET : 0;
- if (how & Z_ASYNC) {
- /*
- * If running in the background, we don't need any of
- * the rest of this functino 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)) {
- case -1:
- goto fatal;
- case 0:
- break;
- default:
- return;
- }
- forked = 1;
- } else
- text = NULL;
if (args) {
if (eparams->htok)
@@ -3212,6 +3172,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)
@@ -3230,6 +3192,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
}
} else if ((cflags & BINF_PREFIX) && (cflags & BINF_COMMAND)) {
lastval = 0;
+ if (forked)
+ _exit(lastval);
return;
} else {
/*
@@ -3240,6 +3204,8 @@ 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;
@@ -3253,12 +3219,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;
}
@@ -3293,6 +3263,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
+ if (forked)
+ _exit(lastval);
return;
}
break;
@@ -3301,8 +3273,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;
@@ -3317,6 +3292,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
+ if (forked)
+ _exit(lastval);
return;
}
@@ -3394,6 +3371,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
+ if (forked)
+ _exit(lastval);
return;
}
}
@@ -3422,6 +3401,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
+ if (forked)
+ _exit(lastval);
return;
}
@@ -3497,7 +3478,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
(!is_cursh && (last1 != 1 || nsigtrapped || havefiles() ||
fdtable_flocks)))) {
switch (execcmd_fork(state, how, type, varspc, &filelist,
- text, oautocont)) {
+ text, oautocont, close_if_forked)) {
case -1:
goto fatal;
case 0: