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