]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
env: add -a,--argv0 to set the first argument passed to exec
authorPádraig Brady <P@draigBrady.com>
Thu, 2 Mar 2023 14:56:18 +0000 (11:56 -0300)
committerPádraig Brady <P@draigBrady.com>
Fri, 22 Mar 2024 13:12:52 +0000 (13:12 +0000)
Using the shell's exec -a feature can be awkward
so add support for setting overriding argv[0].
This gives env full control over the arguments it passes.

* src/env.c: Accept -a,--argv0 and set argv[0] appropriately.
* tests/env/env.sh: Add test cases.
* doc/coreutils.texi (env invocation): Describe -a,--argv0.
* NEWS: Mention the new feature.

NEWS
doc/coreutils.texi
src/env.c
tests/env/env.sh

diff --git a/NEWS b/NEWS
index cb47621880657c03170d276af445950581b2eba6..a6ec7c6ef9b0c4027f3c7ce0d70879732daa8850 100644 (file)
--- 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 -a,--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.
index 37d72908936bb5862b83aa14ebc9983345d3bef8..8a21048317b88f833921d81820b433e9d4cf6c6c 100644 (file)
@@ -17950,6 +17950,13 @@ Options must precede operands.
 
 @optNull
 
+@item -a @var{arg}
+@itemx --argv0=@var{arg}
+@opindex -a
+@opindex --argv0
+Override 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
index ed6628f8f1beaa5466ea18028d98717a5dd15f9c..af876fa08b4ba01de30919b3115d9f3d222201ef 100644 (file)
--- 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);
index 1a4b1a53fe51c78765bf39fe5802eaf328000fc2..d8f520299a5e45c77bf8f146f9a2ff079abce590 100755 (executable)
@@ -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