? env.diff
Index: env.1
===================================================================
RCS file: /cvsroot/src/usr.bin/env/env.1,v
retrieving revision 1.12
diff -u -p -u -r1.12 env.1
--- env.1	8 Jun 2007 18:20:42 -0000	1.12
+++ env.1	26 Sep 2014 19:17:36 -0000
@@ -32,7 +32,7 @@
 .\"	from: @(#)printenv.1	6.7 (Berkeley) 7/28/91
 .\"	$NetBSD: env.1,v 1.12 2007/06/08 18:20:42 wiz Exp $
 .\"
-.Dd June 8, 2007
+.Dd September 26, 2014
 .Dt ENV 1
 .Os
 .Sh NAME
@@ -52,6 +52,18 @@ executes
 .Ar utility
 after modifying the environment as
 specified on the command line.
+.Pp
+The utility is executed by seaching on the user's existing
+.Dv PATH
+environment variable, unless
+the
+.Dv PATH
+variable was specified as part of the executing environment on the command
+line.
+In that case the
+.Dv PATH
+used is the one specified on the command line.
+.Pp
 The option
 .Ar name=value
 specifies
Index: env.c
===================================================================
RCS file: /cvsroot/src/usr.bin/env/env.c,v
retrieving revision 1.20
diff -u -p -u -r1.20 env.c
--- env.c	16 Nov 2010 02:53:49 -0000	1.20
+++ env.c	26 Sep 2014 19:17:36 -0000
@@ -40,11 +40,13 @@ __RCSID("$NetBSD: env.c,v 1.20 2010/11/1
 
 #include <err.h>
 #include <stdio.h>
+#include <stdbool.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <locale.h>
 #include <errno.h>
+#include <err.h>
 
 static void usage(void) __attribute__((__noreturn__));
 
@@ -53,41 +55,88 @@ extern char **environ;
 int
 main(int argc, char **argv)
 {
-	char **ep;
-	char *cleanenv[1];
+	bool cleanenv;
+	char **envp, *p;
+	size_t entries;
 	int ch;
 
 	setprogname(*argv);
 	(void)setlocale(LC_ALL, "");
 
+	cleanenv = false;
+
 	while ((ch = getopt(argc, argv, "-i")) != -1)
 		switch((char)ch) {
 		case '-':			/* obsolete */
 		case 'i':
-			environ = cleanenv;
-			cleanenv[0] = NULL;
+			cleanenv = true;
 			break;
 		case '?':
 		default:
 			usage();
 		}
 
-	for (argv += optind; *argv && strchr(*argv, '=') != NULL; ++argv)
-		(void)putenv(*argv);
+	/*
+	 * Count environment slots.
+	 */
+	entries = 0;
+	if (!cleanenv)
+		for (char **ep = environ; *ep; ep++)
+			entries++;
+	for (char **ap = argv + optind; *ap && strchr(*ap, '=') != NULL; ++ap)
+		entries++;
+
+	envp = malloc((entries + 1) * sizeof(*envp));
+	if (envp == NULL)
+		err(EXIT_FAILURE, "malloc");
+
+	entries = 0;
+	if (!cleanenv)
+		for (char **ep = environ; *ep; ep++)
+			if ((envp[entries++] = strdup(*ep)) == NULL)
+				err(EXIT_FAILURE, "strdup");
+
+	for (argv += optind; *argv && (p = strchr(*argv, '=')) != NULL; ++argv)
+	{
+		/*
+		 * Check if PATH is specified on the command line, because we
+		 * have to use that path for searching per posix.
+		 */
+		if (strncmp("PATH=", *argv, 5) == 0)
+			(void)putenv(*argv);
+
+		char *cp = strdup(*argv);
+		if (cp == NULL)
+			err(EXIT_FAILURE, "strdup");
+
+		/*
+		 * See if we are replacing entries.
+		 */
+		for (size_t i = 0; i < entries; i++)
+			if (strncmp(envp[i], *argv, p - *argv + 1) == 0) {
+				free(envp[i]);
+				envp[i] = cp;
+				continue;
+			}
+
+		envp[entries++] = cp;
+	}
+
+	envp[entries] = NULL;
 
 	if (*argv) {
 		/* return 127 if the command to be run could not be found; 126
 		   if the command was found but could not be invoked */
 
-		(void)execvp(*argv, argv);
+		(void)execvpe(*argv, argv, envp);
 		err((errno == ENOENT) ? 127 : 126, "%s", *argv);
 		/* NOTREACHED */
 	}
 
-	for (ep = environ; *ep; ep++)
+	for (char **ep = envp; *ep; ep++)
 		(void)printf("%s\n", *ep);
 
-	exit(0);
+	return 0;
 }
 
 static void