Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
60
third-party/vendor/nix/test/sys/mod.rs
vendored
Normal file
60
third-party/vendor/nix/test/sys/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
mod test_signal;
|
||||
|
||||
// NOTE: DragonFly lacks a kernel-level implementation of Posix AIO as of
|
||||
// this writing. There is an user-level implementation, but whether aio
|
||||
// works or not heavily depends on which pthread implementation is chosen
|
||||
// by the user at link time. For this reason we do not want to run aio test
|
||||
// cases on DragonFly.
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
all(target_os = "linux", not(target_env = "uclibc")),
|
||||
target_os = "macos",
|
||||
target_os = "netbsd"
|
||||
))]
|
||||
mod test_aio;
|
||||
#[cfg(not(any(
|
||||
target_os = "redox",
|
||||
target_os = "fuchsia",
|
||||
target_os = "haiku"
|
||||
)))]
|
||||
mod test_ioctl;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
mod test_mman;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
mod test_select;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod test_signalfd;
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
mod test_socket;
|
||||
#[cfg(not(any(target_os = "redox")))]
|
||||
mod test_sockopt;
|
||||
mod test_stat;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
mod test_sysinfo;
|
||||
#[cfg(not(any(
|
||||
target_os = "redox",
|
||||
target_os = "fuchsia",
|
||||
target_os = "haiku"
|
||||
)))]
|
||||
mod test_termios;
|
||||
mod test_uio;
|
||||
mod test_wait;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
mod test_epoll;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod test_inotify;
|
||||
mod test_pthread;
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
mod test_ptrace;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
mod test_timerfd;
|
||||
626
third-party/vendor/nix/test/sys/test_aio.rs
vendored
Normal file
626
third-party/vendor/nix/test/sys/test_aio.rs
vendored
Normal file
|
|
@ -0,0 +1,626 @@
|
|||
use std::{
|
||||
io::{Read, Seek, SeekFrom, Write},
|
||||
ops::Deref,
|
||||
os::unix::io::AsRawFd,
|
||||
pin::Pin,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
thread, time,
|
||||
};
|
||||
|
||||
use libc::c_int;
|
||||
use nix::{
|
||||
errno::*,
|
||||
sys::{
|
||||
aio::*,
|
||||
signal::{
|
||||
sigaction, SaFlags, SigAction, SigHandler, SigSet, SigevNotify,
|
||||
Signal,
|
||||
},
|
||||
time::{TimeSpec, TimeValLike},
|
||||
},
|
||||
};
|
||||
use tempfile::tempfile;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SIGNALED: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
|
||||
extern "C" fn sigfunc(_: c_int) {
|
||||
SIGNALED.store(true, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
// Helper that polls an AioCb for completion or error
|
||||
macro_rules! poll_aio {
|
||||
($aiocb: expr) => {
|
||||
loop {
|
||||
let err = $aiocb.as_mut().error();
|
||||
if err != Err(Errno::EINPROGRESS) {
|
||||
break err;
|
||||
};
|
||||
thread::sleep(time::Duration::from_millis(10));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod aio_fsync {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_accessors() {
|
||||
let aiocb = AioFsync::new(
|
||||
1001,
|
||||
AioFsyncMode::O_SYNC,
|
||||
42,
|
||||
SigevNotify::SigevSignal {
|
||||
signal: Signal::SIGUSR2,
|
||||
si_value: 99,
|
||||
},
|
||||
);
|
||||
assert_eq!(1001, aiocb.fd());
|
||||
assert_eq!(AioFsyncMode::O_SYNC, aiocb.mode());
|
||||
assert_eq!(42, aiocb.priority());
|
||||
let sev = aiocb.sigevent().sigevent();
|
||||
assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
|
||||
assert_eq!(99, sev.sigev_value.sival_ptr as i64);
|
||||
}
|
||||
|
||||
/// `AioFsync::submit` should not modify the `AioCb` object if
|
||||
/// `libc::aio_fsync` returns an error
|
||||
// Skip on Linux, because Linux's AIO implementation can't detect errors
|
||||
// synchronously
|
||||
#[test]
|
||||
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
|
||||
fn error() {
|
||||
use std::mem;
|
||||
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
// Create an invalid AioFsyncMode
|
||||
let mode = unsafe { mem::transmute(666) };
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiof = Box::pin(AioFsync::new(
|
||||
f.as_raw_fd(),
|
||||
mode,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
let err = aiof.as_mut().submit();
|
||||
err.expect_err("assertion failed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn ok() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let fd = f.as_raw_fd();
|
||||
let mut aiof = Box::pin(AioFsync::new(
|
||||
fd,
|
||||
AioFsyncMode::O_SYNC,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aiof.as_mut().submit().unwrap();
|
||||
poll_aio!(&mut aiof).unwrap();
|
||||
aiof.as_mut().aio_return().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
mod aio_read {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_accessors() {
|
||||
let mut rbuf = vec![0; 4];
|
||||
let aiocb = AioRead::new(
|
||||
1001,
|
||||
2, //offset
|
||||
&mut rbuf,
|
||||
42, //priority
|
||||
SigevNotify::SigevSignal {
|
||||
signal: Signal::SIGUSR2,
|
||||
si_value: 99,
|
||||
},
|
||||
);
|
||||
assert_eq!(1001, aiocb.fd());
|
||||
assert_eq!(4, aiocb.nbytes());
|
||||
assert_eq!(2, aiocb.offset());
|
||||
assert_eq!(42, aiocb.priority());
|
||||
let sev = aiocb.sigevent().sigevent();
|
||||
assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
|
||||
assert_eq!(99, sev.sigev_value.sival_ptr as i64);
|
||||
}
|
||||
|
||||
// Tests AioWrite.cancel. We aren't trying to test the OS's implementation,
|
||||
// only our bindings. So it's sufficient to check that cancel
|
||||
// returned any AioCancelStat value.
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn cancel() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut rbuf = vec![0; 4];
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let fd = f.as_raw_fd();
|
||||
let mut aior =
|
||||
Box::pin(AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone));
|
||||
aior.as_mut().submit().unwrap();
|
||||
|
||||
aior.as_mut().cancel().unwrap();
|
||||
|
||||
// Wait for aiow to complete, but don't care whether it succeeded
|
||||
let _ = poll_aio!(&mut aior);
|
||||
let _ = aior.as_mut().aio_return();
|
||||
}
|
||||
|
||||
/// `AioRead::submit` should not modify the `AioCb` object if
|
||||
/// `libc::aio_read` returns an error
|
||||
// Skip on Linux, because Linux's AIO implementation can't detect errors
|
||||
// synchronously
|
||||
#[test]
|
||||
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
|
||||
fn error() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut rbuf = vec![0; 4];
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aior = Box::pin(AioRead::new(
|
||||
f.as_raw_fd(),
|
||||
-1, //an invalid offset
|
||||
&mut rbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aior.as_mut().submit().expect_err("assertion failed");
|
||||
}
|
||||
|
||||
// Test a simple aio operation with no completion notification. We must
|
||||
// poll for completion
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn ok() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut rbuf = vec![0; 4];
|
||||
const EXPECT: &[u8] = b"cdef";
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
{
|
||||
let fd = f.as_raw_fd();
|
||||
let mut aior = Box::pin(AioRead::new(
|
||||
fd,
|
||||
2,
|
||||
&mut rbuf,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aior.as_mut().submit().unwrap();
|
||||
|
||||
let err = poll_aio!(&mut aior);
|
||||
assert_eq!(err, Ok(()));
|
||||
assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len());
|
||||
}
|
||||
assert_eq!(EXPECT, rbuf.deref().deref());
|
||||
}
|
||||
|
||||
// Like ok, but allocates the structure on the stack.
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn on_stack() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut rbuf = vec![0; 4];
|
||||
const EXPECT: &[u8] = b"cdef";
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
{
|
||||
let fd = f.as_raw_fd();
|
||||
let mut aior =
|
||||
AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone);
|
||||
let mut aior = unsafe { Pin::new_unchecked(&mut aior) };
|
||||
aior.as_mut().submit().unwrap();
|
||||
|
||||
let err = poll_aio!(&mut aior);
|
||||
assert_eq!(err, Ok(()));
|
||||
assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len());
|
||||
}
|
||||
assert_eq!(EXPECT, rbuf.deref().deref());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg(fbsd14)]
|
||||
mod aio_readv {
|
||||
use std::io::IoSliceMut;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_accessors() {
|
||||
let mut rbuf0 = vec![0; 4];
|
||||
let mut rbuf1 = vec![0; 8];
|
||||
let mut rbufs =
|
||||
[IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)];
|
||||
let aiocb = AioReadv::new(
|
||||
1001,
|
||||
2, //offset
|
||||
&mut rbufs,
|
||||
42, //priority
|
||||
SigevNotify::SigevSignal {
|
||||
signal: Signal::SIGUSR2,
|
||||
si_value: 99,
|
||||
},
|
||||
);
|
||||
assert_eq!(1001, aiocb.fd());
|
||||
assert_eq!(2, aiocb.iovlen());
|
||||
assert_eq!(2, aiocb.offset());
|
||||
assert_eq!(42, aiocb.priority());
|
||||
let sev = aiocb.sigevent().sigevent();
|
||||
assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
|
||||
assert_eq!(99, sev.sigev_value.sival_ptr as i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn ok() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let mut rbuf0 = vec![0; 4];
|
||||
let mut rbuf1 = vec![0; 2];
|
||||
let mut rbufs =
|
||||
[IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)];
|
||||
const EXPECT0: &[u8] = b"cdef";
|
||||
const EXPECT1: &[u8] = b"12";
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
{
|
||||
let fd = f.as_raw_fd();
|
||||
let mut aior = Box::pin(AioReadv::new(
|
||||
fd,
|
||||
2,
|
||||
&mut rbufs,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aior.as_mut().submit().unwrap();
|
||||
|
||||
let err = poll_aio!(&mut aior);
|
||||
assert_eq!(err, Ok(()));
|
||||
assert_eq!(
|
||||
aior.as_mut().aio_return().unwrap(),
|
||||
EXPECT0.len() + EXPECT1.len()
|
||||
);
|
||||
}
|
||||
assert_eq!(&EXPECT0, &rbuf0);
|
||||
assert_eq!(&EXPECT1, &rbuf1);
|
||||
}
|
||||
}
|
||||
|
||||
mod aio_write {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_accessors() {
|
||||
let wbuf = vec![0; 4];
|
||||
let aiocb = AioWrite::new(
|
||||
1001,
|
||||
2, //offset
|
||||
&wbuf,
|
||||
42, //priority
|
||||
SigevNotify::SigevSignal {
|
||||
signal: Signal::SIGUSR2,
|
||||
si_value: 99,
|
||||
},
|
||||
);
|
||||
assert_eq!(1001, aiocb.fd());
|
||||
assert_eq!(4, aiocb.nbytes());
|
||||
assert_eq!(2, aiocb.offset());
|
||||
assert_eq!(42, aiocb.priority());
|
||||
let sev = aiocb.sigevent().sigevent();
|
||||
assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
|
||||
assert_eq!(99, sev.sigev_value.sival_ptr as i64);
|
||||
}
|
||||
|
||||
// Tests AioWrite.cancel. We aren't trying to test the OS's implementation,
|
||||
// only our bindings. So it's sufficient to check that cancel
|
||||
// returned any AioCancelStat value.
|
||||
#[test]
|
||||
#[cfg_attr(target_env = "musl", ignore)]
|
||||
fn cancel() {
|
||||
let wbuf: &[u8] = b"CDEF";
|
||||
|
||||
let f = tempfile().unwrap();
|
||||
let mut aiow = Box::pin(AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
0,
|
||||
wbuf,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aiow.as_mut().submit().unwrap();
|
||||
let err = aiow.as_mut().error();
|
||||
assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS));
|
||||
|
||||
aiow.as_mut().cancel().unwrap();
|
||||
|
||||
// Wait for aiow to complete, but don't care whether it succeeded
|
||||
let _ = poll_aio!(&mut aiow);
|
||||
let _ = aiow.as_mut().aio_return();
|
||||
}
|
||||
|
||||
// Test a simple aio operation with no completion notification. We must
|
||||
// poll for completion.
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn ok() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let wbuf = "CDEF".to_string().into_bytes();
|
||||
let mut rbuf = Vec::new();
|
||||
const EXPECT: &[u8] = b"abCDEF123456";
|
||||
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiow = Box::pin(AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
2,
|
||||
&wbuf,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aiow.as_mut().submit().unwrap();
|
||||
|
||||
let err = poll_aio!(&mut aiow);
|
||||
assert_eq!(err, Ok(()));
|
||||
assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len());
|
||||
|
||||
f.seek(SeekFrom::Start(0)).unwrap();
|
||||
let len = f.read_to_end(&mut rbuf).unwrap();
|
||||
assert_eq!(len, EXPECT.len());
|
||||
assert_eq!(rbuf, EXPECT);
|
||||
}
|
||||
|
||||
// Like ok, but allocates the structure on the stack.
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn on_stack() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let wbuf = "CDEF".to_string().into_bytes();
|
||||
let mut rbuf = Vec::new();
|
||||
const EXPECT: &[u8] = b"abCDEF123456";
|
||||
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiow = AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
2, //offset
|
||||
&wbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
);
|
||||
let mut aiow = unsafe { Pin::new_unchecked(&mut aiow) };
|
||||
aiow.as_mut().submit().unwrap();
|
||||
|
||||
let err = poll_aio!(&mut aiow);
|
||||
assert_eq!(err, Ok(()));
|
||||
assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len());
|
||||
|
||||
f.seek(SeekFrom::Start(0)).unwrap();
|
||||
let len = f.read_to_end(&mut rbuf).unwrap();
|
||||
assert_eq!(len, EXPECT.len());
|
||||
assert_eq!(rbuf, EXPECT);
|
||||
}
|
||||
|
||||
/// `AioWrite::write` should not modify the `AioCb` object if
|
||||
/// `libc::aio_write` returns an error.
|
||||
// Skip on Linux, because Linux's AIO implementation can't detect errors
|
||||
// synchronously
|
||||
#[test]
|
||||
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
|
||||
fn error() {
|
||||
let wbuf = "CDEF".to_string().into_bytes();
|
||||
let mut aiow = Box::pin(AioWrite::new(
|
||||
666, // An invalid file descriptor
|
||||
0, //offset
|
||||
&wbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aiow.as_mut().submit().expect_err("assertion failed");
|
||||
// Dropping the AioWrite at this point should not panic
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg(fbsd14)]
|
||||
mod aio_writev {
|
||||
use std::io::IoSlice;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_accessors() {
|
||||
let wbuf0 = vec![0; 4];
|
||||
let wbuf1 = vec![0; 8];
|
||||
let wbufs = [IoSlice::new(&wbuf0), IoSlice::new(&wbuf1)];
|
||||
let aiocb = AioWritev::new(
|
||||
1001,
|
||||
2, //offset
|
||||
&wbufs,
|
||||
42, //priority
|
||||
SigevNotify::SigevSignal {
|
||||
signal: Signal::SIGUSR2,
|
||||
si_value: 99,
|
||||
},
|
||||
);
|
||||
assert_eq!(1001, aiocb.fd());
|
||||
assert_eq!(2, aiocb.iovlen());
|
||||
assert_eq!(2, aiocb.offset());
|
||||
assert_eq!(42, aiocb.priority());
|
||||
let sev = aiocb.sigevent().sigevent();
|
||||
assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
|
||||
assert_eq!(99, sev.sigev_value.sival_ptr as i64);
|
||||
}
|
||||
|
||||
// Test a simple aio operation with no completion notification. We must
|
||||
// poll for completion.
|
||||
#[test]
|
||||
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
|
||||
fn ok() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
let wbuf0 = b"BC";
|
||||
let wbuf1 = b"DEF";
|
||||
let wbufs = [IoSlice::new(wbuf0), IoSlice::new(wbuf1)];
|
||||
let wlen = wbuf0.len() + wbuf1.len();
|
||||
let mut rbuf = Vec::new();
|
||||
const EXPECT: &[u8] = b"aBCDEF123456";
|
||||
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiow = Box::pin(AioWritev::new(
|
||||
f.as_raw_fd(),
|
||||
1,
|
||||
&wbufs,
|
||||
0,
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aiow.as_mut().submit().unwrap();
|
||||
|
||||
let err = poll_aio!(&mut aiow);
|
||||
assert_eq!(err, Ok(()));
|
||||
assert_eq!(aiow.as_mut().aio_return().unwrap(), wlen);
|
||||
|
||||
f.seek(SeekFrom::Start(0)).unwrap();
|
||||
let len = f.read_to_end(&mut rbuf).unwrap();
|
||||
assert_eq!(len, EXPECT.len());
|
||||
assert_eq!(rbuf, EXPECT);
|
||||
}
|
||||
}
|
||||
|
||||
// Test an aio operation with completion delivered by a signal
|
||||
#[test]
|
||||
#[cfg_attr(
|
||||
any(
|
||||
all(target_env = "musl", target_arch = "x86_64"),
|
||||
target_arch = "mips",
|
||||
target_arch = "mips64"
|
||||
),
|
||||
ignore
|
||||
)]
|
||||
fn sigev_signal() {
|
||||
let _m = crate::SIGNAL_MTX.lock();
|
||||
let sa = SigAction::new(
|
||||
SigHandler::Handler(sigfunc),
|
||||
SaFlags::SA_RESETHAND,
|
||||
SigSet::empty(),
|
||||
);
|
||||
SIGNALED.store(false, Ordering::Relaxed);
|
||||
unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();
|
||||
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
const WBUF: &[u8] = b"CDEF";
|
||||
let mut rbuf = Vec::new();
|
||||
const EXPECT: &[u8] = b"abCDEF123456";
|
||||
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
let mut aiow = Box::pin(AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
2, //offset
|
||||
WBUF,
|
||||
0, //priority
|
||||
SigevNotify::SigevSignal {
|
||||
signal: Signal::SIGUSR2,
|
||||
si_value: 0, //TODO: validate in sigfunc
|
||||
},
|
||||
));
|
||||
aiow.as_mut().submit().unwrap();
|
||||
while !SIGNALED.load(Ordering::Relaxed) {
|
||||
thread::sleep(time::Duration::from_millis(10));
|
||||
}
|
||||
|
||||
assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len());
|
||||
f.seek(SeekFrom::Start(0)).unwrap();
|
||||
let len = f.read_to_end(&mut rbuf).unwrap();
|
||||
assert_eq!(len, EXPECT.len());
|
||||
assert_eq!(rbuf, EXPECT);
|
||||
}
|
||||
|
||||
// Tests using aio_cancel_all for all outstanding IOs.
|
||||
#[test]
|
||||
#[cfg_attr(target_env = "musl", ignore)]
|
||||
fn test_aio_cancel_all() {
|
||||
let wbuf: &[u8] = b"CDEF";
|
||||
|
||||
let f = tempfile().unwrap();
|
||||
let mut aiocb = Box::pin(AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
0, //offset
|
||||
wbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aiocb.as_mut().submit().unwrap();
|
||||
let err = aiocb.as_mut().error();
|
||||
assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS));
|
||||
|
||||
aio_cancel_all(f.as_raw_fd()).unwrap();
|
||||
|
||||
// Wait for aiocb to complete, but don't care whether it succeeded
|
||||
let _ = poll_aio!(&mut aiocb);
|
||||
let _ = aiocb.as_mut().aio_return();
|
||||
}
|
||||
|
||||
#[test]
|
||||
// On Cirrus on Linux, this test fails due to a glibc bug.
|
||||
// https://github.com/nix-rust/nix/issues/1099
|
||||
#[cfg_attr(target_os = "linux", ignore)]
|
||||
// On Cirrus, aio_suspend is failing with EINVAL
|
||||
// https://github.com/nix-rust/nix/issues/1361
|
||||
#[cfg_attr(target_os = "macos", ignore)]
|
||||
fn test_aio_suspend() {
|
||||
const INITIAL: &[u8] = b"abcdef123456";
|
||||
const WBUF: &[u8] = b"CDEFG";
|
||||
let timeout = TimeSpec::seconds(10);
|
||||
let mut rbuf = vec![0; 4];
|
||||
let rlen = rbuf.len();
|
||||
let mut f = tempfile().unwrap();
|
||||
f.write_all(INITIAL).unwrap();
|
||||
|
||||
let mut wcb = Box::pin(AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
2, //offset
|
||||
WBUF,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
|
||||
let mut rcb = Box::pin(AioRead::new(
|
||||
f.as_raw_fd(),
|
||||
8, //offset
|
||||
&mut rbuf,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
wcb.as_mut().submit().unwrap();
|
||||
rcb.as_mut().submit().unwrap();
|
||||
loop {
|
||||
{
|
||||
let cbbuf = [
|
||||
&*wcb as &dyn AsRef<libc::aiocb>,
|
||||
&*rcb as &dyn AsRef<libc::aiocb>,
|
||||
];
|
||||
let r = aio_suspend(&cbbuf[..], Some(timeout));
|
||||
match r {
|
||||
Err(Errno::EINTR) => continue,
|
||||
Err(e) => panic!("aio_suspend returned {:?}", e),
|
||||
Ok(_) => (),
|
||||
};
|
||||
}
|
||||
if rcb.as_mut().error() != Err(Errno::EINPROGRESS)
|
||||
&& wcb.as_mut().error() != Err(Errno::EINPROGRESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(wcb.as_mut().aio_return().unwrap(), WBUF.len());
|
||||
assert_eq!(rcb.as_mut().aio_return().unwrap(), rlen);
|
||||
}
|
||||
35
third-party/vendor/nix/test/sys/test_aio_drop.rs
vendored
Normal file
35
third-party/vendor/nix/test/sys/test_aio_drop.rs
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Test dropping an AioCb that hasn't yet finished.
|
||||
// This must happen in its own process, because on OSX this test seems to hose
|
||||
// the AIO subsystem and causes subsequent tests to fail
|
||||
#[test]
|
||||
#[should_panic(expected = "Dropped an in-progress AioCb")]
|
||||
#[cfg(all(
|
||||
not(target_env = "musl"),
|
||||
not(target_env = "uclibc"),
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd"
|
||||
)
|
||||
))]
|
||||
fn test_drop() {
|
||||
use nix::sys::aio::*;
|
||||
use nix::sys::signal::*;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use tempfile::tempfile;
|
||||
|
||||
const WBUF: &[u8] = b"CDEF";
|
||||
|
||||
let f = tempfile().unwrap();
|
||||
f.set_len(6).unwrap();
|
||||
let mut aiocb = Box::pin(AioWrite::new(
|
||||
f.as_raw_fd(),
|
||||
2, //offset
|
||||
WBUF,
|
||||
0, //priority
|
||||
SigevNotify::SigevNone,
|
||||
));
|
||||
aiocb.as_mut().submit().unwrap();
|
||||
}
|
||||
24
third-party/vendor/nix/test/sys/test_epoll.rs
vendored
Normal file
24
third-party/vendor/nix/test/sys/test_epoll.rs
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use nix::errno::Errno;
|
||||
use nix::sys::epoll::{epoll_create1, epoll_ctl};
|
||||
use nix::sys::epoll::{EpollCreateFlags, EpollEvent, EpollFlags, EpollOp};
|
||||
|
||||
#[test]
|
||||
pub fn test_epoll_errno() {
|
||||
let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
|
||||
let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None);
|
||||
result.expect_err("assertion failed");
|
||||
assert_eq!(result.unwrap_err(), Errno::ENOENT);
|
||||
|
||||
let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None);
|
||||
result.expect_err("assertion failed");
|
||||
assert_eq!(result.unwrap_err(), Errno::EINVAL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_epoll_ctl() {
|
||||
let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
|
||||
let mut event =
|
||||
EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1);
|
||||
epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, &mut event).unwrap();
|
||||
epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None).unwrap();
|
||||
}
|
||||
65
third-party/vendor/nix/test/sys/test_inotify.rs
vendored
Normal file
65
third-party/vendor/nix/test/sys/test_inotify.rs
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
use nix::errno::Errno;
|
||||
use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify};
|
||||
use std::ffi::OsString;
|
||||
use std::fs::{rename, File};
|
||||
|
||||
#[test]
|
||||
pub fn test_inotify() {
|
||||
let instance = Inotify::init(InitFlags::IN_NONBLOCK).unwrap();
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
|
||||
instance
|
||||
.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS)
|
||||
.unwrap();
|
||||
|
||||
let events = instance.read_events();
|
||||
assert_eq!(events.unwrap_err(), Errno::EAGAIN);
|
||||
|
||||
File::create(tempdir.path().join("test")).unwrap();
|
||||
|
||||
let events = instance.read_events().unwrap();
|
||||
assert_eq!(events[0].name, Some(OsString::from("test")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_inotify_multi_events() {
|
||||
let instance = Inotify::init(InitFlags::IN_NONBLOCK).unwrap();
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
|
||||
instance
|
||||
.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS)
|
||||
.unwrap();
|
||||
|
||||
let events = instance.read_events();
|
||||
assert_eq!(events.unwrap_err(), Errno::EAGAIN);
|
||||
|
||||
File::create(tempdir.path().join("test")).unwrap();
|
||||
rename(tempdir.path().join("test"), tempdir.path().join("test2")).unwrap();
|
||||
|
||||
// Now there should be 5 events in queue:
|
||||
// - IN_CREATE on test
|
||||
// - IN_OPEN on test
|
||||
// - IN_CLOSE_WRITE on test
|
||||
// - IN_MOVED_FROM on test with a cookie
|
||||
// - IN_MOVED_TO on test2 with the same cookie
|
||||
|
||||
let events = instance.read_events().unwrap();
|
||||
assert_eq!(events.len(), 5);
|
||||
|
||||
assert_eq!(events[0].mask, AddWatchFlags::IN_CREATE);
|
||||
assert_eq!(events[0].name, Some(OsString::from("test")));
|
||||
|
||||
assert_eq!(events[1].mask, AddWatchFlags::IN_OPEN);
|
||||
assert_eq!(events[1].name, Some(OsString::from("test")));
|
||||
|
||||
assert_eq!(events[2].mask, AddWatchFlags::IN_CLOSE_WRITE);
|
||||
assert_eq!(events[2].name, Some(OsString::from("test")));
|
||||
|
||||
assert_eq!(events[3].mask, AddWatchFlags::IN_MOVED_FROM);
|
||||
assert_eq!(events[3].name, Some(OsString::from("test")));
|
||||
|
||||
assert_eq!(events[4].mask, AddWatchFlags::IN_MOVED_TO);
|
||||
assert_eq!(events[4].name, Some(OsString::from("test2")));
|
||||
|
||||
assert_eq!(events[3].cookie, events[4].cookie);
|
||||
}
|
||||
376
third-party/vendor/nix/test/sys/test_ioctl.rs
vendored
Normal file
376
third-party/vendor/nix/test/sys/test_ioctl.rs
vendored
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
// Simple tests to ensure macro generated fns compile
|
||||
ioctl_none_bad!(do_bad, 0x1234);
|
||||
ioctl_read_bad!(do_bad_read, 0x1234, u16);
|
||||
ioctl_write_int_bad!(do_bad_write_int, 0x1234);
|
||||
ioctl_write_ptr_bad!(do_bad_write_ptr, 0x1234, u8);
|
||||
ioctl_readwrite_bad!(do_bad_readwrite, 0x1234, u32);
|
||||
ioctl_none!(do_none, 0, 0);
|
||||
ioctl_read!(read_test, 0, 0, u32);
|
||||
ioctl_write_int!(write_ptr_int, 0, 0);
|
||||
ioctl_write_ptr!(write_ptr_u8, 0, 0, u8);
|
||||
ioctl_write_ptr!(write_ptr_u32, 0, 0, u32);
|
||||
ioctl_write_ptr!(write_ptr_u64, 0, 0, u64);
|
||||
ioctl_readwrite!(readwrite_test, 0, 0, u64);
|
||||
ioctl_read_buf!(readbuf_test, 0, 0, u32);
|
||||
const SPI_IOC_MAGIC: u8 = b'k';
|
||||
const SPI_IOC_MESSAGE: u8 = 0;
|
||||
ioctl_write_buf!(writebuf_test_consts, SPI_IOC_MAGIC, SPI_IOC_MESSAGE, u8);
|
||||
ioctl_write_buf!(writebuf_test_u8, 0, 0, u8);
|
||||
ioctl_write_buf!(writebuf_test_u32, 0, 0, u32);
|
||||
ioctl_write_buf!(writebuf_test_u64, 0, 0, u64);
|
||||
ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32);
|
||||
|
||||
// See C code for source of values for op calculations (does NOT work for mips/powerpc):
|
||||
// https://gist.github.com/posborne/83ea6880770a1aef332e
|
||||
//
|
||||
// TODO: Need a way to compute these constants at test time. Using precomputed
|
||||
// values is fragile and needs to be maintained.
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
mod linux {
|
||||
// The cast is not unnecessary on all platforms.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
#[test]
|
||||
fn test_op_none() {
|
||||
if cfg!(any(
|
||||
target_arch = "mips",
|
||||
target_arch = "mips64",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64"
|
||||
)) {
|
||||
assert_eq!(request_code_none!(b'q', 10) as u32, 0x2000_710A);
|
||||
assert_eq!(request_code_none!(b'a', 255) as u32, 0x2000_61FF);
|
||||
} else {
|
||||
assert_eq!(request_code_none!(b'q', 10) as u32, 0x0000_710A);
|
||||
assert_eq!(request_code_none!(b'a', 255) as u32, 0x0000_61FF);
|
||||
}
|
||||
}
|
||||
|
||||
// The cast is not unnecessary on all platforms.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
#[test]
|
||||
fn test_op_write() {
|
||||
if cfg!(any(
|
||||
target_arch = "mips",
|
||||
target_arch = "mips64",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64"
|
||||
)) {
|
||||
assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x8001_7A0A);
|
||||
assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x8200_7A0A);
|
||||
} else {
|
||||
assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x4001_7A0A);
|
||||
assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x4200_7A0A);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_op_write_64() {
|
||||
if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) {
|
||||
assert_eq!(
|
||||
request_code_write!(b'z', 10, 1u64 << 32) as u32,
|
||||
0x8000_7A0A
|
||||
);
|
||||
} else {
|
||||
assert_eq!(
|
||||
request_code_write!(b'z', 10, 1u64 << 32) as u32,
|
||||
0x4000_7A0A
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// The cast is not unnecessary on all platforms.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
#[test]
|
||||
fn test_op_read() {
|
||||
if cfg!(any(
|
||||
target_arch = "mips",
|
||||
target_arch = "mips64",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64"
|
||||
)) {
|
||||
assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x4001_7A0A);
|
||||
assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x4200_7A0A);
|
||||
} else {
|
||||
assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x8001_7A0A);
|
||||
assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x8200_7A0A);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_op_read_64() {
|
||||
if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) {
|
||||
assert_eq!(
|
||||
request_code_read!(b'z', 10, 1u64 << 32) as u32,
|
||||
0x4000_7A0A
|
||||
);
|
||||
} else {
|
||||
assert_eq!(
|
||||
request_code_read!(b'z', 10, 1u64 << 32) as u32,
|
||||
0x8000_7A0A
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// The cast is not unnecessary on all platforms.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
#[test]
|
||||
fn test_op_read_write() {
|
||||
assert_eq!(request_code_readwrite!(b'z', 10, 1) as u32, 0xC001_7A0A);
|
||||
assert_eq!(request_code_readwrite!(b'z', 10, 512) as u32, 0xC200_7A0A);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_op_read_write_64() {
|
||||
assert_eq!(
|
||||
request_code_readwrite!(b'z', 10, 1u64 << 32) as u32,
|
||||
0xC000_7A0A
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
mod bsd {
|
||||
#[test]
|
||||
fn test_op_none() {
|
||||
assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
|
||||
assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
|
||||
#[test]
|
||||
fn test_op_write_int() {
|
||||
assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604);
|
||||
assert_eq!(request_code_write_int!(b'p', 2), 0x2004_7002);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_op_write() {
|
||||
assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A);
|
||||
assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_op_write_64() {
|
||||
assert_eq!(request_code_write!(b'z', 10, 1u64 << 32), 0x8000_7A0A);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_op_read() {
|
||||
assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A);
|
||||
assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_op_read_64() {
|
||||
assert_eq!(request_code_read!(b'z', 10, 1u64 << 32), 0x4000_7A0A);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_op_read_write() {
|
||||
assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A);
|
||||
assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn test_op_read_write_64() {
|
||||
assert_eq!(request_code_readwrite!(b'z', 10, 1u64 << 32), 0xC000_7A0A);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
mod linux_ioctls {
|
||||
use std::mem;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use libc::{termios, TCGETS, TCSBRK, TCSETS, TIOCNXCL};
|
||||
use tempfile::tempfile;
|
||||
|
||||
use nix::errno::Errno;
|
||||
|
||||
ioctl_none_bad!(tiocnxcl, TIOCNXCL);
|
||||
#[test]
|
||||
fn test_ioctl_none_bad() {
|
||||
let file = tempfile().unwrap();
|
||||
let res = unsafe { tiocnxcl(file.as_raw_fd()) };
|
||||
assert_eq!(res, Err(Errno::ENOTTY));
|
||||
}
|
||||
|
||||
ioctl_read_bad!(tcgets, TCGETS, termios);
|
||||
#[test]
|
||||
fn test_ioctl_read_bad() {
|
||||
let file = tempfile().unwrap();
|
||||
let mut termios = unsafe { mem::zeroed() };
|
||||
let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) };
|
||||
assert_eq!(res, Err(Errno::ENOTTY));
|
||||
}
|
||||
|
||||
ioctl_write_int_bad!(tcsbrk, TCSBRK);
|
||||
#[test]
|
||||
fn test_ioctl_write_int_bad() {
|
||||
let file = tempfile().unwrap();
|
||||
let res = unsafe { tcsbrk(file.as_raw_fd(), 0) };
|
||||
assert_eq!(res, Err(Errno::ENOTTY));
|
||||
}
|
||||
|
||||
ioctl_write_ptr_bad!(tcsets, TCSETS, termios);
|
||||
#[test]
|
||||
fn test_ioctl_write_ptr_bad() {
|
||||
let file = tempfile().unwrap();
|
||||
let termios: termios = unsafe { mem::zeroed() };
|
||||
let res = unsafe { tcsets(file.as_raw_fd(), &termios) };
|
||||
assert_eq!(res, Err(Errno::ENOTTY));
|
||||
}
|
||||
|
||||
// FIXME: Find a suitable example for `ioctl_readwrite_bad`
|
||||
|
||||
// From linux/videodev2.h
|
||||
ioctl_none!(log_status, b'V', 70);
|
||||
#[test]
|
||||
fn test_ioctl_none() {
|
||||
let file = tempfile().unwrap();
|
||||
let res = unsafe { log_status(file.as_raw_fd()) };
|
||||
assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct v4l2_audio {
|
||||
index: u32,
|
||||
name: [u8; 32],
|
||||
capability: u32,
|
||||
mode: u32,
|
||||
reserved: [u32; 2],
|
||||
}
|
||||
|
||||
// From linux/videodev2.h
|
||||
ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
|
||||
#[test]
|
||||
fn test_ioctl_write_ptr() {
|
||||
let file = tempfile().unwrap();
|
||||
let data: v4l2_audio = unsafe { mem::zeroed() };
|
||||
let res = unsafe { s_audio(file.as_raw_fd(), &data) };
|
||||
assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
|
||||
}
|
||||
|
||||
// From linux/net/bluetooth/hci_sock.h
|
||||
const HCI_IOC_MAGIC: u8 = b'H';
|
||||
const HCI_IOC_HCIDEVUP: u8 = 201;
|
||||
ioctl_write_int!(hcidevup, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
|
||||
#[test]
|
||||
fn test_ioctl_write_int() {
|
||||
let file = tempfile().unwrap();
|
||||
let res = unsafe { hcidevup(file.as_raw_fd(), 0) };
|
||||
assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
|
||||
}
|
||||
|
||||
// From linux/videodev2.h
|
||||
ioctl_read!(g_audio, b'V', 33, v4l2_audio);
|
||||
#[test]
|
||||
fn test_ioctl_read() {
|
||||
let file = tempfile().unwrap();
|
||||
let mut data: v4l2_audio = unsafe { mem::zeroed() };
|
||||
let res = unsafe { g_audio(file.as_raw_fd(), &mut data) };
|
||||
assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
|
||||
}
|
||||
|
||||
// From linux/videodev2.h
|
||||
ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio);
|
||||
#[test]
|
||||
fn test_ioctl_readwrite() {
|
||||
let file = tempfile().unwrap();
|
||||
let mut data: v4l2_audio = unsafe { mem::zeroed() };
|
||||
let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) };
|
||||
assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
|
||||
}
|
||||
|
||||
// FIXME: Find a suitable example for `ioctl_read_buf`.
|
||||
|
||||
#[repr(C)]
|
||||
pub struct spi_ioc_transfer {
|
||||
tx_buf: u64,
|
||||
rx_buf: u64,
|
||||
len: u32,
|
||||
speed_hz: u32,
|
||||
delay_usecs: u16,
|
||||
bits_per_word: u8,
|
||||
cs_change: u8,
|
||||
tx_nbits: u8,
|
||||
rx_nbits: u8,
|
||||
pad: u16,
|
||||
}
|
||||
|
||||
// From linux/spi/spidev.h
|
||||
ioctl_write_buf!(
|
||||
spi_ioc_message,
|
||||
super::SPI_IOC_MAGIC,
|
||||
super::SPI_IOC_MESSAGE,
|
||||
spi_ioc_transfer
|
||||
);
|
||||
#[test]
|
||||
fn test_ioctl_write_buf() {
|
||||
let file = tempfile().unwrap();
|
||||
let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() };
|
||||
let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) };
|
||||
assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
|
||||
}
|
||||
|
||||
// FIXME: Find a suitable example for `ioctl_readwrite_buf`.
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
mod freebsd_ioctls {
|
||||
use std::mem;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use libc::termios;
|
||||
use tempfile::tempfile;
|
||||
|
||||
use nix::errno::Errno;
|
||||
|
||||
// From sys/sys/ttycom.h
|
||||
const TTY_IOC_MAGIC: u8 = b't';
|
||||
const TTY_IOC_TYPE_NXCL: u8 = 14;
|
||||
const TTY_IOC_TYPE_GETA: u8 = 19;
|
||||
const TTY_IOC_TYPE_SETA: u8 = 20;
|
||||
|
||||
ioctl_none!(tiocnxcl, TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL);
|
||||
#[test]
|
||||
fn test_ioctl_none() {
|
||||
let file = tempfile().unwrap();
|
||||
let res = unsafe { tiocnxcl(file.as_raw_fd()) };
|
||||
assert_eq!(res, Err(Errno::ENOTTY));
|
||||
}
|
||||
|
||||
ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios);
|
||||
#[test]
|
||||
fn test_ioctl_read() {
|
||||
let file = tempfile().unwrap();
|
||||
let mut termios = unsafe { mem::zeroed() };
|
||||
let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) };
|
||||
assert_eq!(res, Err(Errno::ENOTTY));
|
||||
}
|
||||
|
||||
ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios);
|
||||
#[test]
|
||||
fn test_ioctl_write_ptr() {
|
||||
let file = tempfile().unwrap();
|
||||
let termios: termios = unsafe { mem::zeroed() };
|
||||
let res = unsafe { tiocseta(file.as_raw_fd(), &termios) };
|
||||
assert_eq!(res, Err(Errno::ENOTTY));
|
||||
}
|
||||
}
|
||||
117
third-party/vendor/nix/test/sys/test_mman.rs
vendored
Normal file
117
third-party/vendor/nix/test/sys/test_mman.rs
vendored
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
use nix::sys::mman::{mmap, MapFlags, ProtFlags};
|
||||
|
||||
#[test]
|
||||
fn test_mmap_anonymous() {
|
||||
unsafe {
|
||||
let ptr = mmap(
|
||||
std::ptr::null_mut(),
|
||||
1,
|
||||
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
|
||||
MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
.unwrap() as *mut u8;
|
||||
assert_eq!(*ptr, 0x00u8);
|
||||
*ptr = 0xffu8;
|
||||
assert_eq!(*ptr, 0xffu8);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "linux", target_os = "netbsd"))]
|
||||
fn test_mremap_grow() {
|
||||
use nix::libc::{c_void, size_t};
|
||||
use nix::sys::mman::{mremap, MRemapFlags};
|
||||
|
||||
const ONE_K: size_t = 1024;
|
||||
let slice: &mut [u8] = unsafe {
|
||||
let mem = mmap(
|
||||
std::ptr::null_mut(),
|
||||
ONE_K,
|
||||
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
|
||||
MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
|
||||
};
|
||||
assert_eq!(slice[ONE_K - 1], 0x00);
|
||||
slice[ONE_K - 1] = 0xFF;
|
||||
assert_eq!(slice[ONE_K - 1], 0xFF);
|
||||
|
||||
let slice: &mut [u8] = unsafe {
|
||||
#[cfg(target_os = "linux")]
|
||||
let mem = mremap(
|
||||
slice.as_mut_ptr() as *mut c_void,
|
||||
ONE_K,
|
||||
10 * ONE_K,
|
||||
MRemapFlags::MREMAP_MAYMOVE,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
#[cfg(target_os = "netbsd")]
|
||||
let mem = mremap(
|
||||
slice.as_mut_ptr() as *mut c_void,
|
||||
ONE_K,
|
||||
10 * ONE_K,
|
||||
MRemapFlags::MAP_REMAPDUP,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
std::slice::from_raw_parts_mut(mem as *mut u8, 10 * ONE_K)
|
||||
};
|
||||
|
||||
// The first KB should still have the old data in it.
|
||||
assert_eq!(slice[ONE_K - 1], 0xFF);
|
||||
|
||||
// The additional range should be zero-init'd and accessible.
|
||||
assert_eq!(slice[10 * ONE_K - 1], 0x00);
|
||||
slice[10 * ONE_K - 1] = 0xFF;
|
||||
assert_eq!(slice[10 * ONE_K - 1], 0xFF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "linux", target_os = "netbsd"))]
|
||||
// Segfaults for unknown reasons under QEMU for 32-bit targets
|
||||
#[cfg_attr(all(target_pointer_width = "32", qemu), ignore)]
|
||||
fn test_mremap_shrink() {
|
||||
use nix::libc::{c_void, size_t};
|
||||
use nix::sys::mman::{mremap, MRemapFlags};
|
||||
|
||||
const ONE_K: size_t = 1024;
|
||||
let slice: &mut [u8] = unsafe {
|
||||
let mem = mmap(
|
||||
std::ptr::null_mut(),
|
||||
10 * ONE_K,
|
||||
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
|
||||
MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
|
||||
};
|
||||
assert_eq!(slice[ONE_K - 1], 0x00);
|
||||
slice[ONE_K - 1] = 0xFF;
|
||||
assert_eq!(slice[ONE_K - 1], 0xFF);
|
||||
|
||||
let slice: &mut [u8] = unsafe {
|
||||
let mem = mremap(
|
||||
slice.as_mut_ptr() as *mut c_void,
|
||||
10 * ONE_K,
|
||||
ONE_K,
|
||||
MRemapFlags::empty(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
// Since we didn't supply MREMAP_MAYMOVE, the address should be the
|
||||
// same.
|
||||
assert_eq!(mem, slice.as_mut_ptr() as *mut c_void);
|
||||
std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
|
||||
};
|
||||
|
||||
// The first KB should still be accessible and have the old data in it.
|
||||
assert_eq!(slice[ONE_K - 1], 0xFF);
|
||||
}
|
||||
22
third-party/vendor/nix/test/sys/test_pthread.rs
vendored
Normal file
22
third-party/vendor/nix/test/sys/test_pthread.rs
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
use nix::sys::pthread::*;
|
||||
|
||||
#[cfg(any(target_env = "musl", target_os = "redox"))]
|
||||
#[test]
|
||||
fn test_pthread_self() {
|
||||
let tid = pthread_self();
|
||||
assert!(!tid.is_null());
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_env = "musl", target_os = "redox")))]
|
||||
#[test]
|
||||
fn test_pthread_self() {
|
||||
let tid = pthread_self();
|
||||
assert_ne!(tid, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_pthread_kill_none() {
|
||||
pthread_kill(pthread_self(), None)
|
||||
.expect("Should be able to send signal to my thread.");
|
||||
}
|
||||
275
third-party/vendor/nix/test/sys/test_ptrace.rs
vendored
Normal file
275
third-party/vendor/nix/test/sys/test_ptrace.rs
vendored
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(target_arch = "x86_64", target_arch = "x86"),
|
||||
target_env = "gnu"
|
||||
))]
|
||||
use memoffset::offset_of;
|
||||
use nix::errno::Errno;
|
||||
use nix::sys::ptrace;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
use nix::sys::ptrace::Options;
|
||||
use nix::unistd::getpid;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
use std::mem;
|
||||
|
||||
use crate::*;
|
||||
|
||||
#[test]
|
||||
fn test_ptrace() {
|
||||
// Just make sure ptrace can be called at all, for now.
|
||||
// FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
|
||||
require_capability!("test_ptrace", CAP_SYS_PTRACE);
|
||||
let err = ptrace::attach(getpid()).unwrap_err();
|
||||
assert!(
|
||||
err == Errno::EPERM || err == Errno::EINVAL || err == Errno::ENOSYS
|
||||
);
|
||||
}
|
||||
|
||||
// Just make sure ptrace_setoptions can be called at all, for now.
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn test_ptrace_setoptions() {
|
||||
require_capability!("test_ptrace_setoptions", CAP_SYS_PTRACE);
|
||||
let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD)
|
||||
.unwrap_err();
|
||||
assert_ne!(err, Errno::EOPNOTSUPP);
|
||||
}
|
||||
|
||||
// Just make sure ptrace_getevent can be called at all, for now.
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn test_ptrace_getevent() {
|
||||
require_capability!("test_ptrace_getevent", CAP_SYS_PTRACE);
|
||||
let err = ptrace::getevent(getpid()).unwrap_err();
|
||||
assert_ne!(err, Errno::EOPNOTSUPP);
|
||||
}
|
||||
|
||||
// Just make sure ptrace_getsiginfo can be called at all, for now.
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn test_ptrace_getsiginfo() {
|
||||
require_capability!("test_ptrace_getsiginfo", CAP_SYS_PTRACE);
|
||||
if let Err(Errno::EOPNOTSUPP) = ptrace::getsiginfo(getpid()) {
|
||||
panic!("ptrace_getsiginfo returns Errno::EOPNOTSUPP!");
|
||||
}
|
||||
}
|
||||
|
||||
// Just make sure ptrace_setsiginfo can be called at all, for now.
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn test_ptrace_setsiginfo() {
|
||||
require_capability!("test_ptrace_setsiginfo", CAP_SYS_PTRACE);
|
||||
let siginfo = unsafe { mem::zeroed() };
|
||||
if let Err(Errno::EOPNOTSUPP) = ptrace::setsiginfo(getpid(), &siginfo) {
|
||||
panic!("ptrace_setsiginfo returns Errno::EOPNOTSUPP!");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ptrace_cont() {
|
||||
use nix::sys::ptrace;
|
||||
use nix::sys::signal::{raise, Signal};
|
||||
use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
|
||||
use nix::unistd::fork;
|
||||
use nix::unistd::ForkResult::*;
|
||||
|
||||
require_capability!("test_ptrace_cont", CAP_SYS_PTRACE);
|
||||
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
// FIXME: qemu-user doesn't implement ptrace on all architectures
|
||||
// and returns ENOSYS in this case.
|
||||
// We (ab)use this behavior to detect the affected platforms
|
||||
// and skip the test then.
|
||||
// On valid platforms the ptrace call should return Errno::EPERM, this
|
||||
// is already tested by `test_ptrace`.
|
||||
let err = ptrace::attach(getpid()).unwrap_err();
|
||||
if err == Errno::ENOSYS {
|
||||
return;
|
||||
}
|
||||
|
||||
match unsafe { fork() }.expect("Error: Fork Failed") {
|
||||
Child => {
|
||||
ptrace::traceme().unwrap();
|
||||
// As recommended by ptrace(2), raise SIGTRAP to pause the child
|
||||
// until the parent is ready to continue
|
||||
loop {
|
||||
raise(Signal::SIGTRAP).unwrap();
|
||||
}
|
||||
}
|
||||
Parent { child } => {
|
||||
assert_eq!(
|
||||
waitpid(child, None),
|
||||
Ok(WaitStatus::Stopped(child, Signal::SIGTRAP))
|
||||
);
|
||||
ptrace::cont(child, None).unwrap();
|
||||
assert_eq!(
|
||||
waitpid(child, None),
|
||||
Ok(WaitStatus::Stopped(child, Signal::SIGTRAP))
|
||||
);
|
||||
ptrace::cont(child, Some(Signal::SIGKILL)).unwrap();
|
||||
match waitpid(child, None) {
|
||||
Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _))
|
||||
if pid == child =>
|
||||
{
|
||||
// FIXME It's been observed on some systems (apple) the
|
||||
// tracee may not be killed but remain as a zombie process
|
||||
// affecting other wait based tests. Add an extra kill just
|
||||
// to make sure there are no zombies.
|
||||
let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
|
||||
while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() {
|
||||
let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
|
||||
}
|
||||
}
|
||||
_ => panic!("The process should have been killed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn test_ptrace_interrupt() {
|
||||
use nix::sys::ptrace;
|
||||
use nix::sys::signal::Signal;
|
||||
use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
|
||||
use nix::unistd::fork;
|
||||
use nix::unistd::ForkResult::*;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
require_capability!("test_ptrace_interrupt", CAP_SYS_PTRACE);
|
||||
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
match unsafe { fork() }.expect("Error: Fork Failed") {
|
||||
Child => loop {
|
||||
sleep(Duration::from_millis(1000));
|
||||
},
|
||||
Parent { child } => {
|
||||
ptrace::seize(child, ptrace::Options::PTRACE_O_TRACESYSGOOD)
|
||||
.unwrap();
|
||||
ptrace::interrupt(child).unwrap();
|
||||
assert_eq!(
|
||||
waitpid(child, None),
|
||||
Ok(WaitStatus::PtraceEvent(child, Signal::SIGTRAP, 128))
|
||||
);
|
||||
ptrace::syscall(child, None).unwrap();
|
||||
assert_eq!(
|
||||
waitpid(child, None),
|
||||
Ok(WaitStatus::PtraceSyscall(child))
|
||||
);
|
||||
ptrace::detach(child, Some(Signal::SIGKILL)).unwrap();
|
||||
match waitpid(child, None) {
|
||||
Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _))
|
||||
if pid == child =>
|
||||
{
|
||||
let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
|
||||
while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() {
|
||||
let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
|
||||
}
|
||||
}
|
||||
_ => panic!("The process should have been killed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ptrace::{setoptions, getregs} are only available in these platforms
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
any(target_arch = "x86_64", target_arch = "x86"),
|
||||
target_env = "gnu"
|
||||
))]
|
||||
#[test]
|
||||
fn test_ptrace_syscall() {
|
||||
use nix::sys::ptrace;
|
||||
use nix::sys::signal::kill;
|
||||
use nix::sys::signal::Signal;
|
||||
use nix::sys::wait::{waitpid, WaitStatus};
|
||||
use nix::unistd::fork;
|
||||
use nix::unistd::getpid;
|
||||
use nix::unistd::ForkResult::*;
|
||||
|
||||
require_capability!("test_ptrace_syscall", CAP_SYS_PTRACE);
|
||||
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
match unsafe { fork() }.expect("Error: Fork Failed") {
|
||||
Child => {
|
||||
ptrace::traceme().unwrap();
|
||||
// first sigstop until parent is ready to continue
|
||||
let pid = getpid();
|
||||
kill(pid, Signal::SIGSTOP).unwrap();
|
||||
kill(pid, Signal::SIGTERM).unwrap();
|
||||
unsafe {
|
||||
::libc::_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
Parent { child } => {
|
||||
assert_eq!(
|
||||
waitpid(child, None),
|
||||
Ok(WaitStatus::Stopped(child, Signal::SIGSTOP))
|
||||
);
|
||||
|
||||
// set this option to recognize syscall-stops
|
||||
ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD)
|
||||
.unwrap();
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let get_syscall_id =
|
||||
|| ptrace::getregs(child).unwrap().orig_rax as libc::c_long;
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
let get_syscall_id =
|
||||
|| ptrace::getregs(child).unwrap().orig_eax as libc::c_long;
|
||||
|
||||
// this duplicates `get_syscall_id` for the purpose of testing `ptrace::read_user`.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let rax_offset = offset_of!(libc::user_regs_struct, orig_rax);
|
||||
#[cfg(target_arch = "x86")]
|
||||
let rax_offset = offset_of!(libc::user_regs_struct, orig_eax);
|
||||
|
||||
let get_syscall_from_user_area = || {
|
||||
// Find the offset of `user.regs.rax` (or `user.regs.eax` for x86)
|
||||
let rax_offset = offset_of!(libc::user, regs) + rax_offset;
|
||||
ptrace::read_user(child, rax_offset as _).unwrap()
|
||||
as libc::c_long
|
||||
};
|
||||
|
||||
// kill entry
|
||||
ptrace::syscall(child, None).unwrap();
|
||||
assert_eq!(
|
||||
waitpid(child, None),
|
||||
Ok(WaitStatus::PtraceSyscall(child))
|
||||
);
|
||||
assert_eq!(get_syscall_id(), ::libc::SYS_kill);
|
||||
assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill);
|
||||
|
||||
// kill exit
|
||||
ptrace::syscall(child, None).unwrap();
|
||||
assert_eq!(
|
||||
waitpid(child, None),
|
||||
Ok(WaitStatus::PtraceSyscall(child))
|
||||
);
|
||||
assert_eq!(get_syscall_id(), ::libc::SYS_kill);
|
||||
assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill);
|
||||
|
||||
// receive signal
|
||||
ptrace::syscall(child, None).unwrap();
|
||||
assert_eq!(
|
||||
waitpid(child, None),
|
||||
Ok(WaitStatus::Stopped(child, Signal::SIGTERM))
|
||||
);
|
||||
|
||||
// inject signal
|
||||
ptrace::syscall(child, Signal::SIGTERM).unwrap();
|
||||
assert_eq!(
|
||||
waitpid(child, None),
|
||||
Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
81
third-party/vendor/nix/test/sys/test_select.rs
vendored
Normal file
81
third-party/vendor/nix/test/sys/test_select.rs
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
use nix::sys::select::*;
|
||||
use nix::sys::signal::SigSet;
|
||||
use nix::sys::time::{TimeSpec, TimeValLike};
|
||||
use nix::unistd::{pipe, write};
|
||||
|
||||
#[test]
|
||||
pub fn test_pselect() {
|
||||
let _mtx = crate::SIGNAL_MTX.lock();
|
||||
|
||||
let (r1, w1) = pipe().unwrap();
|
||||
write(w1, b"hi!").unwrap();
|
||||
let (r2, _w2) = pipe().unwrap();
|
||||
|
||||
let mut fd_set = FdSet::new();
|
||||
fd_set.insert(r1);
|
||||
fd_set.insert(r2);
|
||||
|
||||
let timeout = TimeSpec::seconds(10);
|
||||
let sigmask = SigSet::empty();
|
||||
assert_eq!(
|
||||
1,
|
||||
pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap()
|
||||
);
|
||||
assert!(fd_set.contains(r1));
|
||||
assert!(!fd_set.contains(r2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_pselect_nfds2() {
|
||||
let (r1, w1) = pipe().unwrap();
|
||||
write(w1, b"hi!").unwrap();
|
||||
let (r2, _w2) = pipe().unwrap();
|
||||
|
||||
let mut fd_set = FdSet::new();
|
||||
fd_set.insert(r1);
|
||||
fd_set.insert(r2);
|
||||
|
||||
let timeout = TimeSpec::seconds(10);
|
||||
assert_eq!(
|
||||
1,
|
||||
pselect(
|
||||
::std::cmp::max(r1, r2) + 1,
|
||||
&mut fd_set,
|
||||
None,
|
||||
None,
|
||||
&timeout,
|
||||
None
|
||||
)
|
||||
.unwrap()
|
||||
);
|
||||
assert!(fd_set.contains(r1));
|
||||
assert!(!fd_set.contains(r2));
|
||||
}
|
||||
|
||||
macro_rules! generate_fdset_bad_fd_tests {
|
||||
($fd:expr, $($method:ident),* $(,)?) => {
|
||||
$(
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn $method() {
|
||||
FdSet::new().$method($fd);
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
mod test_fdset_negative_fd {
|
||||
use super::*;
|
||||
generate_fdset_bad_fd_tests!(-1, insert, remove, contains);
|
||||
}
|
||||
|
||||
mod test_fdset_too_large_fd {
|
||||
use super::*;
|
||||
use std::convert::TryInto;
|
||||
generate_fdset_bad_fd_tests!(
|
||||
FD_SETSIZE.try_into().unwrap(),
|
||||
insert,
|
||||
remove,
|
||||
contains,
|
||||
);
|
||||
}
|
||||
147
third-party/vendor/nix/test/sys/test_signal.rs
vendored
Normal file
147
third-party/vendor/nix/test/sys/test_signal.rs
vendored
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::errno::Errno;
|
||||
use nix::sys::signal::*;
|
||||
use nix::unistd::*;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
#[test]
|
||||
fn test_kill_none() {
|
||||
kill(getpid(), None).expect("Should be able to send signal to myself.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "fuchsia"))]
|
||||
fn test_killpg_none() {
|
||||
killpg(getpgrp(), None)
|
||||
.expect("Should be able to send signal to my process group.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_old_sigaction_flags() {
|
||||
let _m = crate::SIGNAL_MTX.lock();
|
||||
|
||||
extern "C" fn handler(_: ::libc::c_int) {}
|
||||
let act = SigAction::new(
|
||||
SigHandler::Handler(handler),
|
||||
SaFlags::empty(),
|
||||
SigSet::empty(),
|
||||
);
|
||||
let oact = unsafe { sigaction(SIGINT, &act) }.unwrap();
|
||||
let _flags = oact.flags();
|
||||
let oact = unsafe { sigaction(SIGINT, &act) }.unwrap();
|
||||
let _flags = oact.flags();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sigprocmask_noop() {
|
||||
sigprocmask(SigmaskHow::SIG_BLOCK, None, None)
|
||||
.expect("this should be an effective noop");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sigprocmask() {
|
||||
let _m = crate::SIGNAL_MTX.lock();
|
||||
|
||||
// This needs to be a signal that rust doesn't use in the test harness.
|
||||
const SIGNAL: Signal = Signal::SIGCHLD;
|
||||
|
||||
let mut old_signal_set = SigSet::empty();
|
||||
sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set))
|
||||
.expect("expect to be able to retrieve old signals");
|
||||
|
||||
// Make sure the old set doesn't contain the signal, otherwise the following
|
||||
// test don't make sense.
|
||||
assert!(
|
||||
!old_signal_set.contains(SIGNAL),
|
||||
"the {:?} signal is already blocked, please change to a \
|
||||
different one",
|
||||
SIGNAL
|
||||
);
|
||||
|
||||
// Now block the signal.
|
||||
let mut signal_set = SigSet::empty();
|
||||
signal_set.add(SIGNAL);
|
||||
sigprocmask(SigmaskHow::SIG_BLOCK, Some(&signal_set), None)
|
||||
.expect("expect to be able to block signals");
|
||||
|
||||
// And test it again, to make sure the change was effective.
|
||||
old_signal_set.clear();
|
||||
sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set))
|
||||
.expect("expect to be able to retrieve old signals");
|
||||
assert!(
|
||||
old_signal_set.contains(SIGNAL),
|
||||
"expected the {:?} to be blocked",
|
||||
SIGNAL
|
||||
);
|
||||
|
||||
// Reset the signal.
|
||||
sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None)
|
||||
.expect("expect to be able to block signals");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SIGNALED: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
|
||||
extern "C" fn test_sigaction_handler(signal: libc::c_int) {
|
||||
let signal = Signal::try_from(signal).unwrap();
|
||||
SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
extern "C" fn test_sigaction_action(
|
||||
_: libc::c_int,
|
||||
_: *mut libc::siginfo_t,
|
||||
_: *mut libc::c_void,
|
||||
) {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_signal_sigaction() {
|
||||
let _m = crate::SIGNAL_MTX.lock();
|
||||
|
||||
let action_handler = SigHandler::SigAction(test_sigaction_action);
|
||||
assert_eq!(
|
||||
unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(),
|
||||
Errno::ENOTSUP
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signal() {
|
||||
let _m = crate::SIGNAL_MTX.lock();
|
||||
|
||||
unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
|
||||
raise(Signal::SIGINT).unwrap();
|
||||
assert_eq!(
|
||||
unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
|
||||
SigHandler::SigIgn
|
||||
);
|
||||
|
||||
let handler = SigHandler::Handler(test_sigaction_handler);
|
||||
assert_eq!(
|
||||
unsafe { signal(Signal::SIGINT, handler) }.unwrap(),
|
||||
SigHandler::SigDfl
|
||||
);
|
||||
raise(Signal::SIGINT).unwrap();
|
||||
assert!(SIGNALED.load(Ordering::Relaxed));
|
||||
|
||||
#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
|
||||
assert_eq!(
|
||||
unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
|
||||
handler
|
||||
);
|
||||
|
||||
// System V based OSes (e.g. illumos and Solaris) always resets the
|
||||
// disposition to SIG_DFL prior to calling the signal handler
|
||||
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
|
||||
assert_eq!(
|
||||
unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
|
||||
SigHandler::SigDfl
|
||||
);
|
||||
|
||||
// Restore default signal handler
|
||||
unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap();
|
||||
}
|
||||
27
third-party/vendor/nix/test/sys/test_signalfd.rs
vendored
Normal file
27
third-party/vendor/nix/test/sys/test_signalfd.rs
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
use std::convert::TryFrom;
|
||||
|
||||
#[test]
|
||||
fn test_signalfd() {
|
||||
use nix::sys::signal::{self, raise, SigSet, Signal};
|
||||
use nix::sys::signalfd::SignalFd;
|
||||
|
||||
// Grab the mutex for altering signals so we don't interfere with other tests.
|
||||
let _m = crate::SIGNAL_MTX.lock();
|
||||
|
||||
// Block the SIGUSR1 signal from automatic processing for this thread
|
||||
let mut mask = SigSet::empty();
|
||||
mask.add(signal::SIGUSR1);
|
||||
mask.thread_block().unwrap();
|
||||
|
||||
let mut fd = SignalFd::new(&mask).unwrap();
|
||||
|
||||
// Send a SIGUSR1 signal to the current process. Note that this uses `raise` instead of `kill`
|
||||
// because `kill` with `getpid` isn't correct during multi-threaded execution like during a
|
||||
// cargo test session. Instead use `raise` which does the correct thing by default.
|
||||
raise(signal::SIGUSR1).expect("Error: raise(SIGUSR1) failed");
|
||||
|
||||
// And now catch that same signal.
|
||||
let res = fd.read_signal().unwrap().unwrap();
|
||||
let signo = Signal::try_from(res.ssi_signo as i32).unwrap();
|
||||
assert_eq!(signo, signal::SIGUSR1);
|
||||
}
|
||||
2557
third-party/vendor/nix/test/sys/test_socket.rs
vendored
Normal file
2557
third-party/vendor/nix/test/sys/test_socket.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
356
third-party/vendor/nix/test/sys/test_sockopt.rs
vendored
Normal file
356
third-party/vendor/nix/test/sys/test_sockopt.rs
vendored
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
use crate::*;
|
||||
use nix::sys::socket::{
|
||||
getsockopt, setsockopt, socket, sockopt, AddressFamily, SockFlag,
|
||||
SockProtocol, SockType,
|
||||
};
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
// NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not.
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",))]
|
||||
#[test]
|
||||
pub fn test_local_peercred_seqpacket() {
|
||||
use nix::{
|
||||
sys::socket::socketpair,
|
||||
unistd::{Gid, Uid},
|
||||
};
|
||||
|
||||
let (fd1, _fd2) = socketpair(
|
||||
AddressFamily::Unix,
|
||||
SockType::SeqPacket,
|
||||
None,
|
||||
SockFlag::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap();
|
||||
assert_eq!(xucred.version(), 0);
|
||||
assert_eq!(Uid::from_raw(xucred.uid()), Uid::current());
|
||||
assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos",
|
||||
target_os = "ios"
|
||||
))]
|
||||
#[test]
|
||||
pub fn test_local_peercred_stream() {
|
||||
use nix::{
|
||||
sys::socket::socketpair,
|
||||
unistd::{Gid, Uid},
|
||||
};
|
||||
|
||||
let (fd1, _fd2) = socketpair(
|
||||
AddressFamily::Unix,
|
||||
SockType::Stream,
|
||||
None,
|
||||
SockFlag::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap();
|
||||
assert_eq!(xucred.version(), 0);
|
||||
assert_eq!(Uid::from_raw(xucred.uid()), Uid::current());
|
||||
assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn is_so_mark_functional() {
|
||||
use nix::sys::socket::sockopt;
|
||||
|
||||
require_capability!("is_so_mark_functional", CAP_NET_ADMIN);
|
||||
|
||||
let s = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Stream,
|
||||
SockFlag::empty(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
setsockopt(s, sockopt::Mark, &1337).unwrap();
|
||||
let mark = getsockopt(s, sockopt::Mark).unwrap();
|
||||
assert_eq!(mark, 1337);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_so_buf() {
|
||||
let fd = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Datagram,
|
||||
SockFlag::empty(),
|
||||
SockProtocol::Udp,
|
||||
)
|
||||
.unwrap();
|
||||
let bufsize: usize = thread_rng().gen_range(4096..131_072);
|
||||
setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap();
|
||||
let actual = getsockopt(fd, sockopt::SndBuf).unwrap();
|
||||
assert!(actual >= bufsize);
|
||||
setsockopt(fd, sockopt::RcvBuf, &bufsize).unwrap();
|
||||
let actual = getsockopt(fd, sockopt::RcvBuf).unwrap();
|
||||
assert!(actual >= bufsize);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_so_tcp_maxseg() {
|
||||
use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn};
|
||||
use nix::unistd::{close, write};
|
||||
use std::net::SocketAddrV4;
|
||||
use std::str::FromStr;
|
||||
|
||||
let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap();
|
||||
let sock_addr = SockaddrIn::from(std_sa);
|
||||
|
||||
let rsock = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Stream,
|
||||
SockFlag::empty(),
|
||||
SockProtocol::Tcp,
|
||||
)
|
||||
.unwrap();
|
||||
bind(rsock, &sock_addr).unwrap();
|
||||
listen(rsock, 10).unwrap();
|
||||
let initial = getsockopt(rsock, sockopt::TcpMaxSeg).unwrap();
|
||||
// Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some
|
||||
// platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger
|
||||
// than 700
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "linux"))] {
|
||||
let segsize: u32 = 873;
|
||||
assert!(initial < segsize);
|
||||
setsockopt(rsock, sockopt::TcpMaxSeg, &segsize).unwrap();
|
||||
} else {
|
||||
assert!(initial < 700);
|
||||
}
|
||||
}
|
||||
|
||||
// Connect and check the MSS that was advertised
|
||||
let ssock = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Stream,
|
||||
SockFlag::empty(),
|
||||
SockProtocol::Tcp,
|
||||
)
|
||||
.unwrap();
|
||||
connect(ssock, &sock_addr).unwrap();
|
||||
let rsess = accept(rsock).unwrap();
|
||||
write(rsess, b"hello").unwrap();
|
||||
let actual = getsockopt(ssock, sockopt::TcpMaxSeg).unwrap();
|
||||
// Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max
|
||||
// TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary.
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "linux"))] {
|
||||
assert!((segsize - 100) <= actual);
|
||||
assert!(actual <= segsize);
|
||||
} else {
|
||||
assert!(initial < actual);
|
||||
assert!(536 < actual);
|
||||
}
|
||||
}
|
||||
close(rsock).unwrap();
|
||||
close(ssock).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_so_type() {
|
||||
let sockfd = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Stream,
|
||||
SockFlag::empty(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(Ok(SockType::Stream), getsockopt(sockfd, sockopt::SockType));
|
||||
}
|
||||
|
||||
/// getsockopt(_, sockopt::SockType) should gracefully handle unknown socket
|
||||
/// types. Regression test for https://github.com/nix-rust/nix/issues/1819
|
||||
#[cfg(any(target_os = "android", target_os = "linux",))]
|
||||
#[test]
|
||||
fn test_so_type_unknown() {
|
||||
use nix::errno::Errno;
|
||||
|
||||
require_capability!("test_so_type", CAP_NET_RAW);
|
||||
let sockfd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) };
|
||||
assert!(sockfd >= 0, "Error opening socket: {}", nix::Error::last());
|
||||
|
||||
assert_eq!(Err(Errno::EINVAL), getsockopt(sockfd, sockopt::SockType));
|
||||
}
|
||||
|
||||
// The CI doesn't supported getsockopt and setsockopt on emulated processors.
|
||||
// It's believed that a QEMU issue, the tests run ok on a fully emulated system.
|
||||
// Current CI just run the binary with QEMU but the Kernel remains the same as the host.
|
||||
// So the syscall doesn't work properly unless the kernel is also emulated.
|
||||
#[test]
|
||||
#[cfg(all(
|
||||
any(target_arch = "x86", target_arch = "x86_64"),
|
||||
any(target_os = "freebsd", target_os = "linux")
|
||||
))]
|
||||
fn test_tcp_congestion() {
|
||||
use std::ffi::OsString;
|
||||
|
||||
let fd = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Stream,
|
||||
SockFlag::empty(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let val = getsockopt(fd, sockopt::TcpCongestion).unwrap();
|
||||
setsockopt(fd, sockopt::TcpCongestion, &val).unwrap();
|
||||
|
||||
setsockopt(
|
||||
fd,
|
||||
sockopt::TcpCongestion,
|
||||
&OsString::from("tcp_congestion_does_not_exist"),
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(getsockopt(fd, sockopt::TcpCongestion).unwrap(), val);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn test_bindtodevice() {
|
||||
skip_if_not_root!("test_bindtodevice");
|
||||
|
||||
let fd = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Stream,
|
||||
SockFlag::empty(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let val = getsockopt(fd, sockopt::BindToDevice).unwrap();
|
||||
setsockopt(fd, sockopt::BindToDevice, &val).unwrap();
|
||||
|
||||
assert_eq!(getsockopt(fd, sockopt::BindToDevice).unwrap(), val);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_so_tcp_keepalive() {
|
||||
let fd = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Stream,
|
||||
SockFlag::empty(),
|
||||
SockProtocol::Tcp,
|
||||
)
|
||||
.unwrap();
|
||||
setsockopt(fd, sockopt::KeepAlive, &true).unwrap();
|
||||
assert!(getsockopt(fd, sockopt::KeepAlive).unwrap());
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux"
|
||||
))]
|
||||
{
|
||||
let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap();
|
||||
setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap();
|
||||
assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1);
|
||||
|
||||
let x = getsockopt(fd, sockopt::TcpKeepCount).unwrap();
|
||||
setsockopt(fd, sockopt::TcpKeepCount, &(x + 1)).unwrap();
|
||||
assert_eq!(getsockopt(fd, sockopt::TcpKeepCount).unwrap(), x + 1);
|
||||
|
||||
let x = getsockopt(fd, sockopt::TcpKeepInterval).unwrap();
|
||||
setsockopt(fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap();
|
||||
assert_eq!(getsockopt(fd, sockopt::TcpKeepInterval).unwrap(), x + 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
|
||||
fn test_ttl_opts() {
|
||||
let fd4 = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Datagram,
|
||||
SockFlag::empty(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
setsockopt(fd4, sockopt::Ipv4Ttl, &1)
|
||||
.expect("setting ipv4ttl on an inet socket should succeed");
|
||||
let fd6 = socket(
|
||||
AddressFamily::Inet6,
|
||||
SockType::Datagram,
|
||||
SockFlag::empty(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
setsockopt(fd6, sockopt::Ipv6Ttl, &1)
|
||||
.expect("setting ipv6ttl on an inet6 socket should succeed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
fn test_dontfrag_opts() {
|
||||
let fd4 = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Stream,
|
||||
SockFlag::empty(),
|
||||
SockProtocol::Tcp,
|
||||
)
|
||||
.unwrap();
|
||||
setsockopt(fd4, sockopt::IpDontFrag, &true)
|
||||
.expect("setting IP_DONTFRAG on an inet stream socket should succeed");
|
||||
setsockopt(fd4, sockopt::IpDontFrag, &false).expect(
|
||||
"unsetting IP_DONTFRAG on an inet stream socket should succeed",
|
||||
);
|
||||
let fd4d = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Datagram,
|
||||
SockFlag::empty(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
setsockopt(fd4d, sockopt::IpDontFrag, &true).expect(
|
||||
"setting IP_DONTFRAG on an inet datagram socket should succeed",
|
||||
);
|
||||
setsockopt(fd4d, sockopt::IpDontFrag, &false).expect(
|
||||
"unsetting IP_DONTFRAG on an inet datagram socket should succeed",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
))]
|
||||
// Disable the test under emulation because it fails in Cirrus-CI. Lack
|
||||
// of QEMU support is suspected.
|
||||
#[cfg_attr(qemu, ignore)]
|
||||
fn test_v6dontfrag_opts() {
|
||||
let fd6 = socket(
|
||||
AddressFamily::Inet6,
|
||||
SockType::Stream,
|
||||
SockFlag::empty(),
|
||||
SockProtocol::Tcp,
|
||||
)
|
||||
.unwrap();
|
||||
setsockopt(fd6, sockopt::Ipv6DontFrag, &true).expect(
|
||||
"setting IPV6_DONTFRAG on an inet6 stream socket should succeed",
|
||||
);
|
||||
setsockopt(fd6, sockopt::Ipv6DontFrag, &false).expect(
|
||||
"unsetting IPV6_DONTFRAG on an inet6 stream socket should succeed",
|
||||
);
|
||||
let fd6d = socket(
|
||||
AddressFamily::Inet6,
|
||||
SockType::Datagram,
|
||||
SockFlag::empty(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
setsockopt(fd6d, sockopt::Ipv6DontFrag, &true).expect(
|
||||
"setting IPV6_DONTFRAG on an inet6 datagram socket should succeed",
|
||||
);
|
||||
setsockopt(fd6d, sockopt::Ipv6DontFrag, &false).expect(
|
||||
"unsetting IPV6_DONTFRAG on an inet6 datagram socket should succeed",
|
||||
);
|
||||
}
|
||||
29
third-party/vendor/nix/test/sys/test_stat.rs
vendored
Normal file
29
third-party/vendor/nix/test/sys/test_stat.rs
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// The conversion is not useless on all platforms.
|
||||
#[allow(clippy::useless_conversion)]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[test]
|
||||
fn test_chflags() {
|
||||
use nix::{
|
||||
sys::stat::{fstat, FileFlag},
|
||||
unistd::chflags,
|
||||
};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
let f = NamedTempFile::new().unwrap();
|
||||
|
||||
let initial = FileFlag::from_bits_truncate(
|
||||
fstat(f.as_raw_fd()).unwrap().st_flags.into(),
|
||||
);
|
||||
// UF_OFFLINE is preserved by all FreeBSD file systems, but not interpreted
|
||||
// in any way, so it's handy for testing.
|
||||
let commanded = initial ^ FileFlag::UF_OFFLINE;
|
||||
|
||||
chflags(f.path(), commanded).unwrap();
|
||||
|
||||
let changed = FileFlag::from_bits_truncate(
|
||||
fstat(f.as_raw_fd()).unwrap().st_flags.into(),
|
||||
);
|
||||
|
||||
assert_eq!(commanded, changed);
|
||||
}
|
||||
20
third-party/vendor/nix/test/sys/test_sysinfo.rs
vendored
Normal file
20
third-party/vendor/nix/test/sys/test_sysinfo.rs
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
use nix::sys::sysinfo::*;
|
||||
|
||||
#[test]
|
||||
fn sysinfo_works() {
|
||||
let info = sysinfo().unwrap();
|
||||
|
||||
let (l1, l5, l15) = info.load_average();
|
||||
assert!(l1 >= 0.0);
|
||||
assert!(l5 >= 0.0);
|
||||
assert!(l15 >= 0.0);
|
||||
|
||||
info.uptime(); // just test Duration construction
|
||||
|
||||
assert!(
|
||||
info.swap_free() <= info.swap_total(),
|
||||
"more swap available than installed (free: {}, total: {})",
|
||||
info.swap_free(),
|
||||
info.swap_total()
|
||||
);
|
||||
}
|
||||
136
third-party/vendor/nix/test/sys/test_termios.rs
vendored
Normal file
136
third-party/vendor/nix/test/sys/test_termios.rs
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
use std::os::unix::prelude::*;
|
||||
use tempfile::tempfile;
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::fcntl;
|
||||
use nix::pty::openpty;
|
||||
use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags};
|
||||
use nix::unistd::{close, read, write};
|
||||
|
||||
/// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s
|
||||
fn write_all(f: RawFd, buf: &[u8]) {
|
||||
let mut len = 0;
|
||||
while len < buf.len() {
|
||||
len += write(f, &buf[len..]).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Test tcgetattr on a terminal
|
||||
#[test]
|
||||
fn test_tcgetattr_pty() {
|
||||
// openpty uses ptname(3) internally
|
||||
let _m = crate::PTSNAME_MTX.lock();
|
||||
|
||||
let pty = openpty(None, None).expect("openpty failed");
|
||||
termios::tcgetattr(pty.slave).unwrap();
|
||||
close(pty.master).expect("closing the master failed");
|
||||
close(pty.slave).expect("closing the slave failed");
|
||||
}
|
||||
|
||||
// Test tcgetattr on something that isn't a terminal
|
||||
#[test]
|
||||
fn test_tcgetattr_enotty() {
|
||||
let file = tempfile().unwrap();
|
||||
assert_eq!(
|
||||
termios::tcgetattr(file.as_raw_fd()).err(),
|
||||
Some(Errno::ENOTTY)
|
||||
);
|
||||
}
|
||||
|
||||
// Test tcgetattr on an invalid file descriptor
|
||||
#[test]
|
||||
fn test_tcgetattr_ebadf() {
|
||||
assert_eq!(termios::tcgetattr(-1).err(), Some(Errno::EBADF));
|
||||
}
|
||||
|
||||
// Test modifying output flags
|
||||
#[test]
|
||||
fn test_output_flags() {
|
||||
// openpty uses ptname(3) internally
|
||||
let _m = crate::PTSNAME_MTX.lock();
|
||||
|
||||
// Open one pty to get attributes for the second one
|
||||
let mut termios = {
|
||||
let pty = openpty(None, None).expect("openpty failed");
|
||||
assert!(pty.master > 0);
|
||||
assert!(pty.slave > 0);
|
||||
let termios = tcgetattr(pty.slave).expect("tcgetattr failed");
|
||||
close(pty.master).unwrap();
|
||||
close(pty.slave).unwrap();
|
||||
termios
|
||||
};
|
||||
|
||||
// Make sure postprocessing '\r' isn't specified by default or this test is useless.
|
||||
assert!(!termios
|
||||
.output_flags
|
||||
.contains(OutputFlags::OPOST | OutputFlags::OCRNL));
|
||||
|
||||
// Specify that '\r' characters should be transformed to '\n'
|
||||
// OPOST is specified to enable post-processing
|
||||
termios
|
||||
.output_flags
|
||||
.insert(OutputFlags::OPOST | OutputFlags::OCRNL);
|
||||
|
||||
// Open a pty
|
||||
let pty = openpty(None, &termios).unwrap();
|
||||
assert!(pty.master > 0);
|
||||
assert!(pty.slave > 0);
|
||||
|
||||
// Write into the master
|
||||
let string = "foofoofoo\r";
|
||||
write_all(pty.master, string.as_bytes());
|
||||
|
||||
// Read from the slave verifying that the output has been properly transformed
|
||||
let mut buf = [0u8; 10];
|
||||
crate::read_exact(pty.slave, &mut buf);
|
||||
let transformed_string = "foofoofoo\n";
|
||||
close(pty.master).unwrap();
|
||||
close(pty.slave).unwrap();
|
||||
assert_eq!(&buf, transformed_string.as_bytes());
|
||||
}
|
||||
|
||||
// Test modifying local flags
|
||||
#[test]
|
||||
fn test_local_flags() {
|
||||
// openpty uses ptname(3) internally
|
||||
let _m = crate::PTSNAME_MTX.lock();
|
||||
|
||||
// Open one pty to get attributes for the second one
|
||||
let mut termios = {
|
||||
let pty = openpty(None, None).unwrap();
|
||||
assert!(pty.master > 0);
|
||||
assert!(pty.slave > 0);
|
||||
let termios = tcgetattr(pty.slave).unwrap();
|
||||
close(pty.master).unwrap();
|
||||
close(pty.slave).unwrap();
|
||||
termios
|
||||
};
|
||||
|
||||
// Make sure echo is specified by default or this test is useless.
|
||||
assert!(termios.local_flags.contains(LocalFlags::ECHO));
|
||||
|
||||
// Disable local echo
|
||||
termios.local_flags.remove(LocalFlags::ECHO);
|
||||
|
||||
// Open a new pty with our modified termios settings
|
||||
let pty = openpty(None, &termios).unwrap();
|
||||
assert!(pty.master > 0);
|
||||
assert!(pty.slave > 0);
|
||||
|
||||
// Set the master is in nonblocking mode or reading will never return.
|
||||
let flags = fcntl::fcntl(pty.master, fcntl::F_GETFL).unwrap();
|
||||
let new_flags =
|
||||
fcntl::OFlag::from_bits_truncate(flags) | fcntl::OFlag::O_NONBLOCK;
|
||||
fcntl::fcntl(pty.master, fcntl::F_SETFL(new_flags)).unwrap();
|
||||
|
||||
// Write into the master
|
||||
let string = "foofoofoo\r";
|
||||
write_all(pty.master, string.as_bytes());
|
||||
|
||||
// Try to read from the master, which should not have anything as echoing was disabled.
|
||||
let mut buf = [0u8; 10];
|
||||
let read = read(pty.master, &mut buf).unwrap_err();
|
||||
close(pty.master).unwrap();
|
||||
close(pty.slave).unwrap();
|
||||
assert_eq!(read, Errno::EAGAIN);
|
||||
}
|
||||
69
third-party/vendor/nix/test/sys/test_timerfd.rs
vendored
Normal file
69
third-party/vendor/nix/test/sys/test_timerfd.rs
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
use nix::sys::time::{TimeSpec, TimeValLike};
|
||||
use nix::sys::timerfd::{
|
||||
ClockId, Expiration, TimerFd, TimerFlags, TimerSetTimeFlags,
|
||||
};
|
||||
use std::time::Instant;
|
||||
|
||||
#[test]
|
||||
pub fn test_timerfd_oneshot() {
|
||||
let timer =
|
||||
TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
|
||||
|
||||
let before = Instant::now();
|
||||
|
||||
timer
|
||||
.set(
|
||||
Expiration::OneShot(TimeSpec::seconds(1)),
|
||||
TimerSetTimeFlags::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
timer.wait().unwrap();
|
||||
|
||||
let millis = before.elapsed().as_millis();
|
||||
assert!(millis > 900);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timerfd_interval() {
|
||||
let timer =
|
||||
TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
|
||||
|
||||
let before = Instant::now();
|
||||
timer
|
||||
.set(
|
||||
Expiration::IntervalDelayed(
|
||||
TimeSpec::seconds(1),
|
||||
TimeSpec::seconds(2),
|
||||
),
|
||||
TimerSetTimeFlags::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
timer.wait().unwrap();
|
||||
|
||||
let start_delay = before.elapsed().as_millis();
|
||||
assert!(start_delay > 900);
|
||||
|
||||
timer.wait().unwrap();
|
||||
|
||||
let interval_delay = before.elapsed().as_millis();
|
||||
assert!(interval_delay > 2900);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_timerfd_unset() {
|
||||
let timer =
|
||||
TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
|
||||
|
||||
timer
|
||||
.set(
|
||||
Expiration::OneShot(TimeSpec::seconds(1)),
|
||||
TimerSetTimeFlags::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
timer.unset().unwrap();
|
||||
|
||||
assert!(timer.get().unwrap().is_none());
|
||||
}
|
||||
270
third-party/vendor/nix/test/sys/test_uio.rs
vendored
Normal file
270
third-party/vendor/nix/test/sys/test_uio.rs
vendored
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
use nix::sys::uio::*;
|
||||
use nix::unistd::*;
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::IoSlice;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::{cmp, iter};
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use std::io::IoSliceMut;
|
||||
|
||||
use tempfile::tempdir;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use tempfile::tempfile;
|
||||
|
||||
#[test]
|
||||
fn test_writev() {
|
||||
let mut to_write = Vec::with_capacity(16 * 128);
|
||||
for _ in 0..16 {
|
||||
let s: String = thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.map(char::from)
|
||||
.take(128)
|
||||
.collect();
|
||||
let b = s.as_bytes();
|
||||
to_write.extend(b.iter().cloned());
|
||||
}
|
||||
// Allocate and fill iovecs
|
||||
let mut iovecs = Vec::new();
|
||||
let mut consumed = 0;
|
||||
while consumed < to_write.len() {
|
||||
let left = to_write.len() - consumed;
|
||||
let slice_len = if left <= 64 {
|
||||
left
|
||||
} else {
|
||||
thread_rng().gen_range(64..cmp::min(256, left))
|
||||
};
|
||||
let b = &to_write[consumed..consumed + slice_len];
|
||||
iovecs.push(IoSlice::new(b));
|
||||
consumed += slice_len;
|
||||
}
|
||||
let pipe_res = pipe();
|
||||
let (reader, writer) = pipe_res.expect("Couldn't create pipe");
|
||||
// FileDesc will close its filedesc (reader).
|
||||
let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect();
|
||||
// Blocking io, should write all data.
|
||||
let write_res = writev(writer, &iovecs);
|
||||
let written = write_res.expect("couldn't write");
|
||||
// Check whether we written all data
|
||||
assert_eq!(to_write.len(), written);
|
||||
let read_res = read(reader, &mut read_buf[..]);
|
||||
let read = read_res.expect("couldn't read");
|
||||
// Check we have read as much as we written
|
||||
assert_eq!(read, written);
|
||||
// Check equality of written and read data
|
||||
assert_eq!(&to_write, &read_buf);
|
||||
close(writer).expect("closed writer");
|
||||
close(reader).expect("closed reader");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_readv() {
|
||||
let s: String = thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.map(char::from)
|
||||
.take(128)
|
||||
.collect();
|
||||
let to_write = s.as_bytes().to_vec();
|
||||
let mut storage = Vec::new();
|
||||
let mut allocated = 0;
|
||||
while allocated < to_write.len() {
|
||||
let left = to_write.len() - allocated;
|
||||
let vec_len = if left <= 64 {
|
||||
left
|
||||
} else {
|
||||
thread_rng().gen_range(64..cmp::min(256, left))
|
||||
};
|
||||
let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect();
|
||||
storage.push(v);
|
||||
allocated += vec_len;
|
||||
}
|
||||
let mut iovecs = Vec::with_capacity(storage.len());
|
||||
for v in &mut storage {
|
||||
iovecs.push(IoSliceMut::new(&mut v[..]));
|
||||
}
|
||||
let (reader, writer) = pipe().expect("couldn't create pipe");
|
||||
// Blocking io, should write all data.
|
||||
write(writer, &to_write).expect("write failed");
|
||||
let read = readv(reader, &mut iovecs[..]).expect("read failed");
|
||||
// Check whether we've read all data
|
||||
assert_eq!(to_write.len(), read);
|
||||
// Cccumulate data from iovecs
|
||||
let mut read_buf = Vec::with_capacity(to_write.len());
|
||||
for iovec in &iovecs {
|
||||
read_buf.extend(iovec.iter().cloned());
|
||||
}
|
||||
// Check whether iovecs contain all written data
|
||||
assert_eq!(read_buf.len(), to_write.len());
|
||||
// Check equality of written and read data
|
||||
assert_eq!(&read_buf, &to_write);
|
||||
close(reader).expect("couldn't close reader");
|
||||
close(writer).expect("couldn't close writer");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_pwrite() {
|
||||
use std::io::Read;
|
||||
|
||||
let mut file = tempfile().unwrap();
|
||||
let buf = [1u8; 8];
|
||||
assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8));
|
||||
let mut file_content = Vec::new();
|
||||
file.read_to_end(&mut file_content).unwrap();
|
||||
let mut expected = vec![0u8; 8];
|
||||
expected.extend(vec![1; 8]);
|
||||
assert_eq!(file_content, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pread() {
|
||||
use std::io::Write;
|
||||
|
||||
let tempdir = tempdir().unwrap();
|
||||
|
||||
let path = tempdir.path().join("pread_test_file");
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.read(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(path)
|
||||
.unwrap();
|
||||
let file_content: Vec<u8> = (0..64).collect();
|
||||
file.write_all(&file_content).unwrap();
|
||||
|
||||
let mut buf = [0u8; 16];
|
||||
assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16));
|
||||
let expected: Vec<_> = (16..32).collect();
|
||||
assert_eq!(&buf[..], &expected[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
fn test_pwritev() {
|
||||
use std::io::Read;
|
||||
|
||||
let to_write: Vec<u8> = (0..128).collect();
|
||||
let expected: Vec<u8> = [vec![0; 100], to_write.clone()].concat();
|
||||
|
||||
let iovecs = [
|
||||
IoSlice::new(&to_write[0..17]),
|
||||
IoSlice::new(&to_write[17..64]),
|
||||
IoSlice::new(&to_write[64..128]),
|
||||
];
|
||||
|
||||
let tempdir = tempdir().unwrap();
|
||||
|
||||
// pwritev them into a temporary file
|
||||
let path = tempdir.path().join("pwritev_test_file");
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.read(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(path)
|
||||
.unwrap();
|
||||
|
||||
let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap();
|
||||
assert_eq!(written, to_write.len());
|
||||
|
||||
// Read the data back and make sure it matches
|
||||
let mut contents = Vec::new();
|
||||
file.read_to_end(&mut contents).unwrap();
|
||||
assert_eq!(contents, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
fn test_preadv() {
|
||||
use std::io::Write;
|
||||
|
||||
let to_write: Vec<u8> = (0..200).collect();
|
||||
let expected: Vec<u8> = (100..200).collect();
|
||||
|
||||
let tempdir = tempdir().unwrap();
|
||||
|
||||
let path = tempdir.path().join("preadv_test_file");
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(path)
|
||||
.unwrap();
|
||||
file.write_all(&to_write).unwrap();
|
||||
|
||||
let mut buffers: Vec<Vec<u8>> = vec![vec![0; 24], vec![0; 1], vec![0; 75]];
|
||||
|
||||
{
|
||||
// Borrow the buffers into IoVecs and preadv into them
|
||||
let mut iovecs: Vec<_> = buffers
|
||||
.iter_mut()
|
||||
.map(|buf| IoSliceMut::new(&mut buf[..]))
|
||||
.collect();
|
||||
assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100));
|
||||
}
|
||||
|
||||
let all = buffers.concat();
|
||||
assert_eq!(all, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
|
||||
// uclibc doesn't implement process_vm_readv
|
||||
// qemu-user doesn't implement process_vm_readv/writev on most arches
|
||||
#[cfg_attr(qemu, ignore)]
|
||||
fn test_process_vm_readv() {
|
||||
use crate::*;
|
||||
use nix::sys::signal::*;
|
||||
use nix::sys::wait::*;
|
||||
use nix::unistd::ForkResult::*;
|
||||
|
||||
require_capability!("test_process_vm_readv", CAP_SYS_PTRACE);
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
// Pre-allocate memory in the child, since allocation isn't safe
|
||||
// post-fork (~= async-signal-safe)
|
||||
let mut vector = vec![1u8, 2, 3, 4, 5];
|
||||
|
||||
let (r, w) = pipe().unwrap();
|
||||
match unsafe { fork() }.expect("Error: Fork Failed") {
|
||||
Parent { child } => {
|
||||
close(w).unwrap();
|
||||
// wait for child
|
||||
read(r, &mut [0u8]).unwrap();
|
||||
close(r).unwrap();
|
||||
|
||||
let ptr = vector.as_ptr() as usize;
|
||||
let remote_iov = RemoteIoVec { base: ptr, len: 5 };
|
||||
let mut buf = vec![0u8; 5];
|
||||
|
||||
let ret = process_vm_readv(
|
||||
child,
|
||||
&mut [IoSliceMut::new(&mut buf)],
|
||||
&[remote_iov],
|
||||
);
|
||||
|
||||
kill(child, SIGTERM).unwrap();
|
||||
waitpid(child, None).unwrap();
|
||||
|
||||
assert_eq!(Ok(5), ret);
|
||||
assert_eq!(20u8, buf.iter().sum());
|
||||
}
|
||||
Child => {
|
||||
let _ = close(r);
|
||||
for i in &mut vector {
|
||||
*i += 1;
|
||||
}
|
||||
let _ = write(w, b"\0");
|
||||
let _ = close(w);
|
||||
loop {
|
||||
pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
257
third-party/vendor/nix/test/sys/test_wait.rs
vendored
Normal file
257
third-party/vendor/nix/test/sys/test_wait.rs
vendored
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
use libc::_exit;
|
||||
use nix::errno::Errno;
|
||||
use nix::sys::signal::*;
|
||||
use nix::sys::wait::*;
|
||||
use nix::unistd::ForkResult::*;
|
||||
use nix::unistd::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
fn test_wait_signal() {
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
// Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe.
|
||||
match unsafe { fork() }.expect("Error: Fork Failed") {
|
||||
Child => {
|
||||
pause();
|
||||
unsafe { _exit(123) }
|
||||
}
|
||||
Parent { child } => {
|
||||
kill(child, Some(SIGKILL)).expect("Error: Kill Failed");
|
||||
assert_eq!(
|
||||
waitpid(child, None),
|
||||
Ok(WaitStatus::Signaled(child, SIGKILL, false))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
//target_os = "haiku",
|
||||
all(target_os = "linux", not(target_env = "uclibc")),
|
||||
))]
|
||||
#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
|
||||
fn test_waitid_signal() {
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
// Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe.
|
||||
match unsafe { fork() }.expect("Error: Fork Failed") {
|
||||
Child => {
|
||||
pause();
|
||||
unsafe { _exit(123) }
|
||||
}
|
||||
Parent { child } => {
|
||||
kill(child, Some(SIGKILL)).expect("Error: Kill Failed");
|
||||
assert_eq!(
|
||||
waitid(Id::Pid(child), WaitPidFlag::WEXITED),
|
||||
Ok(WaitStatus::Signaled(child, SIGKILL, false)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wait_exit() {
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
// Safe: Child only calls `_exit`, which is async-signal-safe.
|
||||
match unsafe { fork() }.expect("Error: Fork Failed") {
|
||||
Child => unsafe {
|
||||
_exit(12);
|
||||
},
|
||||
Parent { child } => {
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "haiku"))]
|
||||
#[test]
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
all(target_os = "linux", not(target_env = "uclibc")),
|
||||
))]
|
||||
#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
|
||||
fn test_waitid_exit() {
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
// Safe: Child only calls `_exit`, which is async-signal-safe.
|
||||
match unsafe { fork() }.expect("Error: Fork Failed") {
|
||||
Child => unsafe {
|
||||
_exit(12);
|
||||
},
|
||||
Parent { child } => {
|
||||
assert_eq!(
|
||||
waitid(Id::Pid(child), WaitPidFlag::WEXITED),
|
||||
Ok(WaitStatus::Exited(child, 12)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_waitstatus_from_raw() {
|
||||
let pid = Pid::from_raw(1);
|
||||
assert_eq!(
|
||||
WaitStatus::from_raw(pid, 0x0002),
|
||||
Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false))
|
||||
);
|
||||
assert_eq!(
|
||||
WaitStatus::from_raw(pid, 0x0200),
|
||||
Ok(WaitStatus::Exited(pid, 2))
|
||||
);
|
||||
assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Errno::EINVAL));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_waitstatus_pid() {
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
match unsafe { fork() }.unwrap() {
|
||||
Child => unsafe { _exit(0) },
|
||||
Parent { child } => {
|
||||
let status = waitpid(child, None).unwrap();
|
||||
assert_eq!(status.pid(), Some(child));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "haiku",
|
||||
all(target_os = "linux", not(target_env = "uclibc")),
|
||||
))]
|
||||
fn test_waitid_pid() {
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
match unsafe { fork() }.unwrap() {
|
||||
Child => unsafe { _exit(0) },
|
||||
Parent { child } => {
|
||||
let status = waitid(Id::Pid(child), WaitPidFlag::WEXITED).unwrap();
|
||||
assert_eq!(status.pid(), Some(child));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
// FIXME: qemu-user doesn't implement ptrace on most arches
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
mod ptrace {
|
||||
use crate::*;
|
||||
use libc::_exit;
|
||||
use nix::sys::ptrace::{self, Event, Options};
|
||||
use nix::sys::signal::*;
|
||||
use nix::sys::wait::*;
|
||||
use nix::unistd::ForkResult::*;
|
||||
use nix::unistd::*;
|
||||
|
||||
fn ptrace_child() -> ! {
|
||||
ptrace::traceme().unwrap();
|
||||
// As recommended by ptrace(2), raise SIGTRAP to pause the child
|
||||
// until the parent is ready to continue
|
||||
raise(SIGTRAP).unwrap();
|
||||
unsafe { _exit(0) }
|
||||
}
|
||||
|
||||
fn ptrace_wait_parent(child: Pid) {
|
||||
// Wait for the raised SIGTRAP
|
||||
assert_eq!(
|
||||
waitpid(child, None),
|
||||
Ok(WaitStatus::Stopped(child, SIGTRAP))
|
||||
);
|
||||
// We want to test a syscall stop and a PTRACE_EVENT stop
|
||||
ptrace::setoptions(
|
||||
child,
|
||||
Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT,
|
||||
)
|
||||
.expect("setoptions failed");
|
||||
|
||||
// First, stop on the next system call, which will be exit()
|
||||
ptrace::syscall(child, None).expect("syscall failed");
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
|
||||
// Then get the ptrace event for the process exiting
|
||||
ptrace::cont(child, None).expect("cont failed");
|
||||
assert_eq!(
|
||||
waitpid(child, None),
|
||||
Ok(WaitStatus::PtraceEvent(
|
||||
child,
|
||||
SIGTRAP,
|
||||
Event::PTRACE_EVENT_EXIT as i32
|
||||
))
|
||||
);
|
||||
// Finally get the normal wait() result, now that the process has exited
|
||||
ptrace::cont(child, None).expect("cont failed");
|
||||
assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0)));
|
||||
}
|
||||
|
||||
#[cfg(not(target_env = "uclibc"))]
|
||||
fn ptrace_waitid_parent(child: Pid) {
|
||||
// Wait for the raised SIGTRAP
|
||||
//
|
||||
// Unlike waitpid(), waitid() can distinguish trap events from regular
|
||||
// stop events, so unlike ptrace_wait_parent(), we get a PtraceEvent here
|
||||
assert_eq!(
|
||||
waitid(Id::Pid(child), WaitPidFlag::WEXITED),
|
||||
Ok(WaitStatus::PtraceEvent(child, SIGTRAP, 0)),
|
||||
);
|
||||
// We want to test a syscall stop and a PTRACE_EVENT stop
|
||||
ptrace::setoptions(
|
||||
child,
|
||||
Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT,
|
||||
)
|
||||
.expect("setopts failed");
|
||||
|
||||
// First, stop on the next system call, which will be exit()
|
||||
ptrace::syscall(child, None).expect("syscall failed");
|
||||
assert_eq!(
|
||||
waitid(Id::Pid(child), WaitPidFlag::WEXITED),
|
||||
Ok(WaitStatus::PtraceSyscall(child)),
|
||||
);
|
||||
// Then get the ptrace event for the process exiting
|
||||
ptrace::cont(child, None).expect("cont failed");
|
||||
assert_eq!(
|
||||
waitid(Id::Pid(child), WaitPidFlag::WEXITED),
|
||||
Ok(WaitStatus::PtraceEvent(
|
||||
child,
|
||||
SIGTRAP,
|
||||
Event::PTRACE_EVENT_EXIT as i32
|
||||
)),
|
||||
);
|
||||
// Finally get the normal wait() result, now that the process has exited
|
||||
ptrace::cont(child, None).expect("cont failed");
|
||||
assert_eq!(
|
||||
waitid(Id::Pid(child), WaitPidFlag::WEXITED),
|
||||
Ok(WaitStatus::Exited(child, 0)),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wait_ptrace() {
|
||||
require_capability!("test_wait_ptrace", CAP_SYS_PTRACE);
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
match unsafe { fork() }.expect("Error: Fork Failed") {
|
||||
Child => ptrace_child(),
|
||||
Parent { child } => ptrace_wait_parent(child),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_env = "uclibc"))]
|
||||
fn test_waitid_ptrace() {
|
||||
require_capability!("test_waitid_ptrace", CAP_SYS_PTRACE);
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
match unsafe { fork() }.expect("Error: Fork Failed") {
|
||||
Child => ptrace_child(),
|
||||
Parent { child } => ptrace_waitid_parent(child),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue