Skip to content

Commit 97caa0c

Browse files
committed
Merge #727
727: unistd: add fexecve() r=Susurrus This adds fexecve(). It is available in libc since 0.2.29. Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html
2 parents e2f9531 + d9f1b3d commit 97caa0c

File tree

4 files changed

+54
-10
lines changed

4 files changed

+54
-10
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1616
([#647](https://github.com/nix-rust/nix/pull/647))
1717
- Added the `pid()` method to `WaitStatus` for extracting the PID.
1818
([#722](https://github.com/nix-rust/nix/pull/722))
19+
- Added `nix::unistd:fexecve`.
20+
([#727](https://github.com/nix-rust/nix/pull/727))
1921

2022
### Changed
2123
- Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692))

src/unistd.rs

+31
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,37 @@ pub fn execvp(filename: &CString, args: &[CString]) -> Result<Void> {
593593
Err(Error::Sys(Errno::last()))
594594
}
595595

596+
/// Replace the current process image with a new one (see
597+
/// [fexecve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)).
598+
///
599+
/// The `fexecve` function allows for another process to be "called" which will
600+
/// replace the current process image. That is, this process becomes the new
601+
/// command that is run. On success, this function will not return. Instead,
602+
/// the new program will run until it exits.
603+
///
604+
/// This function is similar to `execve`, except that the program to be executed
605+
/// is referenced as a file descriptor instead of a path.
606+
///
607+
/// # Errors
608+
///
609+
/// If an error occurs, this function will return with an indication of the
610+
/// cause of failure. See
611+
/// [fexecve(2)#errors](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html#tag_16_111_05)
612+
/// for a list of error conditions.
613+
#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
614+
target_os = "netbsd", target_os = "openbsd", target_os = "linux"))]
615+
#[inline]
616+
pub fn fexecve(fd: RawFd, args: &[CString], env: &[CString]) -> Result<Void> {
617+
let args_p = to_exec_array(args);
618+
let env_p = to_exec_array(env);
619+
620+
unsafe {
621+
libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr())
622+
};
623+
624+
Err(Error::Sys(Errno::last()))
625+
}
626+
596627
/// Daemonize this process by detaching from the controlling terminal (see
597628
/// [daemon(3)](http://man7.org/linux/man-pages/man3/daemon.3.html)).
598629
///

test/test.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#[macro_use]
2+
extern crate cfg_if;
3+
#[macro_use]
24
extern crate nix;
35
#[macro_use]
46
extern crate lazy_static;

test/test_unistd.rs

+19-10
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ mod linux_android {
105105
}
106106

107107
macro_rules! execve_test_factory(
108-
($test_name:ident, $syscall:ident, $unix_sh:expr, $android_sh:expr) => (
108+
($test_name:ident, $syscall:ident, $exe: expr) => (
109109
#[test]
110110
fn $test_name() {
111111
#[allow(unused_variables)]
@@ -119,19 +119,13 @@ macro_rules! execve_test_factory(
119119
// The tests make sure not to do that, though.
120120
match fork().unwrap() {
121121
Child => {
122-
#[cfg(not(target_os = "android"))]
123-
const SH_PATH: &'static [u8] = $unix_sh;
124-
125-
#[cfg(target_os = "android")]
126-
const SH_PATH: &'static [u8] = $android_sh;
127-
128122
// Close stdout.
129123
close(1).unwrap();
130124
// Make `writer` be the stdout of the new process.
131125
dup(writer).unwrap();
132126
// exec!
133127
$syscall(
134-
&CString::new(SH_PATH).unwrap(),
128+
$exe,
135129
&[CString::new(b"".as_ref()).unwrap(),
136130
CString::new(b"-c".as_ref()).unwrap(),
137131
CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz"
@@ -156,6 +150,23 @@ macro_rules! execve_test_factory(
156150
)
157151
);
158152

153+
cfg_if!{
154+
if #[cfg(target_os = "android")] {
155+
execve_test_factory!(test_execve, execve, &CString::new("/system/bin/sh").unwrap());
156+
execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd());
157+
} else if #[cfg(any(target_os = "dragonfly",
158+
target_os = "freebsd",
159+
target_os = "netbsd",
160+
target_os = "openbsd",
161+
target_os = "linux", ))] {
162+
execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap());
163+
execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd());
164+
} else if #[cfg(any(target_os = "ios", target_os = "macos", ))] {
165+
execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap());
166+
// No fexecve() on macos/ios.
167+
}
168+
}
169+
159170
#[test]
160171
fn test_fchdir() {
161172
// fchdir changes the process's cwd
@@ -231,8 +242,6 @@ fn test_lseek64() {
231242
close(tmpfd).unwrap();
232243
}
233244

234-
execve_test_factory!(test_execve, execve, b"/bin/sh", b"/system/bin/sh");
235-
236245
#[test]
237246
fn test_fpathconf_limited() {
238247
let f = tempfile().unwrap();

0 commit comments

Comments
 (0)