sh: Allow vfork on redirected simple commands
Things like `{ some_program; } >/dev/null` use vfork, so use vfork
similarly for things like `some_program >/dev/null`.
This cannot be done for command substitutions, because of two problems:
* Redirections might cause the error message for later redirections or
for an unknown command to be sent to the pipe (to be substituted), and
this might cause a deadlock if the message is too long.
* The assignment of the pipe needs to come before instead of after the
redirections.
Reviewed by: bdrewery
Differential Revision: https://reviews.freebsd.org/D55190
This commit is contained in:
+58
-3
@@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
@@ -803,6 +804,50 @@ safe_builtin(int idx, int argc, char **argv)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform redirections, then execute a simple command with vfork.
|
||||||
|
* This cannot be used for command substitutions for two reasons:
|
||||||
|
* - Redirections might cause the error message for later redirections or for
|
||||||
|
* an unknown command to be sent to the pipe (to be substituted), and this
|
||||||
|
* might cause a deadlock if the message is too long.
|
||||||
|
* - The assignment of the pipe needs to come before instead of after the
|
||||||
|
* redirections.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
redirected_vforkexecshell(struct job *jp, union node *redir, char **argv,
|
||||||
|
char **envp, const char *path, int idx)
|
||||||
|
{
|
||||||
|
struct jmploc jmploc;
|
||||||
|
struct jmploc *savehandler;
|
||||||
|
volatile int in_redirect = 1;
|
||||||
|
|
||||||
|
savehandler = handler;
|
||||||
|
if (setjmp(jmploc.loc)) {
|
||||||
|
int e;
|
||||||
|
|
||||||
|
handler = savehandler;
|
||||||
|
e = exception;
|
||||||
|
popredir();
|
||||||
|
if (e == EXERROR && in_redirect) {
|
||||||
|
FORCEINTON;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
longjmp(handler->loc, 1);
|
||||||
|
} else {
|
||||||
|
INTOFF;
|
||||||
|
handler = &jmploc;
|
||||||
|
redirect(redir, REDIR_PUSH);
|
||||||
|
in_redirect = 0;
|
||||||
|
INTON;
|
||||||
|
vforkexecshell(jp, argv, envp, path, idx, NULL);
|
||||||
|
}
|
||||||
|
INTOFF;
|
||||||
|
handler = savehandler;
|
||||||
|
popredir();
|
||||||
|
INTON;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute a simple command.
|
* Execute a simple command.
|
||||||
* Note: This may or may not return if (flags & EV_EXIT).
|
* Note: This may or may not return if (flags & EV_EXIT).
|
||||||
@@ -986,12 +1031,22 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
|||||||
error("Pipe call failed: %s", strerror(errno));
|
error("Pipe call failed: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
if (cmdentry.cmdtype == CMDNORMAL &&
|
if (cmdentry.cmdtype == CMDNORMAL &&
|
||||||
cmd->ncmd.redirect == NULL &&
|
(cmd->ncmd.redirect == NULL || (flags & EV_BACKCMD) == 0) &&
|
||||||
varlist.count == 0 &&
|
varlist.count == 0 &&
|
||||||
(mode == FORK_FG || mode == FORK_NOJOB) &&
|
(mode == FORK_FG || mode == FORK_NOJOB) &&
|
||||||
!disvforkset() && !iflag && !mflag) {
|
!disvforkset() && !iflag && !mflag) {
|
||||||
vforkexecshell(jp, argv, environment(), path,
|
if (cmd->ncmd.redirect != NULL) {
|
||||||
cmdentry.u.index, flags & EV_BACKCMD ? pip : NULL);
|
if (redirected_vforkexecshell(jp,
|
||||||
|
cmd->ncmd.redirect,
|
||||||
|
argv, environment(), path,
|
||||||
|
cmdentry.u.index))
|
||||||
|
goto parent;
|
||||||
|
else
|
||||||
|
goto out;
|
||||||
|
} else
|
||||||
|
vforkexecshell(jp, argv, environment(), path,
|
||||||
|
cmdentry.u.index,
|
||||||
|
flags & EV_BACKCMD ? pip : NULL);
|
||||||
goto parent;
|
goto parent;
|
||||||
}
|
}
|
||||||
if (forkshell(jp, cmd, mode) != 0)
|
if (forkshell(jp, cmd, mode) != 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user