From 284a27675c5d3274965a4fc312d3f410c090f25f Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sat, 6 Nov 2021 20:10:42 -0500 Subject: [PATCH] Fix env properly: env -i uses old $PATH, but use new PATH= when redefined. Also add QUIET macro to shut up gcc's "isn't actually used uninitalized" warnings, instead of doing the "int x=x;" trick. --- lib/portability.h | 5 +++++ tests/env.test | 3 ++- toys/posix/env.c | 30 +++++++++++++++++++++--------- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/lib/portability.h b/lib/portability.h index 67727f9c..4286b7b0 100644 --- a/lib/portability.h +++ b/lib/portability.h @@ -29,6 +29,11 @@ // Test for gcc (using compiler builtin #define) #ifdef __GNUC__ +#ifndef __clang__ +#define QUIET = 0 // shut up false positive "may be used uninitialized" warning +#else +#define QUIET +#endif #define printf_format __attribute__((format(printf, 1, 2))) #else #define printf_format diff --git a/tests/env.test b/tests/env.test index 30757be4..06ba680e 100755 --- a/tests/env.test +++ b/tests/env.test @@ -11,7 +11,8 @@ FILTER="| egrep '^(WALRUS|BANANA|LETTERS)=' | sort" testcmd "read" "$FILTER" "BANANA=hello\nLETTERS=\nWALRUS=42\n" "" "" testcmd "-u" "-u BANANA $FILTER" "LETTERS=\nWALRUS=42\n" "" "" testcmd "-uu" "-u LETTERS -u WALRUS $FILTER" "BANANA=hello\n" "" "" -testcmd "-i" "-i \"$(which env)\"" "" "" "" +testcmd "-i uses old \$PATH" "-i echo hello" "hello\n" "" "" +testcmd "-i env" "-i env" "" "" "" testcmd "-i =" "-i one=two three=four $C | sort" \ "one=two\nthree=four\n" "" "" testcmd "-0" "-i five=six seven=eight $C -0 | sort -z" "five=six\0seven=eight\0" "" "" diff --git a/toys/posix/env.c b/toys/posix/env.c index 750ba49a..8e560a25 100644 --- a/toys/posix/env.c +++ b/toys/posix/env.c @@ -4,6 +4,8 @@ * * http://opengroup.org/onlinepubs/9699919799/utilities/env.html * + * Note: env bypasses shell builtins, so don't xexec(). + * * Deviations from posix: "-" argument and -0 USE_ENV(NEWTOY(env, "^i0u*", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(125))) @@ -30,7 +32,8 @@ GLOBALS( void env_main(void) { - char **ev = toys.optargs; + char **ev = toys.optargs, **ee = 0, **set QUIET, *path = getenv("PATH"); + struct string_list *sl = 0; struct arg_list *u; // If first nonoption argument is "-" treat it as -i @@ -39,16 +42,25 @@ void env_main(void) ev++; } - if (FLAG(i)) xclearenv(); + if (FLAG(i)) ee = set = xzalloc(sizeof(void *)*(toys.optc+1)); else for (u = TT.u; u; u = u->next) xunsetenv(u->arg); - for (; *ev; ev++) - if (strchr(*ev, '=')) xsetenv(xstrdup(*ev), 0); - else { - // a common use of env is to bypass shell builtins - toys.stacktop = 0; - xexec(ev); + for (; *ev; ev++) { + if (strchr(*ev, '=')) { + if (FLAG(i)) *set++ = *ev; + else xsetenv(xstrdup(*ev), 0); + if (!strncmp(*ev, "PATH=", 5)) path=(*ev)+5; + } else { + // unfortunately, posix has no exec combining p and e, so do p ourselves + if (!strchr(*ev, '/') && path) { + errno = ENOENT; + for (sl = find_in_path(path, *ev); sl; sl = sl->next) + execve(sl->str, ev, ee ? : environ); + } else execve(*ev, ev, ee ? : environ); + perror_msg("exec %s", *ev); + _exit(126+(errno == ENOENT)); } + } - for (ev = environ; *ev; ev++) xprintf("%s%c", *ev, '\n'*!FLAG(0)); + for (ev = ee ? : environ; *ev; ev++) xprintf("%s%c", *ev, '\n'*!FLAG(0)); }