From 83c57e10c81650bb980e942622973e8a7bb8cbba Mon Sep 17 00:00:00 2001 From: Lucas Holt <luke@foolishgames.com> Date: Tue, 3 Dec 2024 13:15:31 -0500 Subject: [PATCH] add support for alternate working directory, similar to GNU version. Based on freebsd 14 stable cahnge from FreeBSD --- usr.bin/env/Makefile.depend | 1 + usr.bin/env/env.1 | 15 +++++++++++++-- usr.bin/env/env.c | 24 ++++++++++++++++++------ usr.bin/env/tests/env_test.sh | 25 ++++++++++++++++++++++++- 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/usr.bin/env/Makefile.depend b/usr.bin/env/Makefile.depend index 84b8ddd67e..ffc295f2fe 100644 --- a/usr.bin/env/Makefile.depend +++ b/usr.bin/env/Makefile.depend @@ -7,6 +7,7 @@ DIRDEPS = \ lib/${CSU_DIR} \ lib/libc \ lib/libcompiler_rt \ + lib/libutil \ .include <dirdeps.mk> diff --git a/usr.bin/env/env.1 b/usr.bin/env/env.1 index 6858a6465b..4badea7161 100644 --- a/usr.bin/env/env.1 +++ b/usr.bin/env/env.1 @@ -30,7 +30,7 @@ .\" From @(#)printenv.1 8.1 (Berkeley) 6/6/93 .\" From FreeBSD: src/usr.bin/printenv/printenv.1,v 1.17 2002/11/26 17:33:35 ru Exp .\" -.Dd October 7, 2024 +.Dd October 8, 2024 .Dt ENV 1 .Os .Sh NAME @@ -44,6 +44,7 @@ .Op Ar name Ns = Ns Ar value ... .Nm .Op Fl iv +.Op Fl C Ar altwd .Op Fl L Ns | Ns Fl U Ar user Ns Op / Ns Ar class .Op Fl P Ar altpath .Op Fl S Ar string @@ -81,6 +82,12 @@ The environment inherited by .Nm is ignored completely. +.\" -C +.It Fl C Ar altwd +Change to the specified alternate working directory before executing +the specified +.Ar utility +program. .\" -L | -U .It Fl L | Fl U Ar user Ns Op / Ns Ar class Add the environment variable definitions from @@ -508,7 +515,7 @@ The utility conforms to .St -p1003.1-2001 . The -.Fl 0 , L , P , S , U , u +.Fl 0 , C , L , P , S , U , u and .Fl v options are non-standard extensions supported by @@ -531,6 +538,10 @@ and .Fl U options were added in .Fx 13.0 . +The +.Fl C +option was added in +.Fx 14.2 . .Sh BUGS The .Nm diff --git a/usr.bin/env/env.c b/usr.bin/env/env.c index 3b7627e534..724a17d8be 100644 --- a/usr.bin/env/env.c +++ b/usr.bin/env/env.c @@ -60,7 +60,7 @@ extern char **environ; int env_verbosity; -static void usage(void); +static void usage(void) __dead2; /* * Exit codes. @@ -72,7 +72,7 @@ static void usage(void); int main(int argc, char **argv) { - char *altpath, **ep, *p, **parg, term; + char *altpath, *altwd, **ep, *p, **parg, term; char *cleanenv[1]; char *login_class, *login_name; struct passwd *pw; @@ -83,6 +83,7 @@ main(int argc, char **argv) int rtrn; altpath = NULL; + altwd = NULL; login_class = NULL; login_name = NULL; pw = NULL; @@ -90,7 +91,7 @@ main(int argc, char **argv) login_as_user = false; want_clear = 0; term = '\n'; - while ((ch = getopt(argc, argv, "-0iL:P:S:U:u:v")) != -1) + while ((ch = getopt(argc, argv, "-0C:iL:P:S:U:u:v")) != -1) switch(ch) { case '-': case 'i': @@ -99,6 +100,9 @@ main(int argc, char **argv) case '0': term = '\0'; break; + case 'C': + altwd = optarg; + break; case 'U': login_as_user = true; /* FALLTHROUGH */ @@ -106,7 +110,7 @@ main(int argc, char **argv) login_name = optarg; break; case 'P': - altpath = strdup(optarg); + altpath = optarg; break; case 'S': /* @@ -199,6 +203,9 @@ main(int argc, char **argv) if (*argv) { if (term == '\0') errx(EXIT_CANCELED, "cannot specify command with -0"); + if (altwd && chdir(altwd) != 0) + err(EXIT_CANCELED, "cannot change directory to '%s'", + altwd); if (altpath) search_paths(altpath, argv); if (env_verbosity) { @@ -212,6 +219,11 @@ main(int argc, char **argv) execvp(*argv, argv); err(errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE, "%s", *argv); + } else { + if (altwd) + errx(EXIT_CANCELED, "must specify command with -C"); + if (altpath) + errx(EXIT_CANCELED, "must specify command with -P"); } for (ep = environ; *ep; ep++) (void)printf("%s%c", *ep, term); @@ -224,7 +236,7 @@ static void usage(void) { (void)fprintf(stderr, - "usage: env [-0iv] [-L|-U user[/class]] [-P utilpath] [-S string] [-u name]\n" - " [name=value ...] [utility [argument ...]]\n"); + "usage: env [-0iv] [-C workdir] [-L|-U user[/class]] [-P utilpath] [-S string]\n" + " [-u name] [name=value ...] [utility [argument ...]]\n"); exit(1); } diff --git a/usr.bin/env/tests/env_test.sh b/usr.bin/env/tests/env_test.sh index a3e05c0502..2dc8f1a4c9 100644 --- a/usr.bin/env/tests/env_test.sh +++ b/usr.bin/env/tests/env_test.sh @@ -83,6 +83,8 @@ altpath_body() { echo "echo ${magic_words}" >magic_words chmod 0755 magic_words + atf_check -s exit:125 -e match:"must specify command" \ + env -P "${PWD}" atf_check -s exit:127 -e match:"No such file" \ env magic_words atf_check -o inline:"${magic_words}\n" \ @@ -100,7 +102,7 @@ equal_body() chmod 0755 "magic=words" atf_check -o match:"^${PWD}/magic=words$" \ env "${PWD}/magic=words" - atf_check -o match:"^magic=words$" \ + atf_check -s exit:125 -e match:"must specify command" \ env -P "${PATH}:${PWD}" "magic=words" atf_check -o inline:"${magic_words}\n" \ env command "${PWD}/magic=words" @@ -108,6 +110,26 @@ equal_body() env PATH="${PATH}:${PWD}" command "magic=words" } +atf_test_case chdir +chdir_head() +{ + atf_set "descr" "Change working directory" +} +chdir_body() +{ + local subdir="dir.$$" + atf_check -o inline:"${PWD}\n" \ + env pwd + atf_check -s exit:125 -e match:"must specify command" \ + env -C "${subdir}" + atf_check -s exit:125 \ + -e match:"cannot change directory to '${subdir}':" \ + env -C "${subdir}" pwd + atf_check mkdir "${subdir}" + atf_check -o inline:"${PWD}/${subdir}\n" \ + env -C "${subdir}" pwd +} + atf_test_case stdout stdout_head() { @@ -133,5 +155,6 @@ atf_init_test_cases() atf_add_test_case false atf_add_test_case altpath atf_add_test_case equal + atf_add_test_case chdir atf_add_test_case stdout }