Skip to content

Commit dcccf7b

Browse files
committed
Add process_vm_readv and process_vm_writev
1 parent 5d29650 commit dcccf7b

File tree

3 files changed

+86
-0
lines changed

3 files changed

+86
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
2424
and nix::Error::UnsupportedOperation}`
2525
([#614](https://github.com/nix-rust/nix/pull/614))
2626
- Added `cfmakeraw`, `cfsetspeed`, and `tcgetsid`. ([#527](https://github.com/nix-rust/nix/pull/527))
27+
- Added `nix::sys::uio::{process_vm_readv, process_vm_writev}`
28+
([#568](https://github.com/nix-rust/nix/pull/568))
2729

2830
### Changed
2931
- Changed `ioctl!(write ...)` to take argument by value instead as pointer.

src/sys/uio.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
// Silence invalid warnings due to rust-lang/rust#16719
22
#![allow(improper_ctypes)]
3+
// Silence warning from empty bitflags
4+
#![allow(unused_imports)]
35

46
use {Errno, Result};
7+
use unistd::Pid;
58
use libc::{self, c_int, c_void, size_t, off_t};
69
use std::marker::PhantomData;
710
use std::os::unix::io::RawFd;
@@ -56,6 +59,39 @@ pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{
5659
Errno::result(res).map(|r| r as usize)
5760
}
5861

62+
// process_vm_{read,write}v currently doesn't use flags, but we define this
63+
// type for forwards-compatibility.
64+
#[cfg(any(target_os = "linux",
65+
target_os = "android"))]
66+
bitflags!(
67+
pub struct CmaFlags: libc::c_ulong {
68+
// The bitflags! macro requires at least one variant. any() evaluates
69+
// to false, so this symbol never actually exists.
70+
#[cfg(any())]
71+
const CMA_DUMMY = 0;
72+
}
73+
);
74+
75+
#[cfg(any(target_os = "linux", target_os = "android"))]
76+
pub fn process_vm_writev(pid: Pid, local_iov: &[IoVec<&[u8]>], remote_iov: &mut [IoVec<&mut [u8]>], flags: CmaFlags) -> Result<usize> {
77+
let res = unsafe {
78+
libc::process_vm_writev(pid.into(), local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
79+
remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, flags.bits())
80+
};
81+
82+
Errno::result(res).map(|r| r as usize)
83+
}
84+
85+
#[cfg(any(target_os = "linux", target_os = "android"))]
86+
pub fn process_vm_readv(pid: Pid, local_iov: &mut [IoVec<&mut [u8]>], remote_iov: &[IoVec<&[u8]>], flags: CmaFlags) -> Result<usize> {
87+
let res = unsafe {
88+
libc::process_vm_readv(pid.into(), local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
89+
remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, flags.bits())
90+
};
91+
92+
Errno::result(res).map(|r| r as usize)
93+
}
94+
5995
#[repr(C)]
6096
pub struct IoVec<T>(libc::iovec, PhantomData<T>);
6197

test/sys/test_uio.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,51 @@ fn test_preadv() {
190190
let all = buffers.concat();
191191
assert_eq!(all, expected);
192192
}
193+
194+
#[test]
195+
#[cfg(any(target_os = "linux", target_os = "android"))]
196+
// FIXME: qemu-user doesn't implement process_vm_readv/writev on most arches
197+
#[cfg_attr(not(any(target_arch = "x86", target_arch = "x86_64")), ignore)]
198+
fn test_process_vm_readv() {
199+
use nix::unistd::ForkResult::*;
200+
use nix::sys::signal::*;
201+
use nix::sys::wait::*;
202+
use std::{str, slice};
203+
204+
let (r, w) = pipe().unwrap();
205+
match fork() {
206+
Ok(Parent { child }) => {
207+
close(w).unwrap();
208+
let mut msg = vec![0u8; 32];
209+
let bytes_read = read(r, &mut msg).unwrap();
210+
msg.truncate(bytes_read);
211+
close(r).unwrap();
212+
213+
let ptr: usize = str::from_utf8(&msg).unwrap().parse().unwrap();
214+
let remote_iov = IoVec::from_slice(unsafe {
215+
slice::from_raw_parts(ptr as *const _, 4)
216+
});
217+
let mut buf = vec![0u8; 4];
218+
219+
let ret = process_vm_readv(child,
220+
&mut [IoVec::from_mut_slice(&mut buf)],
221+
&[remote_iov],
222+
CmaFlags::empty());
223+
224+
kill(child, SIGTERM).unwrap();
225+
waitpid(child, None).unwrap();
226+
227+
assert_eq!(Ok(4), ret);
228+
assert_eq!(&buf, b"test");
229+
},
230+
Ok(Child) => {
231+
close(r).unwrap();
232+
let s = String::from("test");
233+
let msg = format!("{}", s.as_bytes().as_ptr() as usize);
234+
write(w, msg.as_bytes()).unwrap();
235+
close(w).unwrap();
236+
pause().unwrap();
237+
},
238+
Err(_) => panic!("fork failed")
239+
}
240+
}

0 commit comments

Comments
 (0)