On 20/03/2024 23:19, Pádraig Brady wrote:
On 13/03/2024 10:19, Matheus Afonso Martins Moreira wrote:
About a year ago, I posted an env feature request on this list:
the ability to set the value of argv[0].
https://lists.gnu.org/archive/html/coreutils/2023-03/msg00002.html
I also sent a patch:
https://lists.gnu.org/archive/html/coreutils/2023-03/msg00003.html
After some discussion, I was informed it was under consideration:
https://lists.gnu.org/archive/html/coreutils/2023-03/msg00012.html
We're still considering and will adjust as needed.
I waited a while and eventually sent an email about it:
https://lists.gnu.org/archive/html/coreutils/2023-08/msg00059.html
The maintainer noted that they expected this feature to be included
in the next release which would be focused on features:
https://lists.gnu.org/archive/html/coreutils/2023-08/msg00060.html
The next release will focus on new features, and this
will be considered. I expect this feature will be included.
Since then I've been tracking commits to the coreutils master branch
but it appears the feature has not landed yet.
What happened? Was it rejected?
Thanks for your patience.
I've attached an implementation for --argv0
which I intend to apply for the impending release.
Note this can accept empty and NULL values,
and so now gives env full control of the args it passes on.
In testing this on a newer Linux kernel I see that argv[0] == NULL
is converted to an empty string instead.
That was one of the proposals at https://lwn.net/Articles/882799/
and I see it was implemented on kernels >= 5.18:
https://github.com/torvalds/linux/commit/dcd46d89
So in retrospect it's probably not worth supporting a NULL argv0,
as newer kernels won't pass it. Also with a NULL argv0,
the kernel puts the environ array directly after the first NULL,
and so will discard any other params passed to env,
which would be confusing to users.
Version 2 attached, now makes --argv0 require an argument.
thanks,
Pádraig.
From 38653861b6e353e9f306d92e2e96179040e5b9d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com>
Date: Thu, 2 Mar 2023 11:56:18 -0300
Subject: [PATCH] env: add --argv0 to set the first argument passed to exec
Using the shell's exec -a feature can be awkward
so add support for setting argv0 to arbitrary values.
This gives env full control over the arguments it passes.
* src/env.c: Accept --argv0 and set argv[0] appropriately.
* tests/env/env.sh: Add test cases.
* doc/coreutils.texi (env invocation): Describe --argv0.
* NEWS: Mention the new feature.
---
NEWS | 3 +++
doc/coreutils.texi | 7 +++++++
src/env.c | 31 ++++++++++++++++++++++++++-----
tests/env/env.sh | 10 ++++++++++
4 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/NEWS b/NEWS
index cb4762188..4110cafaf 100644
--- a/NEWS
+++ b/NEWS
@@ -92,6 +92,9 @@ GNU coreutils NEWS -*- outline -*-
and the command exits with failure status if existing files.
The -n,--no-clobber option is best avoided due to platform differences.
+ env now accepts the --argv0 option to override the zeroth argument
+ of the command being executed.
+
mv now accepts an --exchange option, which causes the source and
destination to be exchanged. It should be combined with
--no-target-directory (-T) if the destination is a directory.
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index e36269588..5f7646039 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -17948,6 +17948,13 @@ Options must precede operands.
@optNull
+@item -a @var{arg}
+@itemx --argv0=@var{arg}
+@opindex -a
+@opindex --argv0
+Override the the zeroth argument passed to the command being executed.
+Without this option a default value of @var{command} is used.
+
@item -u @var{name}
@itemx --unset=@var{name}
@opindex -u
diff --git a/src/env.c b/src/env.c
index ed6628f8f..af876fa08 100644
--- a/src/env.c
+++ b/src/env.c
@@ -73,7 +73,7 @@ static bool report_signal_handling;
/* The isspace characters in the C locale. */
#define C_ISSPACE_CHARS " \t\n\v\f\r"
-static char const shortopts[] = "+C:iS:u:v0" C_ISSPACE_CHARS;
+static char const shortopts[] = "+a:C:iS:u:v0" C_ISSPACE_CHARS;
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
@@ -87,6 +87,7 @@ enum
static struct option const longopts[] =
{
+ {"argv0", required_argument, nullptr, 'a'},
{"ignore-environment", no_argument, nullptr, 'i'},
{"null", no_argument, nullptr, '0'},
{"unset", required_argument, nullptr, 'u'},
@@ -118,6 +119,9 @@ Set each NAME to VALUE in the environment and run COMMAND.\n\
emit_mandatory_arg_note ();
+ fputs (_("\
+ -a, --argv0=ARG pass ARG as the zeroth argument of COMMAND\n\
+"), stdout);
fputs (_("\
-i, --ignore-environment start with an empty environment\n\
-0, --null end each output line with NUL, not newline\n\
@@ -759,6 +763,7 @@ main (int argc, char **argv)
bool ignore_environment = false;
bool opt_nul_terminate_output = false;
char const *newdir = nullptr;
+ char *argv0 = nullptr;
initialize_main (&argc, &argv);
set_program_name (argv[0]);
@@ -775,6 +780,9 @@ main (int argc, char **argv)
{
switch (optc)
{
+ case 'a':
+ argv0 = optarg;
+ break;
case 'i':
ignore_environment = true;
break;
@@ -865,6 +873,12 @@ main (int argc, char **argv)
usage (EXIT_CANCELED);
}
+ if (argv0 && ! program_specified)
+ {
+ error (0, 0, _("must specify command with --argv0 (-a)"));
+ usage (EXIT_CANCELED);
+ }
+
if (! program_specified)
{
/* Print the environment and exit. */
@@ -890,19 +904,26 @@ main (int argc, char **argv)
quoteaf (newdir));
}
+ char *program = argv[optind];
+ if (argv0)
+ {
+ devmsg ("argv0: %s\n", quoteaf (argv0));
+ argv[optind] = argv0;
+ }
+
if (dev_debug)
{
- devmsg ("executing: %s\n", argv[optind]);
+ devmsg ("executing: %s\n", program);
for (int i=optind; i<argc; ++i)
devmsg (" arg[%d]= %s\n", i-optind, quote (argv[i]));
}
- execvp (argv[optind], &argv[optind]);
+ execvp (program, &argv[optind]);
int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
- error (0, errno, "%s", quote (argv[optind]));
+ error (0, errno, "%s", quote (program));
- if (exit_status == EXIT_ENOENT && strpbrk (argv[optind], C_ISSPACE_CHARS))
+ if (exit_status == EXIT_ENOENT && strpbrk (program, C_ISSPACE_CHARS))
error (0, 0, _("use -[v]S to pass options in shebang lines"));
main_exit (exit_status);
diff --git a/tests/env/env.sh b/tests/env/env.sh
index 1a4b1a53f..d8f520299 100755
--- a/tests/env/env.sh
+++ b/tests/env/env.sh
@@ -163,4 +163,14 @@ exp=$(cd empty && env pwd) || framework_failure_
got=$(env --chdir=empty pwd) || fail=1
test "$exp" = "$got" || fail=1
+# Verify argv0 overriding
+for arg in 'argv0' ''; do
+env -v -a short --argv0=$arg true 2>err || fail=1
+cat <<EOF >err_exp || framework_failure_
+argv0: '$arg'
+executing: true
+ arg[0]= '$arg'
+EOF
+done
+
Exit $fail
--
2.44.0