? 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