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 Jul 18, 2017
1 parent 5d29650 commit dcccf7b
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
and nix::Error::UnsupportedOperation}`
([#614](https://github.com/nix-rust/nix/pull/614))
- Added `cfmakeraw`, `cfsetspeed`, and `tcgetsid`. ([#527](https://github.com/nix-rust/nix/pull/527))
- Added `nix::sys::uio::{process_vm_readv, process_vm_writev}`
([#568](https://github.com/nix-rust/nix/pull/568))

### Changed
- Changed `ioctl!(write ...)` to take argument by value instead as pointer.
Expand Down
36 changes: 36 additions & 0 deletions src/sys/uio.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Silence invalid warnings due to rust-lang/rust#16719
#![allow(improper_ctypes)]
// Silence warning from empty bitflags
#![allow(unused_imports)]

use {Errno, Result};
use unistd::Pid;
use libc::{self, c_int, c_void, size_t, off_t};
use std::marker::PhantomData;
use std::os::unix::io::RawFd;
Expand Down Expand Up @@ -56,6 +59,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 struct 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: Pid, local_iov: &[IoVec<&[u8]>], remote_iov: &mut [IoVec<&mut [u8]>], flags: CmaFlags) -> Result<usize> {
let res = unsafe {
libc::process_vm_writev(pid.into(), 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: Pid, local_iov: &mut [IoVec<&mut [u8]>], remote_iov: &[IoVec<&[u8]>], flags: CmaFlags) -> Result<usize> {
let res = unsafe {
libc::process_vm_readv(pid.into(), 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
48 changes: 48 additions & 0 deletions test/sys/test_uio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,51 @@ fn test_preadv() {
let all = buffers.concat();
assert_eq!(all, expected);
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
// FIXME: qemu-user doesn't implement process_vm_readv/writev on most arches
#[cfg_attr(not(any(target_arch = "x86", target_arch = "x86_64")), ignore)]
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 dcccf7b

Please sign in to comment.