Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 25 Apr 2026 13:04:53 +0000
From:      Jilles Tjoelker <jilles@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 7262e60119b8 - main - sh: Allow vfork on redirected simple commands
Message-ID:  <69ecbbf5.27f24.19123d52@gitrepo.freebsd.org>

index | next in thread | raw e-mail

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)


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69ecbbf5.27f24.19123d52>