env: Add a handful of test cases.

MFC after:	3 days
Sponsored by:	Klara, Inc.
Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D46996

(cherry picked from commit 334af5e4131b21c658203635bf713d6a59846585)

env: Improve documentation.

* The `env` utility's inability to run a command whose name contains an
  equal sign is a feature, not a bug, so move that paragraph up from the
  BUGS section to the DESCRIPTION section.

* Mention that this can be worked around by prefixing the command name
  with `command`, and add an example of this to the EXAMPLE section.

* Add a test case which verifies that `env` does not run a command with
  an equal sign in its name even if it exists, and also demonstrates the
  workaround.

MFC after:	3 days
Sponsored by:	Klara, Inc.
Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D46997

(cherry picked from commit a0dfb0668b45506de97beb4c7acbe3fd1ba69fc8)

env: Add an option to change the directory.

This mirrors the equivalent option in GNU coreutils env, but does not
add support for long options.

MFC after:	3 days
Relnotes:	yes
Sponsored by:	Klara, Inc.
Reviewed by:	0mp, bcr
Differential Revision:	https://reviews.freebsd.org/D47008

(cherry picked from commit 6f6166e49c78f6460732c02bbbba6fcc218221cf)

env: Check the status of stdout.

MFC after:	3 days
Sponsored by:	Klara, Inc.
Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D47009

(cherry picked from commit c2d93a803acef634bd0eede6673aeea59e90c277)
This commit is contained in:
Dag-Erling Smørgrav 2024-10-07 23:00:17 +02:00
parent 76c656bd97
commit 08e8554c4a
6 changed files with 222 additions and 15 deletions

View file

@ -1057,6 +1057,8 @@
..
du
..
env
..
factor
..
file2c

View file

@ -1,4 +1,5 @@
# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
.include <src.opts.mk>
PACKAGE= runtime
PROG= env
@ -6,4 +7,7 @@ SRCS= env.c envopts.c
LIBADD= util
HAS_TESTS=
SUBDIR.${MK_TESTS}= tests
.include <bsd.prog.mk>

41
usr.bin/env/env.1 vendored
View file

@ -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 March 3, 2021
.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
@ -173,6 +180,19 @@ Both
and
.Ar utility
may not be specified together.
.Pp
The
.Nm
utility does not handle values of
.Ar utility
which have an equals sign
.Pq Ql =
in their name, for obvious reasons.
This can easily be worked around by interposing the
.Xr command 1
utility, which simply executes its arguments; see
.Sx EXAMPLES
below.
.\"
.Ss Details of -S (split-string) processing
The processing of the
@ -471,6 +491,11 @@ and
options:
.Pp
.Dl "#!/usr/bin/env -S-P/usr/local/bin:/usr/bin:${PATH} perl"
.Pp
To execute a utility with an equal sign in its name:
.Bd -literal -offset indent
env name=value ... command foo=bar arg ...
.Ed
.Sh COMPATIBILITY
The
.Nm
@ -490,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
@ -513,15 +538,11 @@ and
.Fl U
options were added in
.Fx 13.0 .
.Sh BUGS
The
.Nm
utility does not handle values of
.Ar utility
which have an equals sign
.Pq Ql =
in their name, for obvious reasons.
.Pp
.Fl C
option was added in
.Fx 14.2 .
.Sh BUGS
The
.Nm
utility does not take multibyte characters into account when

24
usr.bin/env/env.c vendored
View file

@ -72,7 +72,7 @@ static void usage(void) __dead2;
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,9 +219,16 @@ 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);
if (fflush(stdout) != 0)
err(1, "stdout");
exit(0);
}
@ -222,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);
}

6
usr.bin/env/tests/Makefile vendored Normal file
View file

@ -0,0 +1,6 @@
PACKAGE= tests
ATF_TESTS_SH= env_test
BINDIR= ${TESTSDIR}
.include <bsd.test.mk>

160
usr.bin/env/tests/env_test.sh vendored Normal file
View file

@ -0,0 +1,160 @@
#
# Copyright (c) 2024 Klara, Inc.
#
# SPDX-License-Identifier: BSD-2-Clause
#
magic_words="Squeamish $$ Ossifrage"
atf_test_case basic
basic_head()
{
atf_set "descr" "Basic test case"
}
basic_body()
{
atf_check -o match:"^magic_words=${magic_words}\$" \
env magic_words="${magic_words}"
export MAGIC_WORDS="${magic_words}"
atf_check -o match:"^MAGIC_WORDS=${magic_words}\$" \
env
unset MAGIC_WORDS
}
atf_test_case unset
unset_head()
{
atf_set "descr" "Unset a variable"
}
unset_body()
{
export MAGIC_WORDS="${magic_words}"
atf_check -o not-match:"^MAGIC_WORDS=" \
env -u MAGIC_WORDS
unset MAGIC_WORDS
}
atf_test_case empty
empty_head()
{
atf_set "descr" "Empty environment"
}
empty_body()
{
atf_check env -i
}
atf_test_case true
true_head()
{
atf_set "descr" "Run true"
}
true_body()
{
atf_check env true
}
atf_test_case false
false_head()
{
atf_set "descr" "Run false"
}
false_body()
{
atf_check -s exit:1 env false
}
atf_test_case false
false_head()
{
atf_set "descr" "Run false"
}
false_body()
{
atf_check -s exit:1 env false
}
atf_test_case altpath
altpath_head()
{
atf_set "descr" "Use alternate path"
}
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" \
env -P "${PWD}" magic_words
}
atf_test_case equal
equal_head()
{
atf_set "descr" "Command name contains equal sign"
}
equal_body()
{
echo "echo ${magic_words}" >"magic=words"
chmod 0755 "magic=words"
atf_check -o match:"^${PWD}/magic=words$" \
env "${PWD}/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"
atf_check -o inline:"${magic_words}\n" \
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()
{
atf_set descr "Failure to write to stdout"
}
stdout_body()
{
(
trap "" PIPE
env 2>stderr
echo $? >result
) | true
atf_check -o inline:"1\n" cat result
atf_check -o match:"stdout" cat stderr
}
atf_init_test_cases()
{
atf_add_test_case basic
atf_add_test_case unset
atf_add_test_case empty
atf_add_test_case true
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
}