diff options
author | Luca Bruno <lucab@debian.org> | 2017-08-09 20:08:05 +0000 |
---|---|---|
committer | Luca Bruno <lucab@debian.org> | 2017-08-18 08:12:36 +0000 |
commit | d9f1b3df600b9e70c8a64baae9c8e39d2ce733a0 (patch) | |
tree | f97dfdf31f02be3406cd10d492f93d45c6993689 | |
parent | e2f9531aa0ac533bc9328943eb0aac883d10c625 (diff) | |
download | nix-d9f1b3df600b9e70c8a64baae9c8e39d2ce733a0.zip |
unistd: add fexecve()
This adds fexecve() to `nix::unistd`. It is available in libc since 0.2.29.
Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/unistd.rs | 31 | ||||
-rw-r--r-- | test/test.rs | 2 | ||||
-rw-r--r-- | test/test_unistd.rs | 29 |
4 files changed, 54 insertions, 10 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 88c266a5..f9ec8fa1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#647](https://github.com/nix-rust/nix/pull/647)) - Added the `pid()` method to `WaitStatus` for extracting the PID. ([#722](https://github.com/nix-rust/nix/pull/722)) +- Added `nix::unistd:fexecve`. + ([#727](https://github.com/nix-rust/nix/pull/727)) ### Changed - Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692)) diff --git a/src/unistd.rs b/src/unistd.rs index 86cce832..af38cf2d 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -593,6 +593,37 @@ pub fn execvp(filename: &CString, args: &[CString]) -> Result<Void> { Err(Error::Sys(Errno::last())) } +/// Replace the current process image with a new one (see +/// [fexecve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)). +/// +/// The `fexecve` function allows for another process to be "called" which will +/// replace the current process image. That is, this process becomes the new +/// command that is run. On success, this function will not return. Instead, +/// the new program will run until it exits. +/// +/// This function is similar to `execve`, except that the program to be executed +/// is referenced as a file descriptor instead of a path. +/// +/// # Errors +/// +/// If an error occurs, this function will return with an indication of the +/// cause of failure. See +/// [fexecve(2)#errors](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html#tag_16_111_05) +/// for a list of error conditions. +#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "netbsd", target_os = "openbsd", target_os = "linux"))] +#[inline] +pub fn fexecve(fd: RawFd, args: &[CString], env: &[CString]) -> Result<Void> { + let args_p = to_exec_array(args); + let env_p = to_exec_array(env); + + unsafe { + libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr()) + }; + + Err(Error::Sys(Errno::last())) +} + /// Daemonize this process by detaching from the controlling terminal (see /// [daemon(3)](http://man7.org/linux/man-pages/man3/daemon.3.html)). /// diff --git a/test/test.rs b/test/test.rs index 1d22b59a..1b73c4ff 100644 --- a/test/test.rs +++ b/test/test.rs @@ -1,4 +1,6 @@ #[macro_use] +extern crate cfg_if; +#[macro_use] extern crate nix; #[macro_use] extern crate lazy_static; diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 09143c58..adf73579 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -105,7 +105,7 @@ mod linux_android { } macro_rules! execve_test_factory( - ($test_name:ident, $syscall:ident, $unix_sh:expr, $android_sh:expr) => ( + ($test_name:ident, $syscall:ident, $exe: expr) => ( #[test] fn $test_name() { #[allow(unused_variables)] @@ -119,19 +119,13 @@ macro_rules! execve_test_factory( // The tests make sure not to do that, though. match fork().unwrap() { Child => { - #[cfg(not(target_os = "android"))] - const SH_PATH: &'static [u8] = $unix_sh; - - #[cfg(target_os = "android")] - const SH_PATH: &'static [u8] = $android_sh; - // Close stdout. close(1).unwrap(); // Make `writer` be the stdout of the new process. dup(writer).unwrap(); // exec! $syscall( - &CString::new(SH_PATH).unwrap(), + $exe, &[CString::new(b"".as_ref()).unwrap(), CString::new(b"-c".as_ref()).unwrap(), CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz" @@ -156,6 +150,23 @@ macro_rules! execve_test_factory( ) ); +cfg_if!{ + if #[cfg(target_os = "android")] { + execve_test_factory!(test_execve, execve, &CString::new("/system/bin/sh").unwrap()); + execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd()); + } else if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", + target_os = "linux", ))] { + execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap()); + execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd()); + } else if #[cfg(any(target_os = "ios", target_os = "macos", ))] { + execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap()); + // No fexecve() on macos/ios. + } +} + #[test] fn test_fchdir() { // fchdir changes the process's cwd @@ -231,8 +242,6 @@ fn test_lseek64() { close(tmpfd).unwrap(); } -execve_test_factory!(test_execve, execve, b"/bin/sh", b"/system/bin/sh"); - #[test] fn test_fpathconf_limited() { let f = tempfile().unwrap(); |