Skip to content

Commit

Permalink
Add process_vm_readv and process_vm_writev
Browse files Browse the repository at this point in the history
  • Loading branch information
geofft committed Apr 5, 2017
1 parent c086d23 commit 030b770
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
<!--### Added-->
- Added `nix::unistd::{openat, fstatat, readlink, readlinkat}`
([#497](https://github.com/nix-rust/nix/pull/551))
- Added `nix::sys::uio::{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.
Expand Down
35 changes: 35 additions & 0 deletions src/sys/uio.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Silence invalid warnings due to rust-lang/rust#16719
#![allow(improper_ctypes)]
// Silence warning from empty bitflags
#![allow(unused_imports)]

use {Errno, Result};
use libc::{self, c_int, c_void, size_t, off_t};
Expand Down Expand Up @@ -56,6 +58,39 @@ pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{
Errno::result(res).map(|r| r as usize)
}

// process_vm_{read,write}v currently doesn't use flags, but we define this
// type for forwards-compatibility.
#[cfg(any(target_os = "linux",
target_os = "android"))]
bitflags!(
pub flags CmaFlags: libc::c_ulong {
// The bitflags! macro requires at least one variant. any() evaluates
// to false, so this symbol never actually exists.
#[cfg(any())]
const CMA_DUMMY = 0,
}
);

#[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]>], flags: CmaFlags) -> Result<usize> {
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, flags.bits())
};

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]>], flags: CmaFlags) -> Result<usize> {
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, flags.bits())
};

Errno::result(res).map(|r| r as usize)
}

#[repr(C)]
pub struct IoVec<T>(libc::iovec, PhantomData<T>);

Expand Down
46 changes: 46 additions & 0 deletions test/sys/test_uio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,49 @@ 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],
CmaFlags::empty());

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")
}
}

0 comments on commit 030b770

Please sign in to comment.