22//
33// For the full copyright and license information, please view the LICENSE
44// file that was distributed with this source code.
5- // spell-checker:ignore (vars) RFILE
5+ // spell-checker:ignore (vars) RFILE execv execvp
66#![ cfg( target_os = "linux" ) ]
77
88use clap:: builder:: ValueParser ;
@@ -48,7 +48,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
4848 . map_err ( RunconError :: new) ?;
4949 // On successful execution, the following call never returns,
5050 // and this process image is replaced.
51- execute_command ( command, & options. arguments )
51+ // PlainContext mode uses PATH search (like execvp).
52+ execute_command ( command, & options. arguments , false )
5253 }
5354 CommandLineMode :: CustomContext {
5455 compute_transition_context,
@@ -72,7 +73,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
7273 . map_err ( RunconError :: new) ?;
7374 // On successful execution, the following call never returns,
7475 // and this process image is replaced.
75- execute_command ( command, & options. arguments )
76+ // With -c flag, skip PATH search (like execv vs execvp).
77+ execute_command ( command, & options. arguments , * compute_transition_context)
7678 }
7779 None => print_current_context ( ) . map_err ( |e| RunconError :: new ( e) . into ( ) ) ,
7880 }
@@ -367,8 +369,21 @@ fn get_custom_context(
367369/// However, until the *never* type is stabilized, one way to indicate to the
368370/// compiler the only valid return type is to say "if this returns, it will
369371/// always return an error".
370- fn execute_command ( command : & OsStr , arguments : & [ OsString ] ) -> UResult < ( ) > {
371- let err = process:: Command :: new ( command) . args ( arguments) . exec ( ) ;
372+ ///
373+ /// When `skip_path_search` is true (used with `-c` flag), the command is executed
374+ /// without PATH lookup, matching GNU's use of execv() vs execvp().
375+ fn execute_command ( command : & OsStr , arguments : & [ OsString ] , skip_path_search : bool ) -> UResult < ( ) > {
376+ // When skip_path_search is true and command has no path separator,
377+ // prepend "./" to prevent PATH lookup (like execv vs execvp).
378+ let command_path = if skip_path_search && !command. as_bytes ( ) . contains ( & b'/' ) {
379+ let mut path = OsString :: from ( "./" ) ;
380+ path. push ( command) ;
381+ path
382+ } else {
383+ command. to_os_string ( )
384+ } ;
385+
386+ let err = process:: Command :: new ( & command_path) . args ( arguments) . exec ( ) ;
372387
373388 let exit_status = if err. kind ( ) == io:: ErrorKind :: NotFound {
374389 error_exit_status:: NOT_FOUND
0 commit comments