diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs index ab0373722e..92223ba98a 100644 --- a/src/header/unistd/mod.rs +++ b/src/header/unistd/mod.rs @@ -3,7 +3,9 @@ use core::{ptr, slice}; use c_str::CStr; +use header::errno; use header::limits; +use header::stdlib::getenv; use header::time::timespec; use platform; use platform::types::*; @@ -150,9 +152,42 @@ pub unsafe extern "C" fn execve( Sys::execve(path, argv, envp) } -// #[no_mangle] -pub extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -> c_int { - unimplemented!(); +#[cfg(target_os = "linux")] +const PATH_SEPARATOR: u8 = b':'; + +#[cfg(target_os = "redox")] +const PATH_SEPARATOR: u8 = b';'; + +#[no_mangle] +pub unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -> c_int { + let file = CStr::from_ptr(file); + + if file.to_bytes().contains(&b'/') || (cfg!(target_os = "redox") && file.to_bytes().contains(&b':')) { + execv(file.as_ptr(), argv) + } else { + let mut error = errno::ENOENT; + + let path_env = getenv(c_str!("PATH\0").as_ptr()); + if ! path_env.is_null() { + let path_env = CStr::from_ptr(path_env); + for mut path in path_env.to_bytes().split(|&b| b == PATH_SEPARATOR) { + let mut program = path.to_vec(); + program.extend_from_slice(file.to_bytes()); + program.push(b'0'); + + let program_c = CStr::from_bytes_with_nul(&program).unwrap(); + execv(program_c.as_ptr(), argv); + + match platform::errno { + errno::ENOENT => (), + other => error = other, + } + } + } + + platform::errno = error; + -1 + } } #[no_mangle] diff --git a/src/macros.rs b/src/macros.rs index 31e415c3c3..b1c42de6db 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,3 +1,13 @@ +#[macro_export] +macro_rules! c_str { + ($lit:expr) => { + unsafe { + $crate::c_str::CStr::from_ptr(concat!($lit, "\0").as_ptr() + as *const $crate::platform::types::c_char) + } + } +} + /// Print to stdout #[macro_export] macro_rules! print {