@@ -27,7 +27,7 @@ use std::io::{self, Write};
2727use std:: ops:: Deref ;
2828
2929#[ cfg( unix) ]
30- use std:: os:: unix:: process:: ExitStatusExt ;
30+ use std:: os:: unix:: process:: { CommandExt , ExitStatusExt } ;
3131use std:: process:: { self } ;
3232use uucore:: display:: Quotable ;
3333use uucore:: error:: { ExitCode , UError , UResult , USimpleError , UUsageError } ;
@@ -48,6 +48,7 @@ struct Options<'a> {
4848 unsets : Vec < & ' a OsStr > ,
4949 sets : Vec < ( Cow < ' a , OsStr > , Cow < ' a , OsStr > ) > ,
5050 program : Vec < & ' a OsStr > ,
51+ argv0 : Option < & ' a OsStr > ,
5152}
5253
5354// print name=value env pairs on screen
@@ -173,7 +174,7 @@ pub fn uu_app() -> Command {
173174 Arg :: new ( "debug" )
174175 . short ( 'v' )
175176 . long ( "debug" )
176- . action ( ArgAction :: SetTrue )
177+ . action ( ArgAction :: Count )
177178 . help ( "print verbose information for each processing step" ) ,
178179 )
179180 . arg (
@@ -184,6 +185,16 @@ pub fn uu_app() -> Command {
184185 . action ( ArgAction :: Set )
185186 . value_parser ( ValueParser :: os_string ( ) )
186187 . help ( "process and split S into separate arguments; used to pass multiple arguments on shebang lines" )
188+ ) . arg (
189+ Arg :: new ( "argv0" )
190+ . overrides_with ( "argv0" )
191+ . short ( 'a' )
192+ . long ( "argv0" )
193+ . value_name ( "a" )
194+ . action ( ArgAction :: Set )
195+ . value_parser ( ValueParser :: os_string ( ) )
196+ . help ( "Override the zeroth argument passed to the command being executed.\
197+ Without this option a default value of `command` is used.")
187198 )
188199 . arg (
189200 Arg :: new ( "vars" )
@@ -248,6 +259,7 @@ fn check_and_handle_string_args(
248259#[ derive( Default ) ]
249260struct EnvAppData {
250261 do_debug_printing : bool ,
262+ do_input_debug_printing : Option < bool > ,
251263 had_string_argument : bool ,
252264}
253265
@@ -273,14 +285,19 @@ impl EnvAppData {
273285 b if check_and_handle_string_args ( b, "-S" , & mut all_args, None ) ? => {
274286 self . had_string_argument = true ;
275287 }
288+ b if check_and_handle_string_args ( b, "-vS" , & mut all_args, None ) ? => {
289+ self . do_debug_printing = true ;
290+ self . had_string_argument = true ;
291+ }
276292 b if check_and_handle_string_args (
277293 b,
278- "-vS " ,
294+ "-vvS " ,
279295 & mut all_args,
280296 Some ( original_args) ,
281297 ) ? =>
282298 {
283299 self . do_debug_printing = true ;
300+ self . do_input_debug_printing = Some ( false ) ; // already done
284301 self . had_string_argument = true ;
285302 }
286303 _ => {
@@ -323,10 +340,15 @@ impl EnvAppData {
323340 fn run_env ( & mut self , original_args : impl uucore:: Args ) -> UResult < ( ) > {
324341 let ( original_args, matches) = self . parse_arguments ( original_args) ?;
325342
326- let did_debug_printing_before = self . do_debug_printing ; // could have been done already as part of the "-vS" string parsing
327- let do_debug_printing = self . do_debug_printing || matches. get_flag ( "debug" ) ;
328- if do_debug_printing && !did_debug_printing_before {
329- debug_print_args ( & original_args) ;
343+ self . do_debug_printing = self . do_debug_printing || ( 0 != matches. get_count ( "debug" ) ) ;
344+ self . do_input_debug_printing = self
345+ . do_input_debug_printing
346+ . or ( Some ( matches. get_count ( "debug" ) >= 2 ) ) ;
347+ if let Some ( value) = self . do_input_debug_printing {
348+ if value {
349+ debug_print_args ( & original_args) ;
350+ self . do_input_debug_printing = Some ( false ) ;
351+ }
330352 }
331353
332354 let mut opts = make_options ( & matches) ?;
@@ -349,7 +371,7 @@ impl EnvAppData {
349371 // no program provided, so just dump all env vars to stdout
350372 print_env ( opts. line_ending ) ;
351373 } else {
352- return self . run_program ( opts, do_debug_printing) ;
374+ return self . run_program ( opts, self . do_debug_printing ) ;
353375 }
354376
355377 Ok ( ( ) )
@@ -361,22 +383,48 @@ impl EnvAppData {
361383 do_debug_printing : bool ,
362384 ) -> Result < ( ) , Box < dyn UError > > {
363385 let prog = Cow :: from ( opts. program [ 0 ] ) ;
386+ #[ cfg( unix) ]
387+ let mut arg0 = prog. clone ( ) ;
388+ #[ cfg( not( unix) ) ]
389+ let arg0 = prog. clone ( ) ;
364390 let args = & opts. program [ 1 ..] ;
365- if do_debug_printing {
366- eprintln ! ( "executable: {}" , prog. quote( ) ) ;
367- for ( i, arg) in args. iter ( ) . enumerate ( ) {
368- eprintln ! ( "arg[{}]: {}" , i, arg. quote( ) ) ;
369- }
370- }
371- // we need to execute a command
372391
373392 /*
374393 * On Unix-like systems Command::status either ends up calling either fork or posix_spawnp
375394 * (which ends up calling clone). Keep using the current process would be ideal, but the
376395 * standard library contains many checks and fail-safes to ensure the process ends up being
377396 * created. This is much simpler than dealing with the hassles of calling execvp directly.
378397 */
379- match process:: Command :: new ( & * prog) . args ( args) . status ( ) {
398+ let mut cmd = process:: Command :: new ( & * prog) ;
399+ cmd. args ( args) ;
400+
401+ if let Some ( _argv0) = opts. argv0 {
402+ #[ cfg( unix) ]
403+ {
404+ cmd. arg0 ( _argv0) ;
405+ arg0 = Cow :: Borrowed ( _argv0) ;
406+ if do_debug_printing {
407+ eprintln ! ( "argv0: {}" , arg0. quote( ) ) ;
408+ }
409+ }
410+
411+ #[ cfg( not( unix) ) ]
412+ return Err ( USimpleError :: new (
413+ 2 ,
414+ "--argv0 is currently not supported on this platform" ,
415+ ) ) ;
416+ }
417+
418+ if do_debug_printing {
419+ eprintln ! ( "executing: {}" , prog. maybe_quote( ) ) ;
420+ let arg_prefix = " arg" ;
421+ eprintln ! ( "{}[{}]= {}" , arg_prefix, 0 , arg0. quote( ) ) ;
422+ for ( i, arg) in args. iter ( ) . enumerate ( ) {
423+ eprintln ! ( "{}[{}]= {}" , arg_prefix, i + 1 , arg. quote( ) ) ;
424+ }
425+ }
426+
427+ match cmd. status ( ) {
380428 Ok ( exit) if !exit. success ( ) => {
381429 #[ cfg( unix) ]
382430 if let Some ( exit_code) = exit. code ( ) {
@@ -443,6 +491,7 @@ fn make_options(matches: &clap::ArgMatches) -> UResult<Options<'_>> {
443491 Some ( v) => v. map ( |s| s. as_os_str ( ) ) . collect ( ) ,
444492 None => Vec :: with_capacity ( 0 ) ,
445493 } ;
494+ let argv0 = matches. get_one :: < OsString > ( "argv0" ) . map ( |s| s. as_os_str ( ) ) ;
446495
447496 let mut opts = Options {
448497 ignore_env,
@@ -452,6 +501,7 @@ fn make_options(matches: &clap::ArgMatches) -> UResult<Options<'_>> {
452501 unsets,
453502 sets : vec ! [ ] ,
454503 program : vec ! [ ] ,
504+ argv0,
455505 } ;
456506
457507 let mut begin_prog_opts = false ;
0 commit comments