git: 7262e60119b8 - main - sh: Allow vfork on redirected simple commands
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 25 Apr 2026 13:04:53 UTC
The branch main has been updated by jilles:
URL: https://cgit.FreeBSD.org/src/commit/?id=7262e60119b8840ee400d281421b8e65d8af9d84
commit 7262e60119b8840ee400d281421b8e65d8af9d84
Author: Jilles Tjoelker <jilles@FreeBSD.org>
AuthorDate: 2026-04-25 13:03:29 +0000
Commit: Jilles Tjoelker <jilles@FreeBSD.org>
CommitDate: 2026-04-25 13:04:10 +0000
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
---
bin/sh/eval.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 58 insertions(+), 3 deletions(-)
diff --git a/bin/sh/eval.c b/bin/sh/eval.c
index d0fddf160771..0c41c5e69eea 100644
--- a/bin/sh/eval.c
+++ b/bin/sh/eval.c
@@ -34,6 +34,7 @@
#include <paths.h>
#include <signal.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>
@@ -803,6 +804,50 @@ safe_builtin(int idx, int argc, char **argv)
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.
* 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));
}
if (cmdentry.cmdtype == CMDNORMAL &&
- cmd->ncmd.redirect == NULL &&
+ (cmd->ncmd.redirect == NULL || (flags & EV_BACKCMD) == 0) &&
varlist.count == 0 &&
(mode == FORK_FG || mode == FORK_NOJOB) &&
!disvforkset() && !iflag && !mflag) {
- vforkexecshell(jp, argv, environment(), path,
- cmdentry.u.index, flags & EV_BACKCMD ? pip : NULL);
+ if (cmd->ncmd.redirect != 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;
}
if (forkshell(jp, cmd, mode) != 0)