diff --git a/CHANGELOG.md b/CHANGELOG.md index 045756ddb3..d077aae95d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added `nix::unistd::{openat, fstatat, readlink, readlinkat}` ([#497](https://github.com/nix-rust/nix/pull/551)) +- Added `nix::sys::ui::{process_vm_readv, process_vm_writev}` + ([#568](https://github.com/nix-rust/nix/pull/568)) ### Changed - Marked `sys::mman::{ mmap, munmap, madvise, munlock, msync }` as unsafe. diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 5af1093070..18cf67a4cd 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -56,6 +56,26 @@ pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result{ Errno::result(res).map(|r| r as usize) } +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn process_vm_writev(pid: libc::pid_t, local_iov: &[IoVec<&[u8]>], remote_iov: &mut [IoVec<&mut [u8]>]) -> Result { + let res = unsafe { + libc::process_vm_writev(pid, local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, + remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) + }; + + Errno::result(res).map(|r| r as usize) +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn process_vm_readv(pid: libc::pid_t, local_iov: &mut [IoVec<&mut [u8]>], remote_iov: &[IoVec<&[u8]>]) -> Result { + let res = unsafe { + libc::process_vm_readv(pid, local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, + remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) + }; + + Errno::result(res).map(|r| r as usize) +} + #[repr(C)] pub struct IoVec(libc::iovec, PhantomData); diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index 90cda56f5d..658d96b454 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -190,3 +190,48 @@ fn test_preadv() { let all = buffers.concat(); assert_eq!(all, expected); } + +#[test] +#[cfg(any(target_os = "linux", target_os = "android"))] +fn test_process_vm_readv() { + use nix::unistd::ForkResult::*; + use nix::sys::signal::*; + use nix::sys::wait::*; + use std::{str, slice}; + + let (r, w) = pipe().unwrap(); + match fork() { + Ok(Parent { child }) => { + close(w).unwrap(); + let mut msg = vec![0u8; 32]; + let bytes_read = read(r, &mut msg).unwrap(); + msg.truncate(bytes_read); + close(r).unwrap(); + + let ptr: usize = str::from_utf8(&msg).unwrap().parse().unwrap(); + let remote_iov = IoVec::from_slice(unsafe { + slice::from_raw_parts(ptr as *const _, 4) + }); + let mut buf = vec![0u8; 4]; + + let ret = process_vm_readv(child, + &mut [IoVec::from_mut_slice(&mut buf)], + &[remote_iov]); + + kill(child, SIGTERM).unwrap(); + waitpid(child, None).unwrap(); + + assert_eq!(Ok(4), ret); + assert_eq!(&buf, b"test"); + }, + Ok(Child) => { + close(r).unwrap(); + let s = String::from("test"); + let msg = format!("{}", s.as_bytes().as_ptr() as usize); + write(w, msg.as_bytes()).unwrap(); + close(w).unwrap(); + pause().unwrap(); + }, + Err(_) => panic!("fork failed") + } +}