Add Command::resolve_in_parent_path by ChrisDenton · Pull Request #142035 · rust-lang/rust (original) (raw)

if let Some(envp) = maybe_envp
&& self.get_resolve_in_parent_path()
&& self.env_saw_path()
&& self.get_program_kind() == ProgramKind::PathLookup
{
use crate::ffi::CStr;
// execvpe is a gnu extension...
#[cfg(all(target_os = "linux", target_env = "gnu"))]
unsafe fn exec_with_env(
program: &CStr,
args: &CStringArray,
envp: &CStringArray,
) -> io::Error {
unsafe { libc::execvpe(program.as_ptr(), args.as_ptr(), envp.as_ptr()) };
io::Error::last_os_error()
}
// ...so if we're not gnu then use our own implementation.
#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
unsafe fn exec_with_env(
program: &CStr,
args: &CStringArray,
envp: &CStringArray,
) -> io::Error {
unsafe {
let name = program.to_bytes();
let mut buffer =
[const { mem::MaybeUninit::<u8>::uninit() }; libc::PATH_MAX as usize];
let mut environ = *sys::env::environ();
// Search the environment for PATH and, if found,
// search the paths for the executable by trying to execve each candidate.
while !(*environ).is_null() {
let kv = CStr::from_ptr(*environ);
if let Some(value) = kv.to_bytes().strip_prefix(b"PATH=") {
for path in value.split(|&b
if buffer.len() - 2 >= path.len().saturating_add(name.len()) {
let buf_ptr = buffer.as_mut_ptr().cast::<u8>();
let mut offset = 0;
if !path.is_empty() {
buf_ptr.copy_from(path.as_ptr(), path.len());
offset += path.len();
if path.last() != Some(&b'/') {
*buf_ptr.add(path.len()) = b'/';
offset += 1;
}
}
buf_ptr.add(offset).copy_from(name.as_ptr(), name.len());
offset += name.len();
*buf_ptr.add(offset) = 0;
libc::execve(buf_ptr.cast(), args.as_ptr(), envp.as_ptr());
}
}
break;
}
environ = environ.add(1);
}
// If execve is successful then it'll never return,
// thus we only reach this point on failure..
io::Error::from_raw_os_error(libc::ENOENT)
}
}
_reset = Some(Reset(*sys::env::environ()));
return Err(exec_with_env(self.get_program_cstr(), self.get_argv(), envp));
} else if let Some(envp) = maybe_envp {