@@ -276,7 +276,7 @@ impl Command {
276
276
unsafe fn do_exec (
277
277
& mut self ,
278
278
stdio : ChildPipes ,
279
- maybe_envp : Option < & CStringArray > ,
279
+ mut maybe_envp : Option < & CStringArray > ,
280
280
) -> Result < !, io:: Error > {
281
281
use crate :: sys:: { self , cvt_r} ;
282
282
@@ -378,13 +378,73 @@ impl Command {
378
378
callback ( ) ?;
379
379
}
380
380
381
- // Although we're performing an exec here we may also return with an
382
- // error from this function (without actually exec'ing) in which case we
383
- // want to be sure to restore the global environment back to what it
384
- // once was, ensuring that our temporary override, when free'd, doesn't
385
- // corrupt our process's environment.
386
- let mut _reset = None ;
387
- if let Some ( envp) = maybe_envp {
381
+ if let Some ( envp) = maybe_envp
382
+ && self . get_resolve_in_parent_path ( )
383
+ && self . env_saw_path ( )
384
+ && self . get_program_kind ( ) == ProgramKind :: PathLookup
385
+ {
386
+ use crate :: ffi:: CStr ;
387
+ // execvpe is a gnu extension...
388
+ #[ cfg( all( target_os = "linux" , target_env = "gnu" ) ) ]
389
+ unsafe fn exec_with_env (
390
+ program : & CStr ,
391
+ args : & CStringArray ,
392
+ envp : & CStringArray ,
393
+ ) -> libc:: c_int {
394
+ unsafe { libc:: execvpe ( program. as_ptr ( ) , args. as_ptr ( ) , envp. as_ptr ( ) ) }
395
+ }
396
+
397
+ // ...so if we're not gnu then use our own implementation.
398
+ #[ cfg( not( all( target_os = "linux" , target_env = "gnu" ) ) ) ]
399
+ unsafe fn exec_with_env (
400
+ program : & CStr ,
401
+ args : & CStringArray ,
402
+ envp : & CStringArray ,
403
+ ) -> libc:: c_int {
404
+ unsafe {
405
+ let name = program. to_bytes ( ) ;
406
+ let mut buffer =
407
+ [ const { mem:: MaybeUninit :: < u8 > :: uninit ( ) } ; libc:: PATH_MAX as usize ] ;
408
+ let mut environ = * sys:: env:: environ ( ) ;
409
+ // Search the environment for PATH and, if found,
410
+ // search the paths for the executable by trying to execve each candidate.
411
+ while !( * environ) . is_null ( ) {
412
+ let kv = CStr :: from_ptr ( * environ) ;
413
+ if let Some ( value) = kv. to_bytes ( ) . strip_prefix ( b"PATH=" ) {
414
+ for path in value. split ( |& b| b == b':' ) {
415
+ if buffer. len ( ) - 2 >= path. len ( ) . saturating_add ( name. len ( ) ) {
416
+ let buf_ptr = buffer. as_mut_ptr ( ) . cast :: < u8 > ( ) ;
417
+ let mut offset = 0 ;
418
+ if !path. is_empty ( ) {
419
+ buf_ptr. copy_from ( path. as_ptr ( ) , path. len ( ) ) ;
420
+ offset += path. len ( ) ;
421
+ if path. last ( ) != Some ( & b'/' ) {
422
+ * buf_ptr. add ( path. len ( ) ) = b'/' ;
423
+ offset += 1 ;
424
+ }
425
+ }
426
+ buf_ptr. add ( offset) . copy_from ( name. as_ptr ( ) , name. len ( ) ) ;
427
+ offset += name. len ( ) ;
428
+ * buf_ptr. add ( offset) = 0 ;
429
+ libc:: execve ( buf_ptr. cast ( ) , args. as_ptr ( ) , envp. as_ptr ( ) ) ;
430
+ }
431
+ }
432
+ break ;
433
+ }
434
+ environ = environ. add ( 1 ) ;
435
+ }
436
+ // If execve is successful then it'll never return, thus we'll never reach this point.
437
+ -1
438
+ }
439
+ }
440
+ exec_with_env ( self . get_program_cstr ( ) , self . get_argv ( ) , envp) ;
441
+ } else if let Some ( envp) = maybe_envp {
442
+ // Although we're performing an exec here we may also return with an
443
+ // error from this function (without actually exec'ing) in which case we
444
+ // want to be sure to restore the global environment back to what it
445
+ // once was, ensuring that our temporary override, when free'd, doesn't
446
+ // corrupt our process's environment.
447
+ let mut _reset = None ;
388
448
struct Reset ( * const * const libc:: c_char ) ;
389
449
390
450
impl Drop for Reset {
@@ -397,9 +457,8 @@ impl Command {
397
457
398
458
_reset = Some ( Reset ( * sys:: env:: environ ( ) ) ) ;
399
459
* sys:: env:: environ ( ) = envp. as_ptr ( ) ;
460
+ libc:: execvp ( self . get_program_cstr ( ) . as_ptr ( ) , self . get_argv ( ) . as_ptr ( ) ) ;
400
461
}
401
-
402
- libc:: execvp ( self . get_program_cstr ( ) . as_ptr ( ) , self . get_argv ( ) . as_ptr ( ) ) ;
403
462
Err ( io:: Error :: last_os_error ( ) )
404
463
}
405
464
@@ -453,7 +512,9 @@ impl Command {
453
512
454
513
if self . get_gid ( ) . is_some ( )
455
514
|| self . get_uid ( ) . is_some ( )
456
- || ( self . env_saw_path ( ) && !self . program_is_path ( ) )
515
+ || ( !self . get_resolve_in_parent_path ( )
516
+ && self . env_saw_path ( )
517
+ && !self . program_is_path ( ) )
457
518
|| !self . get_closures ( ) . is_empty ( )
458
519
|| self . get_groups ( ) . is_some ( )
459
520
|| self . get_chroot ( ) . is_some ( )
0 commit comments