Skip to content

Commit 2f2ff2d

Browse files
committed
Add process_vm_readv and process_vm_writev
1 parent 635c871 commit 2f2ff2d

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
88
### Added
99
- Added `nix::unistd::{openat, fstatat, readlink, readlinkat}`
1010
([#551](https://github.com/nix-rust/nix/pull/551))
11+
- Added `nix::sys::uio::{process_vm_readv, process_vm_writev}`
12+
([#568](https://github.com/nix-rust/nix/pull/568))
1113

1214
### Changed
1315
- Marked `sys::mman::{ mmap, munmap, madvise, munlock, msync }` as unsafe.

src/sys/uio.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
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};
57
use libc::{self, c_int, c_void, size_t, off_t};
@@ -56,6 +58,39 @@ pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{
5658
Errno::result(res).map(|r| r as usize)
5759
}
5860

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

test/sys/test_uio.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,49 @@ 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+
fn test_process_vm_readv() {
197+
use nix::unistd::ForkResult::*;
198+
use nix::sys::signal::*;
199+
use nix::sys::wait::*;
200+
use std::{str, slice};
201+
202+
let (r, w) = pipe().unwrap();
203+
match fork() {
204+
Ok(Parent { child }) => {
205+
close(w).unwrap();
206+
let mut msg = vec![0u8; 32];
207+
let bytes_read = read(r, &mut msg).unwrap();
208+
msg.truncate(bytes_read);
209+
close(r).unwrap();
210+
211+
let ptr: usize = str::from_utf8(&msg).unwrap().parse().unwrap();
212+
let remote_iov = IoVec::from_slice(unsafe {
213+
slice::from_raw_parts(ptr as *const _, 4)
214+
});
215+
let mut buf = vec![0u8; 4];
216+
217+
let ret = process_vm_readv(child,
218+
&mut [IoVec::from_mut_slice(&mut buf)],
219+
&[remote_iov],
220+
CmaFlags::empty());
221+
222+
kill(child, SIGTERM).unwrap();
223+
waitpid(child, None).unwrap();
224+
225+
assert_eq!(Ok(4), ret);
226+
assert_eq!(&buf, b"test");
227+
},
228+
Ok(Child) => {
229+
close(r).unwrap();
230+
let s = String::from("test");
231+
let msg = format!("{}", s.as_bytes().as_ptr() as usize);
232+
write(w, msg.as_bytes()).unwrap();
233+
close(w).unwrap();
234+
pause().unwrap();
235+
},
236+
Err(_) => panic!("fork failed")
237+
}
238+
}

0 commit comments

Comments
 (0)