From 45a4581876d0a99260fe2616a249ad2c169d11ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= <joerg@higgsboson.tk>
Date: Sun, 10 Apr 2016 21:47:42 +0200
Subject: [PATCH] make execvpe available for all platforms

- execvpe is as GNU extension of libc.
- redone in Rust to make it available on all systems.
- this also makes the feature flag obsolete.
---
 Cargo.toml    |  1 -
 src/unistd.rs | 45 ++++++++++++++++++++++++++-------------------
 2 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 2f2663ada1..f2e213ae03 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,7 +18,6 @@ build = "build.rs"
 
 [features]
 eventfd = []
-execvpe = []
 preadv_pwritev = []
 signalfd = []
 
diff --git a/src/unistd.rs b/src/unistd.rs
index a1200680dd..6c61111417 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -373,13 +373,37 @@ pub fn sleep(seconds: libc::c_uint) -> c_uint {
     unsafe { libc::sleep(seconds) }
 }
 
+pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<()> {
+    use std::env;
+    use std::ffi::OsString;
+    use std::ffi::OsStr;
+    use std::os::unix::ffi::OsStrExt;
+
+    if filename.as_bytes().iter().find(|c| **c == b'/').is_some() {
+        return execve(filename, args, env);
+    }
+
+    let paths = match env::var_os("PATH") {
+        Some(val) => val,
+        None => OsString::from("/usr/local/bin:/bin:/usr/bin"),
+    };
+
+    let name = OsStr::from_bytes(&filename.as_bytes());
+    let mut res = Err(Error::Sys(Errno::ENOENT));
+    for path in env::split_paths(&paths) {
+        let p = path.with_file_name(name);
+        let p2 = &CString::new(p.as_os_str().as_bytes()).unwrap();
+        res = execve(p2, args, env);
+    }
+
+    return res;
+}
+
 #[cfg(any(target_os = "linux", target_os = "android"))]
 mod linux {
     use sys::syscall::{syscall, SYSPIVOTROOT};
     use {Errno, Result, NixPath};
 
-    #[cfg(feature = "execvpe")]
-    use std::ffi::CString;
 
     pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
             new_root: &P1, put_old: &P2) -> Result<()> {
@@ -394,22 +418,5 @@ mod linux {
         Errno::result(res).map(drop)
     }
 
-    #[inline]
-    #[cfg(feature = "execvpe")]
-    pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<()> {
-        use std::ptr;
-        use libc::c_char;
-
-        let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
-        args_p.push(ptr::null());
-
-        let mut env_p: Vec<*const c_char> = env.iter().map(|s| s.as_ptr()).collect();
-        env_p.push(ptr::null());
 
-        unsafe {
-            super::ffi::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
-        };
-
-        Err(Error::Sys(Errno::last()))
-    }
 }