diff options
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/unistd.rs | 22 | ||||
-rw-r--r-- | test/test_unistd.rs | 57 |
3 files changed, 58 insertions, 23 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 28c01a41..cc29e7ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - ReleaseDate ### Added ### Changed +- Changed unistd::{execv,execve,execvp,execvpe,fexecve,execveat} to take both `&[&CStr]` and `&[CString]` as its list argument(s). + (#[1278](https://github.com/nix-rust/nix/pull/1278)) ### Fixed ### Removed diff --git a/src/unistd.rs b/src/unistd.rs index d53b438c..06f997f4 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -12,9 +12,9 @@ use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t, PATH_MAX}; use std::{fmt, mem, ptr}; use std::convert::Infallible; -use std::ffi::{CStr, OsString}; +use std::ffi::{CStr, CString, OsString}; #[cfg(not(target_os = "redox"))] -use std::ffi::{CString, OsStr}; +use std::ffi::{OsStr}; use std::os::unix::ffi::OsStringExt; #[cfg(not(target_os = "redox"))] use std::os::unix::ffi::OsStrExt; @@ -715,9 +715,9 @@ pub fn fchownat<P: ?Sized + NixPath>( Errno::result(res).map(drop) } -fn to_exec_array(args: &[&CStr]) -> Vec<*const c_char> { +fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char> { use std::iter::once; - args.iter().map(|s| s.as_ptr()).chain(once(ptr::null())).collect() + args.iter().map(|s| s.as_ref().as_ptr()).chain(once(ptr::null())).collect() } /// Replace the current process image with a new one (see @@ -727,7 +727,7 @@ fn to_exec_array(args: &[&CStr]) -> Vec<*const c_char> { /// performs the same action but does not allow for customization of the /// environment for the new process. #[inline] -pub fn execv(path: &CStr, argv: &[&CStr]) -> Result<Infallible> { +pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> { let args_p = to_exec_array(argv); unsafe { @@ -751,7 +751,7 @@ pub fn execv(path: &CStr, argv: &[&CStr]) -> Result<Infallible> { /// in the `args` list is an argument to the new process. Each element in the /// `env` list should be a string in the form "key=value". #[inline] -pub fn execve(path: &CStr, args: &[&CStr], env: &[&CStr]) -> Result<Infallible> { +pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> { let args_p = to_exec_array(args); let env_p = to_exec_array(env); @@ -772,7 +772,7 @@ pub fn execve(path: &CStr, args: &[&CStr], env: &[&CStr]) -> Result<Infallible> /// would not work if "bash" was specified for the path argument, but `execvp` /// would assuming that a bash executable was on the system `PATH`. #[inline] -pub fn execvp(filename: &CStr, args: &[&CStr]) -> Result<Infallible> { +pub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible> { let args_p = to_exec_array(args); unsafe { @@ -792,7 +792,7 @@ pub fn execvp(filename: &CStr, args: &[&CStr]) -> Result<Infallible> { #[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))] -pub fn execvpe(filename: &CStr, args: &[&CStr], env: &[&CStr]) -> Result<Infallible> { +pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> { let args_p = to_exec_array(args); let env_p = to_exec_array(env); @@ -820,7 +820,7 @@ pub fn execvpe(filename: &CStr, args: &[&CStr], env: &[&CStr]) -> Result<Infalli target_os = "linux", target_os = "freebsd"))] #[inline] -pub fn fexecve(fd: RawFd, args: &[&CStr], env: &[&CStr]) -> Result<Infallible> { +pub fn fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[SE]) -> Result<Infallible> { let args_p = to_exec_array(args); let env_p = to_exec_array(env); @@ -843,8 +843,8 @@ pub fn fexecve(fd: RawFd, args: &[&CStr], env: &[&CStr]) -> Result<Infallible> { /// is referenced as a file descriptor to the base directory plus a path. #[cfg(any(target_os = "android", target_os = "linux"))] #[inline] -pub fn execveat(dirfd: RawFd, pathname: &CStr, args: &[&CStr], - env: &[&CStr], flags: super::fcntl::AtFlags) -> Result<Infallible> { +pub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, args: &[SA], + env: &[SE], flags: super::fcntl::AtFlags) -> Result<Infallible> { let args_p = to_exec_array(args); let env_p = to_exec_array(env); diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 8fe1d432..0b2a810a 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -256,8 +256,38 @@ fn test_initgroups() { #[cfg(not(target_os = "redox"))] macro_rules! execve_test_factory( ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => ( - #[test] - fn $test_name() { + + #[cfg(test)] + mod $test_name { + use super::*; + + fn syscall_cstr_ref() -> Result<std::convert::Infallible, nix::Error> { + $syscall( + $exe, + $(CString::new($pathname).unwrap().as_c_str(), )* + &[CString::new(b"".as_ref()).unwrap().as_c_str(), + CString::new(b"-c".as_ref()).unwrap().as_c_str(), + CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz" + .as_ref()).unwrap().as_c_str()], + &[CString::new(b"foo=bar".as_ref()).unwrap().as_c_str(), + CString::new(b"baz=quux".as_ref()).unwrap().as_c_str()] + $(, $flags)*) + } + + fn syscall_cstring() -> Result<std::convert::Infallible, nix::Error> { + $syscall( + $exe, + $(CString::new($pathname).unwrap().as_c_str(), )* + &[CString::new(b"".as_ref()).unwrap(), + CString::new(b"-c".as_ref()).unwrap(), + CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz" + .as_ref()).unwrap()], + &[CString::new(b"foo=bar".as_ref()).unwrap(), + CString::new(b"baz=quux".as_ref()).unwrap()] + $(, $flags)*) + } + + fn common_test(syscall: fn() -> Result<std::convert::Infallible, nix::Error>) { if "execveat" == stringify!($syscall) { // Though undocumented, Docker's default seccomp profile seems to // block this syscall. https://github.com/nix-rust/nix/issues/1122 @@ -276,16 +306,7 @@ macro_rules! execve_test_factory( Child => { // Make `writer` be the stdout of the new process. dup2(writer, 1).unwrap(); - let r = $syscall( - $exe, - $(CString::new($pathname).unwrap().as_c_str(), )* - &[CString::new(b"".as_ref()).unwrap().as_c_str(), - CString::new(b"-c".as_ref()).unwrap().as_c_str(), - CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz" - .as_ref()).unwrap().as_c_str()], - &[CString::new(b"foo=bar".as_ref()).unwrap().as_c_str(), - CString::new(b"baz=quux".as_ref()).unwrap().as_c_str()] - $(, $flags)*); + let r = syscall(); let _ = std::io::stderr() .write_all(format!("{:?}", r).as_bytes()); // Should only get here in event of error @@ -307,6 +328,18 @@ macro_rules! execve_test_factory( } } } + + #[test] + fn test_cstr_ref() { + common_test(syscall_cstr_ref); + } + + #[test] + fn test_cstring() { + common_test(syscall_cstring); + } + } + ) ); |