Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
149
third-party/vendor/nix/test/common/mod.rs
vendored
Normal file
149
third-party/vendor/nix/test/common/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
use cfg_if::cfg_if;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! skip {
|
||||
($($reason: expr),+) => {
|
||||
use ::std::io::{self, Write};
|
||||
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
writeln!(handle, $($reason),+).unwrap();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "linux"))] {
|
||||
#[macro_export] macro_rules! require_capability {
|
||||
($name:expr, $capname:ident) => {
|
||||
use ::caps::{Capability, CapSet, has_cap};
|
||||
|
||||
if !has_cap(None, CapSet::Effective, Capability::$capname)
|
||||
.unwrap()
|
||||
{
|
||||
skip!("{} requires capability {}. Skipping test.", $name, Capability::$capname);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if #[cfg(not(target_os = "redox"))] {
|
||||
#[macro_export] macro_rules! require_capability {
|
||||
($name:expr, $capname:ident) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Skip the test if we don't have the ability to mount file systems.
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[macro_export]
|
||||
macro_rules! require_mount {
|
||||
($name:expr) => {
|
||||
use ::sysctl::{CtlValue, Sysctl};
|
||||
use nix::unistd::Uid;
|
||||
|
||||
let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap();
|
||||
if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap()
|
||||
{
|
||||
skip!(
|
||||
"{} requires the ability to mount file systems. Skipping test.",
|
||||
$name
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[macro_export]
|
||||
macro_rules! skip_if_cirrus {
|
||||
($reason:expr) => {
|
||||
if std::env::var_os("CIRRUS_CI").is_some() {
|
||||
skip!("{}", $reason);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[macro_export]
|
||||
macro_rules! skip_if_jailed {
|
||||
($name:expr) => {
|
||||
use ::sysctl::{CtlValue, Sysctl};
|
||||
|
||||
let ctl = ::sysctl::Ctl::new("security.jail.jailed").unwrap();
|
||||
if let CtlValue::Int(1) = ctl.value().unwrap() {
|
||||
skip!("{} cannot run in a jail. Skipping test.", $name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
|
||||
#[macro_export]
|
||||
macro_rules! skip_if_not_root {
|
||||
($name:expr) => {
|
||||
use nix::unistd::Uid;
|
||||
|
||||
if !Uid::current().is_root() {
|
||||
skip!("{} requires root privileges. Skipping test.", $name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "linux"))] {
|
||||
#[macro_export] macro_rules! skip_if_seccomp {
|
||||
($name:expr) => {
|
||||
if let Ok(s) = std::fs::read_to_string("/proc/self/status") {
|
||||
for l in s.lines() {
|
||||
let mut fields = l.split_whitespace();
|
||||
if fields.next() == Some("Seccomp:") &&
|
||||
fields.next() != Some("0")
|
||||
{
|
||||
skip!("{} cannot be run in Seccomp mode. Skipping test.",
|
||||
stringify!($name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if #[cfg(not(target_os = "redox"))] {
|
||||
#[macro_export] macro_rules! skip_if_seccomp {
|
||||
($name:expr) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_os = "linux")] {
|
||||
#[macro_export] macro_rules! require_kernel_version {
|
||||
($name:expr, $version_requirement:expr) => {
|
||||
use semver::{Version, VersionReq};
|
||||
|
||||
let version_requirement = VersionReq::parse($version_requirement)
|
||||
.expect("Bad match_version provided");
|
||||
|
||||
let uname = nix::sys::utsname::uname().unwrap();
|
||||
println!("{}", uname.sysname().to_str().unwrap());
|
||||
println!("{}", uname.nodename().to_str().unwrap());
|
||||
println!("{}", uname.release().to_str().unwrap());
|
||||
println!("{}", uname.version().to_str().unwrap());
|
||||
println!("{}", uname.machine().to_str().unwrap());
|
||||
|
||||
// Fix stuff that the semver parser can't handle
|
||||
let fixed_release = &uname.release().to_str().unwrap().to_string()
|
||||
// Fedora 33 reports version as 4.18.el8_2.x86_64 or
|
||||
// 5.18.200-fc33.x86_64. Remove the underscore.
|
||||
.replace("_", "-")
|
||||
// Cirrus-CI reports version as 4.19.112+ . Remove the +
|
||||
.replace("+", "");
|
||||
let mut version = Version::parse(fixed_release).unwrap();
|
||||
|
||||
//Keep only numeric parts
|
||||
version.pre = semver::Prerelease::EMPTY;
|
||||
version.build = semver::BuildMetadata::EMPTY;
|
||||
|
||||
if !version_requirement.matches(&version) {
|
||||
skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`",
|
||||
stringify!($name), version, version_requirement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
123
third-party/vendor/nix/test/test.rs
vendored
Normal file
123
third-party/vendor/nix/test/test.rs
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
#[macro_use]
|
||||
extern crate cfg_if;
|
||||
#[cfg_attr(not(any(target_os = "redox", target_os = "haiku")), macro_use)]
|
||||
extern crate nix;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
mod common;
|
||||
mod sys;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
mod test_dir;
|
||||
mod test_fcntl;
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
mod test_kmod;
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "fushsia",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd"
|
||||
))]
|
||||
mod test_mq;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
mod test_net;
|
||||
mod test_nix_path;
|
||||
#[cfg(target_os = "freebsd")]
|
||||
mod test_nmount;
|
||||
mod test_poll;
|
||||
#[cfg(not(any(
|
||||
target_os = "redox",
|
||||
target_os = "fuchsia",
|
||||
target_os = "haiku"
|
||||
)))]
|
||||
mod test_pty;
|
||||
mod test_resource;
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "linux"
|
||||
))]
|
||||
mod test_sched;
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos"
|
||||
))]
|
||||
mod test_sendfile;
|
||||
mod test_stat;
|
||||
mod test_time;
|
||||
#[cfg(all(
|
||||
any(
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd"
|
||||
),
|
||||
feature = "time",
|
||||
feature = "signal"
|
||||
))]
|
||||
mod test_timer;
|
||||
mod test_unistd;
|
||||
|
||||
use nix::unistd::{chdir, getcwd, read};
|
||||
use parking_lot::{Mutex, RwLock, RwLockWriteGuard};
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s
|
||||
fn read_exact(f: RawFd, buf: &mut [u8]) {
|
||||
let mut len = 0;
|
||||
while len < buf.len() {
|
||||
// get_mut would be better than split_at_mut, but it requires nightly
|
||||
let (_, remaining) = buf.split_at_mut(len);
|
||||
len += read(f, remaining).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Any test that changes the process's current working directory must grab
|
||||
/// the RwLock exclusively. Any process that cares about the current
|
||||
/// working directory must grab it shared.
|
||||
pub static ref CWD_LOCK: RwLock<()> = RwLock::new(());
|
||||
/// Any test that creates child processes must grab this mutex, regardless
|
||||
/// of what it does with those children.
|
||||
pub static ref FORK_MTX: Mutex<()> = Mutex::new(());
|
||||
/// Any test that changes the process's supplementary groups must grab this
|
||||
/// mutex
|
||||
pub static ref GROUPS_MTX: Mutex<()> = Mutex::new(());
|
||||
/// Any tests that loads or unloads kernel modules must grab this mutex
|
||||
pub static ref KMOD_MTX: Mutex<()> = Mutex::new(());
|
||||
/// Any test that calls ptsname(3) must grab this mutex.
|
||||
pub static ref PTSNAME_MTX: Mutex<()> = Mutex::new(());
|
||||
/// Any test that alters signal handling must grab this mutex.
|
||||
pub static ref SIGNAL_MTX: Mutex<()> = Mutex::new(());
|
||||
}
|
||||
|
||||
/// RAII object that restores a test's original directory on drop
|
||||
struct DirRestore<'a> {
|
||||
d: PathBuf,
|
||||
_g: RwLockWriteGuard<'a, ()>,
|
||||
}
|
||||
|
||||
impl<'a> DirRestore<'a> {
|
||||
fn new() -> Self {
|
||||
let guard = crate::CWD_LOCK.write();
|
||||
DirRestore {
|
||||
_g: guard,
|
||||
d: getcwd().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for DirRestore<'a> {
|
||||
fn drop(&mut self) {
|
||||
let r = chdir(&self.d);
|
||||
if std::thread::panicking() {
|
||||
r.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
9
third-party/vendor/nix/test/test_clearenv.rs
vendored
Normal file
9
third-party/vendor/nix/test/test_clearenv.rs
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
use std::env;
|
||||
|
||||
#[test]
|
||||
fn clearenv() {
|
||||
env::set_var("FOO", "BAR");
|
||||
unsafe { nix::env::clearenv() }.unwrap();
|
||||
assert_eq!(env::var("FOO").unwrap_err(), env::VarError::NotPresent);
|
||||
assert_eq!(env::vars().count(), 0);
|
||||
}
|
||||
65
third-party/vendor/nix/test/test_dir.rs
vendored
Normal file
65
third-party/vendor/nix/test/test_dir.rs
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
use nix::dir::{Dir, Type};
|
||||
use nix::fcntl::OFlag;
|
||||
use nix::sys::stat::Mode;
|
||||
use std::fs::File;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[cfg(test)]
|
||||
fn flags() -> OFlag {
|
||||
#[cfg(target_os = "illumos")]
|
||||
let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC;
|
||||
|
||||
#[cfg(not(target_os = "illumos"))]
|
||||
let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC | OFlag::O_DIRECTORY;
|
||||
|
||||
f
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::unnecessary_sort_by)] // False positive
|
||||
fn read() {
|
||||
let tmp = tempdir().unwrap();
|
||||
File::create(tmp.path().join("foo")).unwrap();
|
||||
std::os::unix::fs::symlink("foo", tmp.path().join("bar")).unwrap();
|
||||
let mut dir = Dir::open(tmp.path(), flags(), Mode::empty()).unwrap();
|
||||
let mut entries: Vec<_> = dir.iter().map(|e| e.unwrap()).collect();
|
||||
entries.sort_by(|a, b| a.file_name().cmp(b.file_name()));
|
||||
let entry_names: Vec<_> = entries
|
||||
.iter()
|
||||
.map(|e| e.file_name().to_str().unwrap().to_owned())
|
||||
.collect();
|
||||
assert_eq!(&entry_names[..], &[".", "..", "bar", "foo"]);
|
||||
|
||||
// Check file types. The system is allowed to return DT_UNKNOWN (aka None here) but if it does
|
||||
// return a type, ensure it's correct.
|
||||
assert!(&[Some(Type::Directory), None].contains(&entries[0].file_type())); // .: dir
|
||||
assert!(&[Some(Type::Directory), None].contains(&entries[1].file_type())); // ..: dir
|
||||
assert!(&[Some(Type::Symlink), None].contains(&entries[2].file_type())); // bar: symlink
|
||||
assert!(&[Some(Type::File), None].contains(&entries[3].file_type())); // foo: regular file
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rewind() {
|
||||
let tmp = tempdir().unwrap();
|
||||
let mut dir = Dir::open(tmp.path(), flags(), Mode::empty()).unwrap();
|
||||
let entries1: Vec<_> = dir
|
||||
.iter()
|
||||
.map(|e| e.unwrap().file_name().to_owned())
|
||||
.collect();
|
||||
let entries2: Vec<_> = dir
|
||||
.iter()
|
||||
.map(|e| e.unwrap().file_name().to_owned())
|
||||
.collect();
|
||||
let entries3: Vec<_> = dir
|
||||
.into_iter()
|
||||
.map(|e| e.unwrap().file_name().to_owned())
|
||||
.collect();
|
||||
assert_eq!(entries1, entries2);
|
||||
assert_eq!(entries2, entries3);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "haiku"))]
|
||||
#[test]
|
||||
fn ebadf() {
|
||||
assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::EBADF);
|
||||
}
|
||||
565
third-party/vendor/nix/test/test_fcntl.rs
vendored
Normal file
565
third-party/vendor/nix/test/test_fcntl.rs
vendored
Normal file
|
|
@ -0,0 +1,565 @@
|
|||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::errno::*;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::fcntl::{open, readlink, OFlag};
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::fcntl::{openat, readlinkat, renameat};
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
target_env = "gnu",
|
||||
any(
|
||||
target_arch = "x86_64",
|
||||
target_arch = "x32",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "s390x"
|
||||
)
|
||||
))]
|
||||
use nix::fcntl::{renameat2, RenameFlags};
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::sys::stat::Mode;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::unistd::{close, read};
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use std::fs::File;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use std::io::prelude::*;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use std::os::unix::fs;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use tempfile::{self, NamedTempFile};
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
// QEMU does not handle openat well enough to satisfy this test
|
||||
// https://gitlab.com/qemu-project/qemu/-/issues/829
|
||||
#[cfg_attr(qemu, ignore)]
|
||||
fn test_openat() {
|
||||
const CONTENTS: &[u8] = b"abcd";
|
||||
let mut tmp = NamedTempFile::new().unwrap();
|
||||
tmp.write_all(CONTENTS).unwrap();
|
||||
|
||||
let dirfd =
|
||||
open(tmp.path().parent().unwrap(), OFlag::empty(), Mode::empty())
|
||||
.unwrap();
|
||||
let fd = openat(
|
||||
dirfd,
|
||||
tmp.path().file_name().unwrap(),
|
||||
OFlag::O_RDONLY,
|
||||
Mode::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut buf = [0u8; 1024];
|
||||
assert_eq!(4, read(fd, &mut buf).unwrap());
|
||||
assert_eq!(CONTENTS, &buf[0..4]);
|
||||
|
||||
close(fd).unwrap();
|
||||
close(dirfd).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_renameat() {
|
||||
let old_dir = tempfile::tempdir().unwrap();
|
||||
let old_dirfd =
|
||||
open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
|
||||
let old_path = old_dir.path().join("old");
|
||||
File::create(old_path).unwrap();
|
||||
let new_dir = tempfile::tempdir().unwrap();
|
||||
let new_dirfd =
|
||||
open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
|
||||
renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap();
|
||||
assert_eq!(
|
||||
renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(),
|
||||
Errno::ENOENT
|
||||
);
|
||||
close(old_dirfd).unwrap();
|
||||
close(new_dirfd).unwrap();
|
||||
assert!(new_dir.path().join("new").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
target_env = "gnu",
|
||||
any(
|
||||
target_arch = "x86_64",
|
||||
target_arch = "x32",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "s390x"
|
||||
)
|
||||
))]
|
||||
fn test_renameat2_behaves_like_renameat_with_no_flags() {
|
||||
let old_dir = tempfile::tempdir().unwrap();
|
||||
let old_dirfd =
|
||||
open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
|
||||
let old_path = old_dir.path().join("old");
|
||||
File::create(old_path).unwrap();
|
||||
let new_dir = tempfile::tempdir().unwrap();
|
||||
let new_dirfd =
|
||||
open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
|
||||
renameat2(
|
||||
Some(old_dirfd),
|
||||
"old",
|
||||
Some(new_dirfd),
|
||||
"new",
|
||||
RenameFlags::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
renameat2(
|
||||
Some(old_dirfd),
|
||||
"old",
|
||||
Some(new_dirfd),
|
||||
"new",
|
||||
RenameFlags::empty()
|
||||
)
|
||||
.unwrap_err(),
|
||||
Errno::ENOENT
|
||||
);
|
||||
close(old_dirfd).unwrap();
|
||||
close(new_dirfd).unwrap();
|
||||
assert!(new_dir.path().join("new").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
target_env = "gnu",
|
||||
any(
|
||||
target_arch = "x86_64",
|
||||
target_arch = "x32",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "s390x"
|
||||
)
|
||||
))]
|
||||
fn test_renameat2_exchange() {
|
||||
let old_dir = tempfile::tempdir().unwrap();
|
||||
let old_dirfd =
|
||||
open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
|
||||
let old_path = old_dir.path().join("old");
|
||||
{
|
||||
let mut old_f = File::create(&old_path).unwrap();
|
||||
old_f.write_all(b"old").unwrap();
|
||||
}
|
||||
let new_dir = tempfile::tempdir().unwrap();
|
||||
let new_dirfd =
|
||||
open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
|
||||
let new_path = new_dir.path().join("new");
|
||||
{
|
||||
let mut new_f = File::create(&new_path).unwrap();
|
||||
new_f.write_all(b"new").unwrap();
|
||||
}
|
||||
renameat2(
|
||||
Some(old_dirfd),
|
||||
"old",
|
||||
Some(new_dirfd),
|
||||
"new",
|
||||
RenameFlags::RENAME_EXCHANGE,
|
||||
)
|
||||
.unwrap();
|
||||
let mut buf = String::new();
|
||||
let mut new_f = File::open(&new_path).unwrap();
|
||||
new_f.read_to_string(&mut buf).unwrap();
|
||||
assert_eq!(buf, "old");
|
||||
buf = "".to_string();
|
||||
let mut old_f = File::open(&old_path).unwrap();
|
||||
old_f.read_to_string(&mut buf).unwrap();
|
||||
assert_eq!(buf, "new");
|
||||
close(old_dirfd).unwrap();
|
||||
close(new_dirfd).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
target_env = "gnu",
|
||||
any(
|
||||
target_arch = "x86_64",
|
||||
target_arch = "x32",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "s390x"
|
||||
)
|
||||
))]
|
||||
fn test_renameat2_noreplace() {
|
||||
let old_dir = tempfile::tempdir().unwrap();
|
||||
let old_dirfd =
|
||||
open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
|
||||
let old_path = old_dir.path().join("old");
|
||||
File::create(old_path).unwrap();
|
||||
let new_dir = tempfile::tempdir().unwrap();
|
||||
let new_dirfd =
|
||||
open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
|
||||
let new_path = new_dir.path().join("new");
|
||||
File::create(new_path).unwrap();
|
||||
assert_eq!(
|
||||
renameat2(
|
||||
Some(old_dirfd),
|
||||
"old",
|
||||
Some(new_dirfd),
|
||||
"new",
|
||||
RenameFlags::RENAME_NOREPLACE
|
||||
)
|
||||
.unwrap_err(),
|
||||
Errno::EEXIST
|
||||
);
|
||||
close(old_dirfd).unwrap();
|
||||
close(new_dirfd).unwrap();
|
||||
assert!(new_dir.path().join("new").exists());
|
||||
assert!(old_dir.path().join("old").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_readlink() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let src = tempdir.path().join("a");
|
||||
let dst = tempdir.path().join("b");
|
||||
println!("a: {:?}, b: {:?}", &src, &dst);
|
||||
fs::symlink(src.as_path(), dst.as_path()).unwrap();
|
||||
let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
|
||||
let expected_dir = src.to_str().unwrap();
|
||||
|
||||
assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir);
|
||||
assert_eq!(
|
||||
readlinkat(dirfd, "b").unwrap().to_str().unwrap(),
|
||||
expected_dir
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
mod linux_android {
|
||||
use libc::loff_t;
|
||||
use std::io::prelude::*;
|
||||
use std::io::{IoSlice, SeekFrom};
|
||||
use std::os::unix::prelude::*;
|
||||
|
||||
use nix::fcntl::*;
|
||||
use nix::unistd::{close, pipe, read, write};
|
||||
|
||||
use tempfile::tempfile;
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
use crate::*;
|
||||
|
||||
/// This test creates a temporary file containing the contents
|
||||
/// 'foobarbaz' and uses the `copy_file_range` call to transfer
|
||||
/// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The
|
||||
/// resulting file is read and should contain the contents `bar`.
|
||||
/// The from_offset should be updated by the call to reflect
|
||||
/// the 3 bytes read (6).
|
||||
#[test]
|
||||
// QEMU does not support copy_file_range. Skip under qemu
|
||||
#[cfg_attr(qemu, ignore)]
|
||||
fn test_copy_file_range() {
|
||||
const CONTENTS: &[u8] = b"foobarbaz";
|
||||
|
||||
let mut tmp1 = tempfile().unwrap();
|
||||
let mut tmp2 = tempfile().unwrap();
|
||||
|
||||
tmp1.write_all(CONTENTS).unwrap();
|
||||
tmp1.flush().unwrap();
|
||||
|
||||
let mut from_offset: i64 = 3;
|
||||
copy_file_range(
|
||||
tmp1.as_raw_fd(),
|
||||
Some(&mut from_offset),
|
||||
tmp2.as_raw_fd(),
|
||||
None,
|
||||
3,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut res: String = String::new();
|
||||
tmp2.seek(SeekFrom::Start(0)).unwrap();
|
||||
tmp2.read_to_string(&mut res).unwrap();
|
||||
|
||||
assert_eq!(res, String::from("bar"));
|
||||
assert_eq!(from_offset, 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_splice() {
|
||||
const CONTENTS: &[u8] = b"abcdef123456";
|
||||
let mut tmp = tempfile().unwrap();
|
||||
tmp.write_all(CONTENTS).unwrap();
|
||||
|
||||
let (rd, wr) = pipe().unwrap();
|
||||
let mut offset: loff_t = 5;
|
||||
let res = splice(
|
||||
tmp.as_raw_fd(),
|
||||
Some(&mut offset),
|
||||
wr,
|
||||
None,
|
||||
2,
|
||||
SpliceFFlags::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(2, res);
|
||||
|
||||
let mut buf = [0u8; 1024];
|
||||
assert_eq!(2, read(rd, &mut buf).unwrap());
|
||||
assert_eq!(b"f1", &buf[0..2]);
|
||||
assert_eq!(7, offset);
|
||||
|
||||
close(rd).unwrap();
|
||||
close(wr).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tee() {
|
||||
let (rd1, wr1) = pipe().unwrap();
|
||||
let (rd2, wr2) = pipe().unwrap();
|
||||
|
||||
write(wr1, b"abc").unwrap();
|
||||
let res = tee(rd1, wr2, 2, SpliceFFlags::empty()).unwrap();
|
||||
|
||||
assert_eq!(2, res);
|
||||
|
||||
let mut buf = [0u8; 1024];
|
||||
|
||||
// Check the tee'd bytes are at rd2.
|
||||
assert_eq!(2, read(rd2, &mut buf).unwrap());
|
||||
assert_eq!(b"ab", &buf[0..2]);
|
||||
|
||||
// Check all the bytes are still at rd1.
|
||||
assert_eq!(3, read(rd1, &mut buf).unwrap());
|
||||
assert_eq!(b"abc", &buf[0..3]);
|
||||
|
||||
close(rd1).unwrap();
|
||||
close(wr1).unwrap();
|
||||
close(rd2).unwrap();
|
||||
close(wr2).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vmsplice() {
|
||||
let (rd, wr) = pipe().unwrap();
|
||||
|
||||
let buf1 = b"abcdef";
|
||||
let buf2 = b"defghi";
|
||||
let iovecs = vec![IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])];
|
||||
|
||||
let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap();
|
||||
|
||||
assert_eq!(6, res);
|
||||
|
||||
// Check the bytes can be read at rd.
|
||||
let mut buf = [0u8; 32];
|
||||
assert_eq!(6, read(rd, &mut buf).unwrap());
|
||||
assert_eq!(b"abcdef", &buf[0..6]);
|
||||
|
||||
close(rd).unwrap();
|
||||
close(wr).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_fallocate() {
|
||||
let tmp = NamedTempFile::new().unwrap();
|
||||
|
||||
let fd = tmp.as_raw_fd();
|
||||
fallocate(fd, FallocateFlags::empty(), 0, 100).unwrap();
|
||||
|
||||
// Check if we read exactly 100 bytes
|
||||
let mut buf = [0u8; 200];
|
||||
assert_eq!(100, read(fd, &mut buf).unwrap());
|
||||
}
|
||||
|
||||
// The tests below are disabled for the listed targets
|
||||
// due to OFD locks not being available in the kernel/libc
|
||||
// versions used in the CI environment, probably because
|
||||
// they run under QEMU.
|
||||
|
||||
#[test]
|
||||
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
|
||||
#[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile
|
||||
fn test_ofd_write_lock() {
|
||||
use nix::sys::stat::fstat;
|
||||
use std::mem;
|
||||
|
||||
let tmp = NamedTempFile::new().unwrap();
|
||||
|
||||
let fd = tmp.as_raw_fd();
|
||||
let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap();
|
||||
if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC {
|
||||
// OverlayFS is a union file system. It returns one inode value in
|
||||
// stat(2), but a different one shows up in /proc/locks. So we must
|
||||
// skip the test.
|
||||
skip!("/proc/locks does not work on overlayfs");
|
||||
}
|
||||
let inode = fstat(fd).expect("fstat failed").st_ino as usize;
|
||||
|
||||
let mut flock: libc::flock = unsafe {
|
||||
mem::zeroed() // required for Linux/mips
|
||||
};
|
||||
flock.l_type = libc::F_WRLCK as libc::c_short;
|
||||
flock.l_whence = libc::SEEK_SET as libc::c_short;
|
||||
flock.l_start = 0;
|
||||
flock.l_len = 0;
|
||||
flock.l_pid = 0;
|
||||
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write lock failed");
|
||||
assert_eq!(
|
||||
Some(("OFDLCK".to_string(), "WRITE".to_string())),
|
||||
lock_info(inode)
|
||||
);
|
||||
|
||||
flock.l_type = libc::F_UNLCK as libc::c_short;
|
||||
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write unlock failed");
|
||||
assert_eq!(None, lock_info(inode));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
|
||||
#[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile
|
||||
fn test_ofd_read_lock() {
|
||||
use nix::sys::stat::fstat;
|
||||
use std::mem;
|
||||
|
||||
let tmp = NamedTempFile::new().unwrap();
|
||||
|
||||
let fd = tmp.as_raw_fd();
|
||||
let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap();
|
||||
if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC {
|
||||
// OverlayFS is a union file system. It returns one inode value in
|
||||
// stat(2), but a different one shows up in /proc/locks. So we must
|
||||
// skip the test.
|
||||
skip!("/proc/locks does not work on overlayfs");
|
||||
}
|
||||
let inode = fstat(fd).expect("fstat failed").st_ino as usize;
|
||||
|
||||
let mut flock: libc::flock = unsafe {
|
||||
mem::zeroed() // required for Linux/mips
|
||||
};
|
||||
flock.l_type = libc::F_RDLCK as libc::c_short;
|
||||
flock.l_whence = libc::SEEK_SET as libc::c_short;
|
||||
flock.l_start = 0;
|
||||
flock.l_len = 0;
|
||||
flock.l_pid = 0;
|
||||
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read lock failed");
|
||||
assert_eq!(
|
||||
Some(("OFDLCK".to_string(), "READ".to_string())),
|
||||
lock_info(inode)
|
||||
);
|
||||
|
||||
flock.l_type = libc::F_UNLCK as libc::c_short;
|
||||
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read unlock failed");
|
||||
assert_eq!(None, lock_info(inode));
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
|
||||
fn lock_info(inode: usize) -> Option<(String, String)> {
|
||||
use std::{fs::File, io::BufReader};
|
||||
|
||||
let file = File::open("/proc/locks").expect("open /proc/locks failed");
|
||||
let buf = BufReader::new(file);
|
||||
|
||||
for line in buf.lines() {
|
||||
let line = line.unwrap();
|
||||
let parts: Vec<_> = line.split_whitespace().collect();
|
||||
let lock_type = parts[1];
|
||||
let lock_access = parts[3];
|
||||
let ino_parts: Vec<_> = parts[5].split(':').collect();
|
||||
let ino: usize = ino_parts[2].parse().unwrap();
|
||||
if ino == inode {
|
||||
return Some((lock_type.to_string(), lock_access.to_string()));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "wasi",
|
||||
target_env = "uclibc",
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
mod test_posix_fadvise {
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::fcntl::*;
|
||||
use nix::unistd::pipe;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
#[test]
|
||||
fn test_success() {
|
||||
let tmp = NamedTempFile::new().unwrap();
|
||||
let fd = tmp.as_raw_fd();
|
||||
posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED)
|
||||
.expect("posix_fadvise failed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_errno() {
|
||||
let (rd, _wr) = pipe().unwrap();
|
||||
let res = posix_fadvise(
|
||||
rd as RawFd,
|
||||
0,
|
||||
100,
|
||||
PosixFadviseAdvice::POSIX_FADV_WILLNEED,
|
||||
);
|
||||
assert_eq!(res, Err(Errno::ESPIPE));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "wasi",
|
||||
target_os = "freebsd"
|
||||
))]
|
||||
mod test_posix_fallocate {
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::fcntl::*;
|
||||
use nix::unistd::pipe;
|
||||
use std::{
|
||||
io::Read,
|
||||
os::unix::io::{AsRawFd, RawFd},
|
||||
};
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
#[test]
|
||||
fn success() {
|
||||
const LEN: usize = 100;
|
||||
let mut tmp = NamedTempFile::new().unwrap();
|
||||
let fd = tmp.as_raw_fd();
|
||||
let res = posix_fallocate(fd, 0, LEN as libc::off_t);
|
||||
match res {
|
||||
Ok(_) => {
|
||||
let mut data = [1u8; LEN];
|
||||
assert_eq!(tmp.read(&mut data).expect("read failure"), LEN);
|
||||
assert_eq!(&data[..], &[0u8; LEN][..]);
|
||||
}
|
||||
Err(Errno::EINVAL) => {
|
||||
// POSIX requires posix_fallocate to return EINVAL both for
|
||||
// invalid arguments (i.e. len < 0) and if the operation is not
|
||||
// supported by the file system.
|
||||
// There's no way to tell for sure whether the file system
|
||||
// supports posix_fallocate, so we must pass the test if it
|
||||
// returns EINVAL.
|
||||
}
|
||||
_ => res.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn errno() {
|
||||
let (rd, _wr) = pipe().unwrap();
|
||||
let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err();
|
||||
match err {
|
||||
Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (),
|
||||
errno => panic!("unexpected errno {}", errno,),
|
||||
}
|
||||
}
|
||||
}
|
||||
7
third-party/vendor/nix/test/test_kmod/hello_mod/Makefile
vendored
Normal file
7
third-party/vendor/nix/test/test_kmod/hello_mod/Makefile
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
obj-m += hello.o
|
||||
|
||||
all:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
|
||||
|
||||
clean:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
|
||||
26
third-party/vendor/nix/test/test_kmod/hello_mod/hello.c
vendored
Normal file
26
third-party/vendor/nix/test/test_kmod/hello_mod/hello.c
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0+ or MIT
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
static int number= 1;
|
||||
static char *who = "World";
|
||||
|
||||
module_param(number, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
MODULE_PARM_DESC(myint, "Just some number");
|
||||
module_param(who, charp, 0000);
|
||||
MODULE_PARM_DESC(who, "Whot to greet");
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
printk(KERN_INFO "Hello %s (%d)!\n", who, number);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_module(void)
|
||||
{
|
||||
printk(KERN_INFO "Goodbye %s (%d)!\n", who, number);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
188
third-party/vendor/nix/test/test_kmod/mod.rs
vendored
Normal file
188
third-party/vendor/nix/test/test_kmod/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
use crate::*;
|
||||
use std::fs::copy;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use tempfile::{tempdir, TempDir};
|
||||
|
||||
fn compile_kernel_module() -> (PathBuf, String, TempDir) {
|
||||
let _m = crate::FORK_MTX.lock();
|
||||
|
||||
let tmp_dir =
|
||||
tempdir().expect("unable to create temporary build directory");
|
||||
|
||||
copy(
|
||||
"test/test_kmod/hello_mod/hello.c",
|
||||
tmp_dir.path().join("hello.c"),
|
||||
)
|
||||
.expect("unable to copy hello.c to temporary build directory");
|
||||
copy(
|
||||
"test/test_kmod/hello_mod/Makefile",
|
||||
tmp_dir.path().join("Makefile"),
|
||||
)
|
||||
.expect("unable to copy Makefile to temporary build directory");
|
||||
|
||||
let status = Command::new("make")
|
||||
.current_dir(tmp_dir.path())
|
||||
.status()
|
||||
.expect("failed to run make");
|
||||
|
||||
assert!(status.success());
|
||||
|
||||
// Return the relative path of the build kernel module
|
||||
(tmp_dir.path().join("hello.ko"), "hello".to_owned(), tmp_dir)
|
||||
}
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::kmod::{delete_module, DeleteModuleFlags};
|
||||
use nix::kmod::{finit_module, init_module, ModuleInitFlags};
|
||||
use std::ffi::CString;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
#[test]
|
||||
fn test_finit_and_delete_module() {
|
||||
require_capability!("test_finit_and_delete_module", CAP_SYS_MODULE);
|
||||
let _m0 = crate::KMOD_MTX.lock();
|
||||
let _m1 = crate::CWD_LOCK.read();
|
||||
|
||||
let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
|
||||
|
||||
let f = File::open(kmod_path).expect("unable to open kernel module");
|
||||
finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty())
|
||||
.expect("unable to load kernel module");
|
||||
|
||||
delete_module(
|
||||
&CString::new(kmod_name).unwrap(),
|
||||
DeleteModuleFlags::empty(),
|
||||
)
|
||||
.expect("unable to unload kernel module");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_finit_and_delete_module_with_params() {
|
||||
require_capability!(
|
||||
"test_finit_and_delete_module_with_params",
|
||||
CAP_SYS_MODULE
|
||||
);
|
||||
let _m0 = crate::KMOD_MTX.lock();
|
||||
let _m1 = crate::CWD_LOCK.read();
|
||||
|
||||
let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
|
||||
|
||||
let f = File::open(kmod_path).expect("unable to open kernel module");
|
||||
finit_module(
|
||||
&f,
|
||||
&CString::new("who=Rust number=2018").unwrap(),
|
||||
ModuleInitFlags::empty(),
|
||||
)
|
||||
.expect("unable to load kernel module");
|
||||
|
||||
delete_module(
|
||||
&CString::new(kmod_name).unwrap(),
|
||||
DeleteModuleFlags::empty(),
|
||||
)
|
||||
.expect("unable to unload kernel module");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_init_and_delete_module() {
|
||||
require_capability!("test_init_and_delete_module", CAP_SYS_MODULE);
|
||||
let _m0 = crate::KMOD_MTX.lock();
|
||||
let _m1 = crate::CWD_LOCK.read();
|
||||
|
||||
let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
|
||||
|
||||
let mut f = File::open(kmod_path).expect("unable to open kernel module");
|
||||
let mut contents: Vec<u8> = Vec::new();
|
||||
f.read_to_end(&mut contents)
|
||||
.expect("unable to read kernel module content to buffer");
|
||||
init_module(&contents, &CString::new("").unwrap())
|
||||
.expect("unable to load kernel module");
|
||||
|
||||
delete_module(
|
||||
&CString::new(kmod_name).unwrap(),
|
||||
DeleteModuleFlags::empty(),
|
||||
)
|
||||
.expect("unable to unload kernel module");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_init_and_delete_module_with_params() {
|
||||
require_capability!(
|
||||
"test_init_and_delete_module_with_params",
|
||||
CAP_SYS_MODULE
|
||||
);
|
||||
let _m0 = crate::KMOD_MTX.lock();
|
||||
let _m1 = crate::CWD_LOCK.read();
|
||||
|
||||
let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
|
||||
|
||||
let mut f = File::open(kmod_path).expect("unable to open kernel module");
|
||||
let mut contents: Vec<u8> = Vec::new();
|
||||
f.read_to_end(&mut contents)
|
||||
.expect("unable to read kernel module content to buffer");
|
||||
init_module(&contents, &CString::new("who=Nix number=2015").unwrap())
|
||||
.expect("unable to load kernel module");
|
||||
|
||||
delete_module(
|
||||
&CString::new(kmod_name).unwrap(),
|
||||
DeleteModuleFlags::empty(),
|
||||
)
|
||||
.expect("unable to unload kernel module");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_finit_module_invalid() {
|
||||
require_capability!("test_finit_module_invalid", CAP_SYS_MODULE);
|
||||
let _m0 = crate::KMOD_MTX.lock();
|
||||
let _m1 = crate::CWD_LOCK.read();
|
||||
|
||||
let kmod_path = "/dev/zero";
|
||||
|
||||
let f = File::open(kmod_path).expect("unable to open kernel module");
|
||||
let result =
|
||||
finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
|
||||
|
||||
assert_eq!(result.unwrap_err(), Errno::EINVAL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_finit_module_twice_and_delete_module() {
|
||||
require_capability!(
|
||||
"test_finit_module_twice_and_delete_module",
|
||||
CAP_SYS_MODULE
|
||||
);
|
||||
let _m0 = crate::KMOD_MTX.lock();
|
||||
let _m1 = crate::CWD_LOCK.read();
|
||||
|
||||
let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
|
||||
|
||||
let f = File::open(kmod_path).expect("unable to open kernel module");
|
||||
finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty())
|
||||
.expect("unable to load kernel module");
|
||||
|
||||
let result =
|
||||
finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
|
||||
|
||||
assert_eq!(result.unwrap_err(), Errno::EEXIST);
|
||||
|
||||
delete_module(
|
||||
&CString::new(kmod_name).unwrap(),
|
||||
DeleteModuleFlags::empty(),
|
||||
)
|
||||
.expect("unable to unload kernel module");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_module_not_loaded() {
|
||||
require_capability!("test_delete_module_not_loaded", CAP_SYS_MODULE);
|
||||
let _m0 = crate::KMOD_MTX.lock();
|
||||
let _m1 = crate::CWD_LOCK.read();
|
||||
|
||||
let result = delete_module(
|
||||
&CString::new("hello").unwrap(),
|
||||
DeleteModuleFlags::empty(),
|
||||
);
|
||||
|
||||
assert_eq!(result.unwrap_err(), Errno::ENOENT);
|
||||
}
|
||||
271
third-party/vendor/nix/test/test_mount.rs
vendored
Normal file
271
third-party/vendor/nix/test/test_mount.rs
vendored
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
mod common;
|
||||
|
||||
// Implementation note: to allow unprivileged users to run it, this test makes
|
||||
// use of user and mount namespaces. On systems that allow unprivileged user
|
||||
// namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run
|
||||
// without root.
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod test_mount {
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::process::{self, Command};
|
||||
|
||||
use libc::{EACCES, EROFS};
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::mount::{mount, umount, MsFlags};
|
||||
use nix::sched::{unshare, CloneFlags};
|
||||
use nix::sys::stat::{self, Mode};
|
||||
use nix::unistd::getuid;
|
||||
|
||||
static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh
|
||||
exit 23";
|
||||
|
||||
const EXPECTED_STATUS: i32 = 23;
|
||||
|
||||
const NONE: Option<&'static [u8]> = None;
|
||||
#[allow(clippy::bind_instead_of_map)] // False positive
|
||||
pub fn test_mount_tmpfs_without_flags_allows_rwx() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
|
||||
mount(
|
||||
NONE,
|
||||
tempdir.path(),
|
||||
Some(b"tmpfs".as_ref()),
|
||||
MsFlags::empty(),
|
||||
NONE,
|
||||
)
|
||||
.unwrap_or_else(|e| panic!("mount failed: {}", e));
|
||||
|
||||
let test_path = tempdir.path().join("test");
|
||||
|
||||
// Verify write.
|
||||
fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
|
||||
.open(&test_path)
|
||||
.or_else(|e| {
|
||||
if Errno::from_i32(e.raw_os_error().unwrap())
|
||||
== Errno::EOVERFLOW
|
||||
{
|
||||
// Skip tests on certain Linux kernels which have a bug
|
||||
// regarding tmpfs in namespaces.
|
||||
// Ubuntu 14.04 and 16.04 are known to be affected; 16.10 is
|
||||
// not. There is no legitimate reason for open(2) to return
|
||||
// EOVERFLOW here.
|
||||
// https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1659087
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
writeln!(
|
||||
handle,
|
||||
"Buggy Linux kernel detected. Skipping test."
|
||||
)
|
||||
.unwrap();
|
||||
process::exit(0);
|
||||
} else {
|
||||
panic!("open failed: {}", e);
|
||||
}
|
||||
})
|
||||
.and_then(|mut f| f.write(SCRIPT_CONTENTS))
|
||||
.unwrap_or_else(|e| panic!("write failed: {}", e));
|
||||
|
||||
// Verify read.
|
||||
let mut buf = Vec::new();
|
||||
File::open(&test_path)
|
||||
.and_then(|mut f| f.read_to_end(&mut buf))
|
||||
.unwrap_or_else(|e| panic!("read failed: {}", e));
|
||||
assert_eq!(buf, SCRIPT_CONTENTS);
|
||||
|
||||
// Verify execute.
|
||||
assert_eq!(
|
||||
EXPECTED_STATUS,
|
||||
Command::new(&test_path)
|
||||
.status()
|
||||
.unwrap_or_else(|e| panic!("exec failed: {}", e))
|
||||
.code()
|
||||
.unwrap_or_else(|| panic!("child killed by signal"))
|
||||
);
|
||||
|
||||
umount(tempdir.path())
|
||||
.unwrap_or_else(|e| panic!("umount failed: {}", e));
|
||||
}
|
||||
|
||||
pub fn test_mount_rdonly_disallows_write() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
|
||||
mount(
|
||||
NONE,
|
||||
tempdir.path(),
|
||||
Some(b"tmpfs".as_ref()),
|
||||
MsFlags::MS_RDONLY,
|
||||
NONE,
|
||||
)
|
||||
.unwrap_or_else(|e| panic!("mount failed: {}", e));
|
||||
|
||||
// EROFS: Read-only file system
|
||||
assert_eq!(
|
||||
EROFS,
|
||||
File::create(tempdir.path().join("test"))
|
||||
.unwrap_err()
|
||||
.raw_os_error()
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
umount(tempdir.path())
|
||||
.unwrap_or_else(|e| panic!("umount failed: {}", e));
|
||||
}
|
||||
|
||||
pub fn test_mount_noexec_disallows_exec() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
|
||||
mount(
|
||||
NONE,
|
||||
tempdir.path(),
|
||||
Some(b"tmpfs".as_ref()),
|
||||
MsFlags::MS_NOEXEC,
|
||||
NONE,
|
||||
)
|
||||
.unwrap_or_else(|e| panic!("mount failed: {}", e));
|
||||
|
||||
let test_path = tempdir.path().join("test");
|
||||
|
||||
fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
|
||||
.open(&test_path)
|
||||
.and_then(|mut f| f.write(SCRIPT_CONTENTS))
|
||||
.unwrap_or_else(|e| panic!("write failed: {}", e));
|
||||
|
||||
// Verify that we cannot execute despite a+x permissions being set.
|
||||
let mode = stat::Mode::from_bits_truncate(
|
||||
fs::metadata(&test_path)
|
||||
.map(|md| md.permissions().mode())
|
||||
.unwrap_or_else(|e| panic!("metadata failed: {}", e)),
|
||||
);
|
||||
|
||||
assert!(
|
||||
mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH),
|
||||
"{:?} did not have execute permissions",
|
||||
&test_path
|
||||
);
|
||||
|
||||
// EACCES: Permission denied
|
||||
assert_eq!(
|
||||
EACCES,
|
||||
Command::new(&test_path)
|
||||
.status()
|
||||
.unwrap_err()
|
||||
.raw_os_error()
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
umount(tempdir.path())
|
||||
.unwrap_or_else(|e| panic!("umount failed: {}", e));
|
||||
}
|
||||
|
||||
pub fn test_mount_bind() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let file_name = "test";
|
||||
|
||||
{
|
||||
let mount_point = tempfile::tempdir().unwrap();
|
||||
|
||||
mount(
|
||||
Some(tempdir.path()),
|
||||
mount_point.path(),
|
||||
NONE,
|
||||
MsFlags::MS_BIND,
|
||||
NONE,
|
||||
)
|
||||
.unwrap_or_else(|e| panic!("mount failed: {}", e));
|
||||
|
||||
fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
|
||||
.open(mount_point.path().join(file_name))
|
||||
.and_then(|mut f| f.write(SCRIPT_CONTENTS))
|
||||
.unwrap_or_else(|e| panic!("write failed: {}", e));
|
||||
|
||||
umount(mount_point.path())
|
||||
.unwrap_or_else(|e| panic!("umount failed: {}", e));
|
||||
}
|
||||
|
||||
// Verify the file written in the mount shows up in source directory, even
|
||||
// after unmounting.
|
||||
|
||||
let mut buf = Vec::new();
|
||||
File::open(tempdir.path().join(file_name))
|
||||
.and_then(|mut f| f.read_to_end(&mut buf))
|
||||
.unwrap_or_else(|e| panic!("read failed: {}", e));
|
||||
assert_eq!(buf, SCRIPT_CONTENTS);
|
||||
}
|
||||
|
||||
pub fn setup_namespaces() {
|
||||
// Hold on to the uid in the parent namespace.
|
||||
let uid = getuid();
|
||||
|
||||
unshare(CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_NEWUSER).unwrap_or_else(|e| {
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
writeln!(handle,
|
||||
"unshare failed: {}. Are unprivileged user namespaces available?",
|
||||
e).unwrap();
|
||||
writeln!(handle, "mount is not being tested").unwrap();
|
||||
// Exit with success because not all systems support unprivileged user namespaces, and
|
||||
// that's not what we're testing for.
|
||||
process::exit(0);
|
||||
});
|
||||
|
||||
// Map user as uid 1000.
|
||||
fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.open("/proc/self/uid_map")
|
||||
.and_then(|mut f| f.write(format!("1000 {} 1\n", uid).as_bytes()))
|
||||
.unwrap_or_else(|e| panic!("could not write uid map: {}", e));
|
||||
}
|
||||
}
|
||||
|
||||
// Test runner
|
||||
|
||||
/// Mimic normal test output (hackishly).
|
||||
#[cfg(target_os = "linux")]
|
||||
macro_rules! run_tests {
|
||||
( $($test_fn:ident),* ) => {{
|
||||
println!();
|
||||
|
||||
$(
|
||||
print!("test test_mount::{} ... ", stringify!($test_fn));
|
||||
$test_fn();
|
||||
println!("ok");
|
||||
)*
|
||||
|
||||
println!();
|
||||
}}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn main() {
|
||||
use test_mount::{
|
||||
setup_namespaces, test_mount_bind, test_mount_noexec_disallows_exec,
|
||||
test_mount_rdonly_disallows_write,
|
||||
test_mount_tmpfs_without_flags_allows_rwx,
|
||||
};
|
||||
skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1351");
|
||||
setup_namespaces();
|
||||
|
||||
run_tests!(
|
||||
test_mount_tmpfs_without_flags_allows_rwx,
|
||||
test_mount_rdonly_disallows_write,
|
||||
test_mount_noexec_disallows_exec,
|
||||
test_mount_bind
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn main() {}
|
||||
190
third-party/vendor/nix/test/test_mq.rs
vendored
Normal file
190
third-party/vendor/nix/test/test_mq.rs
vendored
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
use cfg_if::cfg_if;
|
||||
use std::ffi::CString;
|
||||
use std::str;
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::mqueue::{mq_attr_member_t, mq_close, mq_open, mq_receive, mq_send};
|
||||
use nix::mqueue::{MQ_OFlag, MqAttr};
|
||||
use nix::sys::stat::Mode;
|
||||
|
||||
// Defined as a macro such that the error source is reported as the caller's location.
|
||||
macro_rules! assert_attr_eq {
|
||||
($read_attr:ident, $initial_attr:ident) => {
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "dragonfly", target_os = "netbsd"))] {
|
||||
// NetBSD (and others which inherit its implementation) include other flags
|
||||
// in read_attr, such as those specified by oflag. Just make sure at least
|
||||
// the correct bits are set.
|
||||
assert_eq!($read_attr.flags() & $initial_attr.flags(), $initial_attr.flags());
|
||||
assert_eq!($read_attr.maxmsg(), $initial_attr.maxmsg());
|
||||
assert_eq!($read_attr.msgsize(), $initial_attr.msgsize());
|
||||
assert_eq!($read_attr.curmsgs(), $initial_attr.curmsgs());
|
||||
} else {
|
||||
assert_eq!($read_attr, $initial_attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_send_and_receive() {
|
||||
const MSG_SIZE: mq_attr_member_t = 32;
|
||||
let attr = MqAttr::new(0, 10, MSG_SIZE, 0);
|
||||
let mq_name = &CString::new(b"/a_nix_test_queue".as_ref()).unwrap();
|
||||
|
||||
let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
|
||||
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
|
||||
let r0 = mq_open(mq_name, oflag0, mode, Some(&attr));
|
||||
if let Err(Errno::ENOSYS) = r0 {
|
||||
println!("message queues not supported or module not loaded?");
|
||||
return;
|
||||
};
|
||||
let mqd0 = r0.unwrap();
|
||||
let msg_to_send = "msg_1";
|
||||
mq_send(&mqd0, msg_to_send.as_bytes(), 1).unwrap();
|
||||
|
||||
let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY;
|
||||
let mqd1 = mq_open(mq_name, oflag1, mode, Some(&attr)).unwrap();
|
||||
let mut buf = [0u8; 32];
|
||||
let mut prio = 0u32;
|
||||
let len = mq_receive(&mqd1, &mut buf, &mut prio).unwrap();
|
||||
assert_eq!(prio, 1);
|
||||
|
||||
mq_close(mqd1).unwrap();
|
||||
mq_close(mqd0).unwrap();
|
||||
assert_eq!(msg_to_send, str::from_utf8(&buf[0..len]).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_getattr() {
|
||||
use nix::mqueue::mq_getattr;
|
||||
const MSG_SIZE: mq_attr_member_t = 32;
|
||||
let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
|
||||
let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
|
||||
let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
|
||||
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
|
||||
let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
|
||||
if let Err(Errno::ENOSYS) = r {
|
||||
println!("message queues not supported or module not loaded?");
|
||||
return;
|
||||
};
|
||||
let mqd = r.unwrap();
|
||||
|
||||
let read_attr = mq_getattr(&mqd).unwrap();
|
||||
assert_attr_eq!(read_attr, initial_attr);
|
||||
mq_close(mqd).unwrap();
|
||||
}
|
||||
|
||||
// FIXME: Fix failures for mips in QEMU
|
||||
#[test]
|
||||
#[cfg_attr(
|
||||
all(qemu, any(target_arch = "mips", target_arch = "mips64")),
|
||||
ignore
|
||||
)]
|
||||
fn test_mq_setattr() {
|
||||
use nix::mqueue::{mq_getattr, mq_setattr};
|
||||
const MSG_SIZE: mq_attr_member_t = 32;
|
||||
let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
|
||||
let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
|
||||
let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
|
||||
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
|
||||
let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
|
||||
if let Err(Errno::ENOSYS) = r {
|
||||
println!("message queues not supported or module not loaded?");
|
||||
return;
|
||||
};
|
||||
let mqd = r.unwrap();
|
||||
|
||||
let new_attr = MqAttr::new(0, 20, MSG_SIZE * 2, 100);
|
||||
let old_attr = mq_setattr(&mqd, &new_attr).unwrap();
|
||||
assert_attr_eq!(old_attr, initial_attr);
|
||||
|
||||
// No changes here because according to the Linux man page only
|
||||
// O_NONBLOCK can be set (see tests below)
|
||||
#[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))]
|
||||
{
|
||||
let new_attr_get = mq_getattr(&mqd).unwrap();
|
||||
assert_ne!(new_attr_get, new_attr);
|
||||
}
|
||||
|
||||
let new_attr_non_blocking = MqAttr::new(
|
||||
MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t,
|
||||
10,
|
||||
MSG_SIZE,
|
||||
0,
|
||||
);
|
||||
mq_setattr(&mqd, &new_attr_non_blocking).unwrap();
|
||||
let new_attr_get = mq_getattr(&mqd).unwrap();
|
||||
|
||||
// now the O_NONBLOCK flag has been set
|
||||
#[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))]
|
||||
{
|
||||
assert_ne!(new_attr_get, initial_attr);
|
||||
}
|
||||
assert_attr_eq!(new_attr_get, new_attr_non_blocking);
|
||||
mq_close(mqd).unwrap();
|
||||
}
|
||||
|
||||
// FIXME: Fix failures for mips in QEMU
|
||||
#[test]
|
||||
#[cfg_attr(
|
||||
all(qemu, any(target_arch = "mips", target_arch = "mips64")),
|
||||
ignore
|
||||
)]
|
||||
fn test_mq_set_nonblocking() {
|
||||
use nix::mqueue::{mq_getattr, mq_remove_nonblock, mq_set_nonblock};
|
||||
const MSG_SIZE: mq_attr_member_t = 32;
|
||||
let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
|
||||
let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
|
||||
let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
|
||||
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
|
||||
let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
|
||||
if let Err(Errno::ENOSYS) = r {
|
||||
println!("message queues not supported or module not loaded?");
|
||||
return;
|
||||
};
|
||||
let mqd = r.unwrap();
|
||||
mq_set_nonblock(&mqd).unwrap();
|
||||
let new_attr = mq_getattr(&mqd);
|
||||
let o_nonblock_bits = MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t;
|
||||
assert_eq!(new_attr.unwrap().flags() & o_nonblock_bits, o_nonblock_bits);
|
||||
mq_remove_nonblock(&mqd).unwrap();
|
||||
let new_attr = mq_getattr(&mqd);
|
||||
assert_eq!(new_attr.unwrap().flags() & o_nonblock_bits, 0);
|
||||
mq_close(mqd).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mq_unlink() {
|
||||
use nix::mqueue::mq_unlink;
|
||||
const MSG_SIZE: mq_attr_member_t = 32;
|
||||
let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
|
||||
let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap();
|
||||
#[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))]
|
||||
let mq_name_not_opened =
|
||||
&CString::new(b"/mq_unlink_test".as_ref()).unwrap();
|
||||
let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
|
||||
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
|
||||
let r = mq_open(mq_name_opened, oflag, mode, Some(&initial_attr));
|
||||
if let Err(Errno::ENOSYS) = r {
|
||||
println!("message queues not supported or module not loaded?");
|
||||
return;
|
||||
};
|
||||
let mqd = r.unwrap();
|
||||
|
||||
let res_unlink = mq_unlink(mq_name_opened);
|
||||
assert_eq!(res_unlink, Ok(()));
|
||||
|
||||
// NetBSD (and others which inherit its implementation) defer removing the message
|
||||
// queue name until all references are closed, whereas Linux and others remove the
|
||||
// message queue name immediately.
|
||||
#[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))]
|
||||
{
|
||||
let res_unlink_not_opened = mq_unlink(mq_name_not_opened);
|
||||
assert_eq!(res_unlink_not_opened, Err(Errno::ENOENT));
|
||||
}
|
||||
|
||||
mq_close(mqd).unwrap();
|
||||
let res_unlink_after_close = mq_unlink(mq_name_opened);
|
||||
assert_eq!(res_unlink_after_close, Err(Errno::ENOENT));
|
||||
}
|
||||
19
third-party/vendor/nix/test/test_net.rs
vendored
Normal file
19
third-party/vendor/nix/test/test_net.rs
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use nix::net::if_::*;
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
const LOOPBACK: &[u8] = b"lo";
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "haiku"
|
||||
)))]
|
||||
const LOOPBACK: &[u8] = b"lo0";
|
||||
|
||||
#[cfg(target_os = "haiku")]
|
||||
const LOOPBACK: &[u8] = b"loop";
|
||||
|
||||
#[test]
|
||||
fn test_if_nametoindex() {
|
||||
if_nametoindex(LOOPBACK).expect("assertion failed");
|
||||
}
|
||||
1
third-party/vendor/nix/test/test_nix_path.rs
vendored
Normal file
1
third-party/vendor/nix/test/test_nix_path.rs
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
49
third-party/vendor/nix/test/test_nmount.rs
vendored
Normal file
49
third-party/vendor/nix/test/test_nmount.rs
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
use crate::*;
|
||||
use nix::{
|
||||
errno::Errno,
|
||||
mount::{unmount, MntFlags, Nmount},
|
||||
};
|
||||
use std::{ffi::CString, fs::File, path::Path};
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
fn ok() {
|
||||
require_mount!("nullfs");
|
||||
|
||||
let mountpoint = tempdir().unwrap();
|
||||
let target = tempdir().unwrap();
|
||||
let _sentry = File::create(target.path().join("sentry")).unwrap();
|
||||
|
||||
let fstype = CString::new("fstype").unwrap();
|
||||
let nullfs = CString::new("nullfs").unwrap();
|
||||
Nmount::new()
|
||||
.str_opt(&fstype, &nullfs)
|
||||
.str_opt_owned("fspath", mountpoint.path().to_str().unwrap())
|
||||
.str_opt_owned("target", target.path().to_str().unwrap())
|
||||
.nmount(MntFlags::empty())
|
||||
.unwrap();
|
||||
|
||||
// Now check that the sentry is visible through the mountpoint
|
||||
let exists = Path::exists(&mountpoint.path().join("sentry"));
|
||||
|
||||
// Cleanup the mountpoint before asserting
|
||||
unmount(mountpoint.path(), MntFlags::empty()).unwrap();
|
||||
|
||||
assert!(exists);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_fstype() {
|
||||
let mountpoint = tempdir().unwrap();
|
||||
let target = tempdir().unwrap();
|
||||
let _sentry = File::create(target.path().join("sentry")).unwrap();
|
||||
|
||||
let e = Nmount::new()
|
||||
.str_opt_owned("fspath", mountpoint.path().to_str().unwrap())
|
||||
.str_opt_owned("target", target.path().to_str().unwrap())
|
||||
.nmount(MntFlags::empty())
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(e.error(), Errno::EINVAL);
|
||||
assert_eq!(e.errmsg(), Some("Invalid fstype"));
|
||||
}
|
||||
84
third-party/vendor/nix/test/test_poll.rs
vendored
Normal file
84
third-party/vendor/nix/test/test_poll.rs
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
use nix::{
|
||||
errno::Errno,
|
||||
poll::{poll, PollFd, PollFlags},
|
||||
unistd::{pipe, write},
|
||||
};
|
||||
|
||||
macro_rules! loop_while_eintr {
|
||||
($poll_expr: expr) => {
|
||||
loop {
|
||||
match $poll_expr {
|
||||
Ok(nfds) => break nfds,
|
||||
Err(Errno::EINTR) => (),
|
||||
Err(e) => panic!("{}", e),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_poll() {
|
||||
let (r, w) = pipe().unwrap();
|
||||
let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
|
||||
|
||||
// Poll an idle pipe. Should timeout
|
||||
let nfds = loop_while_eintr!(poll(&mut fds, 100));
|
||||
assert_eq!(nfds, 0);
|
||||
assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
|
||||
|
||||
write(w, b".").unwrap();
|
||||
|
||||
// Poll a readable pipe. Should return an event.
|
||||
let nfds = poll(&mut fds, 100).unwrap();
|
||||
assert_eq!(nfds, 1);
|
||||
assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
|
||||
}
|
||||
|
||||
// ppoll(2) is the same as poll except for how it handles timeouts and signals.
|
||||
// Repeating the test for poll(2) should be sufficient to check that our
|
||||
// bindings are correct.
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux"
|
||||
))]
|
||||
#[test]
|
||||
fn test_ppoll() {
|
||||
use nix::poll::ppoll;
|
||||
use nix::sys::signal::SigSet;
|
||||
use nix::sys::time::{TimeSpec, TimeValLike};
|
||||
|
||||
let timeout = TimeSpec::milliseconds(1);
|
||||
let (r, w) = pipe().unwrap();
|
||||
let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
|
||||
|
||||
// Poll an idle pipe. Should timeout
|
||||
let sigset = SigSet::empty();
|
||||
let nfds = loop_while_eintr!(ppoll(&mut fds, Some(timeout), Some(sigset)));
|
||||
assert_eq!(nfds, 0);
|
||||
assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
|
||||
|
||||
write(w, b".").unwrap();
|
||||
|
||||
// Poll a readable pipe. Should return an event.
|
||||
let nfds = ppoll(&mut fds, Some(timeout), None).unwrap();
|
||||
assert_eq!(nfds, 1);
|
||||
assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pollfd_fd() {
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
let pfd = PollFd::new(0x1234, PollFlags::empty());
|
||||
assert_eq!(pfd.as_raw_fd(), 0x1234);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pollfd_events() {
|
||||
let mut pfd = PollFd::new(-1, PollFlags::POLLIN);
|
||||
assert_eq!(pfd.events(), PollFlags::POLLIN);
|
||||
pfd.set_events(PollFlags::POLLOUT);
|
||||
assert_eq!(pfd.events(), PollFlags::POLLOUT);
|
||||
}
|
||||
313
third-party/vendor/nix/test/test_pty.rs
vendored
Normal file
313
third-party/vendor/nix/test/test_pty.rs
vendored
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::prelude::*;
|
||||
use std::path::Path;
|
||||
use tempfile::tempfile;
|
||||
|
||||
use libc::{_exit, STDOUT_FILENO};
|
||||
use nix::fcntl::{open, OFlag};
|
||||
use nix::pty::*;
|
||||
use nix::sys::stat;
|
||||
use nix::sys::termios::*;
|
||||
use nix::unistd::{close, pause, write};
|
||||
|
||||
/// Regression test for Issue #659
|
||||
/// This is the correct way to explicitly close a `PtyMaster`
|
||||
#[test]
|
||||
fn test_explicit_close() {
|
||||
let mut f = {
|
||||
let m = posix_openpt(OFlag::O_RDWR).unwrap();
|
||||
close(m.into_raw_fd()).unwrap();
|
||||
tempfile().unwrap()
|
||||
};
|
||||
// This should work. But if there's been a double close, then it will
|
||||
// return EBADF
|
||||
f.write_all(b"whatever").unwrap();
|
||||
}
|
||||
|
||||
/// Test equivalence of `ptsname` and `ptsname_r`
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn test_ptsname_equivalence() {
|
||||
let _m = crate::PTSNAME_MTX.lock();
|
||||
|
||||
// Open a new PTTY master
|
||||
let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
|
||||
assert!(master_fd.as_raw_fd() > 0);
|
||||
|
||||
// Get the name of the slave
|
||||
let slave_name = unsafe { ptsname(&master_fd) }.unwrap();
|
||||
let slave_name_r = ptsname_r(&master_fd).unwrap();
|
||||
assert_eq!(slave_name, slave_name_r);
|
||||
}
|
||||
|
||||
/// Test data copying of `ptsname`
|
||||
// TODO need to run in a subprocess, since ptsname is non-reentrant
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn test_ptsname_copy() {
|
||||
let _m = crate::PTSNAME_MTX.lock();
|
||||
|
||||
// Open a new PTTY master
|
||||
let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
|
||||
assert!(master_fd.as_raw_fd() > 0);
|
||||
|
||||
// Get the name of the slave
|
||||
let slave_name1 = unsafe { ptsname(&master_fd) }.unwrap();
|
||||
let slave_name2 = unsafe { ptsname(&master_fd) }.unwrap();
|
||||
assert_eq!(slave_name1, slave_name2);
|
||||
// Also make sure that the string was actually copied and they point to different parts of
|
||||
// memory.
|
||||
assert_ne!(slave_name1.as_ptr(), slave_name2.as_ptr());
|
||||
}
|
||||
|
||||
/// Test data copying of `ptsname_r`
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn test_ptsname_r_copy() {
|
||||
// Open a new PTTY master
|
||||
let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
|
||||
assert!(master_fd.as_raw_fd() > 0);
|
||||
|
||||
// Get the name of the slave
|
||||
let slave_name1 = ptsname_r(&master_fd).unwrap();
|
||||
let slave_name2 = ptsname_r(&master_fd).unwrap();
|
||||
assert_eq!(slave_name1, slave_name2);
|
||||
assert_ne!(slave_name1.as_ptr(), slave_name2.as_ptr());
|
||||
}
|
||||
|
||||
/// Test that `ptsname` returns different names for different devices
|
||||
#[test]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
fn test_ptsname_unique() {
|
||||
let _m = crate::PTSNAME_MTX.lock();
|
||||
|
||||
// Open a new PTTY master
|
||||
let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap();
|
||||
assert!(master1_fd.as_raw_fd() > 0);
|
||||
|
||||
// Open a second PTTY master
|
||||
let master2_fd = posix_openpt(OFlag::O_RDWR).unwrap();
|
||||
assert!(master2_fd.as_raw_fd() > 0);
|
||||
|
||||
// Get the name of the slave
|
||||
let slave_name1 = unsafe { ptsname(&master1_fd) }.unwrap();
|
||||
let slave_name2 = unsafe { ptsname(&master2_fd) }.unwrap();
|
||||
assert_ne!(slave_name1, slave_name2);
|
||||
}
|
||||
|
||||
/// Common setup for testing PTTY pairs
|
||||
fn open_ptty_pair() -> (PtyMaster, File) {
|
||||
let _m = crate::PTSNAME_MTX.lock();
|
||||
|
||||
// Open a new PTTY master
|
||||
let master = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed");
|
||||
|
||||
// Allow a slave to be generated for it
|
||||
grantpt(&master).expect("grantpt failed");
|
||||
unlockpt(&master).expect("unlockpt failed");
|
||||
|
||||
// Get the name of the slave
|
||||
let slave_name = unsafe { ptsname(&master) }.expect("ptsname failed");
|
||||
|
||||
// Open the slave device
|
||||
let slave_fd =
|
||||
open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty())
|
||||
.unwrap();
|
||||
|
||||
#[cfg(target_os = "illumos")]
|
||||
// TODO: rewrite using ioctl!
|
||||
#[allow(clippy::comparison_chain)]
|
||||
{
|
||||
use libc::{ioctl, I_FIND, I_PUSH};
|
||||
|
||||
// On illumos systems, as per pts(7D), one must push STREAMS modules
|
||||
// after opening a device path returned from ptsname().
|
||||
let ptem = b"ptem\0";
|
||||
let ldterm = b"ldterm\0";
|
||||
let r = unsafe { ioctl(slave_fd, I_FIND, ldterm.as_ptr()) };
|
||||
if r < 0 {
|
||||
panic!("I_FIND failure");
|
||||
} else if r == 0 {
|
||||
if unsafe { ioctl(slave_fd, I_PUSH, ptem.as_ptr()) } < 0 {
|
||||
panic!("I_PUSH ptem failure");
|
||||
}
|
||||
if unsafe { ioctl(slave_fd, I_PUSH, ldterm.as_ptr()) } < 0 {
|
||||
panic!("I_PUSH ldterm failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let slave = unsafe { File::from_raw_fd(slave_fd) };
|
||||
|
||||
(master, slave)
|
||||
}
|
||||
|
||||
/// Test opening a master/slave PTTY pair
|
||||
///
|
||||
/// This uses a common `open_ptty_pair` because much of these functions aren't useful by
|
||||
/// themselves. So for this test we perform the basic act of getting a file handle for a
|
||||
/// master/slave PTTY pair, then just sanity-check the raw values.
|
||||
#[test]
|
||||
fn test_open_ptty_pair() {
|
||||
let (master, slave) = open_ptty_pair();
|
||||
assert!(master.as_raw_fd() > 0);
|
||||
assert!(slave.as_raw_fd() > 0);
|
||||
}
|
||||
|
||||
/// Put the terminal in raw mode.
|
||||
fn make_raw(fd: RawFd) {
|
||||
let mut termios = tcgetattr(fd).unwrap();
|
||||
cfmakeraw(&mut termios);
|
||||
tcsetattr(fd, SetArg::TCSANOW, &termios).unwrap();
|
||||
}
|
||||
|
||||
/// Test `io::Read` on the PTTY master
|
||||
#[test]
|
||||
fn test_read_ptty_pair() {
|
||||
let (mut master, mut slave) = open_ptty_pair();
|
||||
make_raw(slave.as_raw_fd());
|
||||
|
||||
let mut buf = [0u8; 5];
|
||||
slave.write_all(b"hello").unwrap();
|
||||
master.read_exact(&mut buf).unwrap();
|
||||
assert_eq!(&buf, b"hello");
|
||||
|
||||
let mut master = &master;
|
||||
slave.write_all(b"hello").unwrap();
|
||||
master.read_exact(&mut buf).unwrap();
|
||||
assert_eq!(&buf, b"hello");
|
||||
}
|
||||
|
||||
/// Test `io::Write` on the PTTY master
|
||||
#[test]
|
||||
fn test_write_ptty_pair() {
|
||||
let (mut master, mut slave) = open_ptty_pair();
|
||||
make_raw(slave.as_raw_fd());
|
||||
|
||||
let mut buf = [0u8; 5];
|
||||
master.write_all(b"adios").unwrap();
|
||||
slave.read_exact(&mut buf).unwrap();
|
||||
assert_eq!(&buf, b"adios");
|
||||
|
||||
let mut master = &master;
|
||||
master.write_all(b"adios").unwrap();
|
||||
slave.read_exact(&mut buf).unwrap();
|
||||
assert_eq!(&buf, b"adios");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_openpty() {
|
||||
// openpty uses ptname(3) internally
|
||||
let _m = crate::PTSNAME_MTX.lock();
|
||||
|
||||
let pty = openpty(None, None).unwrap();
|
||||
assert!(pty.master > 0);
|
||||
assert!(pty.slave > 0);
|
||||
|
||||
// Writing to one should be readable on the other one
|
||||
let string = "foofoofoo\n";
|
||||
let mut buf = [0u8; 10];
|
||||
write(pty.master, string.as_bytes()).unwrap();
|
||||
crate::read_exact(pty.slave, &mut buf);
|
||||
|
||||
assert_eq!(&buf, string.as_bytes());
|
||||
|
||||
// Read the echo as well
|
||||
let echoed_string = "foofoofoo\r\n";
|
||||
let mut buf = [0u8; 11];
|
||||
crate::read_exact(pty.master, &mut buf);
|
||||
assert_eq!(&buf, echoed_string.as_bytes());
|
||||
|
||||
let string2 = "barbarbarbar\n";
|
||||
let echoed_string2 = "barbarbarbar\r\n";
|
||||
let mut buf = [0u8; 14];
|
||||
write(pty.slave, string2.as_bytes()).unwrap();
|
||||
crate::read_exact(pty.master, &mut buf);
|
||||
|
||||
assert_eq!(&buf, echoed_string2.as_bytes());
|
||||
|
||||
close(pty.master).unwrap();
|
||||
close(pty.slave).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_openpty_with_termios() {
|
||||
// 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 newlines are not transformed so the data is preserved when sent.
|
||||
termios.output_flags.remove(OutputFlags::ONLCR);
|
||||
|
||||
let pty = openpty(None, &termios).unwrap();
|
||||
// Must be valid file descriptors
|
||||
assert!(pty.master > 0);
|
||||
assert!(pty.slave > 0);
|
||||
|
||||
// Writing to one should be readable on the other one
|
||||
let string = "foofoofoo\n";
|
||||
let mut buf = [0u8; 10];
|
||||
write(pty.master, string.as_bytes()).unwrap();
|
||||
crate::read_exact(pty.slave, &mut buf);
|
||||
|
||||
assert_eq!(&buf, string.as_bytes());
|
||||
|
||||
// read the echo as well
|
||||
let echoed_string = "foofoofoo\n";
|
||||
crate::read_exact(pty.master, &mut buf);
|
||||
assert_eq!(&buf, echoed_string.as_bytes());
|
||||
|
||||
let string2 = "barbarbarbar\n";
|
||||
let echoed_string2 = "barbarbarbar\n";
|
||||
let mut buf = [0u8; 13];
|
||||
write(pty.slave, string2.as_bytes()).unwrap();
|
||||
crate::read_exact(pty.master, &mut buf);
|
||||
|
||||
assert_eq!(&buf, echoed_string2.as_bytes());
|
||||
|
||||
close(pty.master).unwrap();
|
||||
close(pty.slave).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_forkpty() {
|
||||
use nix::sys::signal::*;
|
||||
use nix::sys::wait::wait;
|
||||
use nix::unistd::ForkResult::*;
|
||||
// forkpty calls openpty which uses ptname(3) internally.
|
||||
let _m0 = crate::PTSNAME_MTX.lock();
|
||||
// forkpty spawns a child process
|
||||
let _m1 = crate::FORK_MTX.lock();
|
||||
|
||||
let string = "naninani\n";
|
||||
let echoed_string = "naninani\r\n";
|
||||
let pty = unsafe { forkpty(None, None).unwrap() };
|
||||
match pty.fork_result {
|
||||
Child => {
|
||||
write(STDOUT_FILENO, string.as_bytes()).unwrap();
|
||||
pause(); // we need the child to stay alive until the parent calls read
|
||||
unsafe {
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
Parent { child } => {
|
||||
let mut buf = [0u8; 10];
|
||||
assert!(child.as_raw() > 0);
|
||||
crate::read_exact(pty.master, &mut buf);
|
||||
kill(child, SIGTERM).unwrap();
|
||||
wait().unwrap(); // keep other tests using generic wait from getting our child
|
||||
assert_eq!(&buf, echoed_string.as_bytes());
|
||||
close(pty.master).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
20
third-party/vendor/nix/test/test_ptymaster_drop.rs
vendored
Normal file
20
third-party/vendor/nix/test/test_ptymaster_drop.rs
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
|
||||
mod t {
|
||||
use nix::fcntl::OFlag;
|
||||
use nix::pty::*;
|
||||
use nix::unistd::close;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
/// Regression test for Issue #659
|
||||
///
|
||||
/// `PtyMaster` should panic rather than double close the file descriptor
|
||||
/// This must run in its own test process because it deliberately creates a
|
||||
/// race condition.
|
||||
#[test]
|
||||
#[should_panic(expected = "Closing an invalid file descriptor!")]
|
||||
fn test_double_close() {
|
||||
let m = posix_openpt(OFlag::O_RDWR).unwrap();
|
||||
close(m.as_raw_fd()).unwrap();
|
||||
drop(m); // should panic here
|
||||
}
|
||||
}
|
||||
34
third-party/vendor/nix/test/test_resource.rs
vendored
Normal file
34
third-party/vendor/nix/test/test_resource.rs
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#[cfg(not(any(
|
||||
target_os = "redox",
|
||||
target_os = "fuchsia",
|
||||
target_os = "illumos",
|
||||
target_os = "haiku"
|
||||
)))]
|
||||
use nix::sys::resource::{getrlimit, setrlimit, Resource};
|
||||
|
||||
/// Tests the RLIMIT_NOFILE functionality of getrlimit(), where the resource RLIMIT_NOFILE refers
|
||||
/// to the maximum file descriptor number that can be opened by the process (aka the maximum number
|
||||
/// of file descriptors that the process can open, since Linux 4.5).
|
||||
///
|
||||
/// We first fetch the existing file descriptor maximum values using getrlimit(), then edit the
|
||||
/// soft limit to make sure it has a new and distinct value to the hard limit. We then setrlimit()
|
||||
/// to put the new soft limit in effect, and then getrlimit() once more to ensure the limits have
|
||||
/// been updated.
|
||||
#[test]
|
||||
#[cfg(not(any(
|
||||
target_os = "redox",
|
||||
target_os = "fuchsia",
|
||||
target_os = "illumos",
|
||||
target_os = "haiku"
|
||||
)))]
|
||||
pub fn test_resource_limits_nofile() {
|
||||
let (mut soft_limit, hard_limit) =
|
||||
getrlimit(Resource::RLIMIT_NOFILE).unwrap();
|
||||
|
||||
soft_limit -= 1;
|
||||
assert_ne!(soft_limit, hard_limit);
|
||||
setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap();
|
||||
|
||||
let (new_soft_limit, _) = getrlimit(Resource::RLIMIT_NOFILE).unwrap();
|
||||
assert_eq!(new_soft_limit, soft_limit);
|
||||
}
|
||||
35
third-party/vendor/nix/test/test_sched.rs
vendored
Normal file
35
third-party/vendor/nix/test/test_sched.rs
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
use nix::sched::{sched_getaffinity, sched_setaffinity, CpuSet};
|
||||
use nix::unistd::Pid;
|
||||
|
||||
#[test]
|
||||
fn test_sched_affinity() {
|
||||
// If pid is zero, then the mask of the calling process is returned.
|
||||
let initial_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap();
|
||||
let mut at_least_one_cpu = false;
|
||||
let mut last_valid_cpu = 0;
|
||||
for field in 0..CpuSet::count() {
|
||||
if initial_affinity.is_set(field).unwrap() {
|
||||
at_least_one_cpu = true;
|
||||
last_valid_cpu = field;
|
||||
}
|
||||
}
|
||||
assert!(at_least_one_cpu);
|
||||
|
||||
// Now restrict the running CPU
|
||||
let mut new_affinity = CpuSet::new();
|
||||
new_affinity.set(last_valid_cpu).unwrap();
|
||||
sched_setaffinity(Pid::from_raw(0), &new_affinity).unwrap();
|
||||
|
||||
// And now re-check the affinity which should be only the one we set.
|
||||
let updated_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap();
|
||||
for field in 0..CpuSet::count() {
|
||||
// Should be set only for the CPU we set previously
|
||||
assert_eq!(
|
||||
updated_affinity.is_set(field).unwrap(),
|
||||
field == last_valid_cpu
|
||||
)
|
||||
}
|
||||
|
||||
// Finally, reset the initial CPU set
|
||||
sched_setaffinity(Pid::from_raw(0), &initial_affinity).unwrap();
|
||||
}
|
||||
208
third-party/vendor/nix/test/test_sendfile.rs
vendored
Normal file
208
third-party/vendor/nix/test/test_sendfile.rs
vendored
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
use std::io::prelude::*;
|
||||
use std::os::unix::prelude::*;
|
||||
|
||||
use libc::off_t;
|
||||
use nix::sys::sendfile::*;
|
||||
use tempfile::tempfile;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_os = "android", target_os = "linux"))] {
|
||||
use nix::unistd::{close, pipe, read};
|
||||
} else if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos"))] {
|
||||
use std::net::Shutdown;
|
||||
use std::os::unix::net::UnixStream;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[test]
|
||||
fn test_sendfile_linux() {
|
||||
const CONTENTS: &[u8] = b"abcdef123456";
|
||||
let mut tmp = tempfile().unwrap();
|
||||
tmp.write_all(CONTENTS).unwrap();
|
||||
|
||||
let (rd, wr) = pipe().unwrap();
|
||||
let mut offset: off_t = 5;
|
||||
let res = sendfile(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap();
|
||||
|
||||
assert_eq!(2, res);
|
||||
|
||||
let mut buf = [0u8; 1024];
|
||||
assert_eq!(2, read(rd, &mut buf).unwrap());
|
||||
assert_eq!(b"f1", &buf[0..2]);
|
||||
assert_eq!(7, offset);
|
||||
|
||||
close(rd).unwrap();
|
||||
close(wr).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn test_sendfile64_linux() {
|
||||
const CONTENTS: &[u8] = b"abcdef123456";
|
||||
let mut tmp = tempfile().unwrap();
|
||||
tmp.write_all(CONTENTS).unwrap();
|
||||
|
||||
let (rd, wr) = pipe().unwrap();
|
||||
let mut offset: libc::off64_t = 5;
|
||||
let res = sendfile64(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap();
|
||||
|
||||
assert_eq!(2, res);
|
||||
|
||||
let mut buf = [0u8; 1024];
|
||||
assert_eq!(2, read(rd, &mut buf).unwrap());
|
||||
assert_eq!(b"f1", &buf[0..2]);
|
||||
assert_eq!(7, offset);
|
||||
|
||||
close(rd).unwrap();
|
||||
close(wr).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[test]
|
||||
fn test_sendfile_freebsd() {
|
||||
// Declare the content
|
||||
let header_strings =
|
||||
vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
|
||||
let body = "Xabcdef123456";
|
||||
let body_offset = 1;
|
||||
let trailer_strings = vec!["\n", "Served by Make Believe\n"];
|
||||
|
||||
// Write the body to a file
|
||||
let mut tmp = tempfile().unwrap();
|
||||
tmp.write_all(body.as_bytes()).unwrap();
|
||||
|
||||
// Prepare headers and trailers for sendfile
|
||||
let headers: Vec<&[u8]> =
|
||||
header_strings.iter().map(|s| s.as_bytes()).collect();
|
||||
let trailers: Vec<&[u8]> =
|
||||
trailer_strings.iter().map(|s| s.as_bytes()).collect();
|
||||
|
||||
// Prepare socket pair
|
||||
let (mut rd, wr) = UnixStream::pair().unwrap();
|
||||
|
||||
// Call the test method
|
||||
let (res, bytes_written) = sendfile(
|
||||
tmp.as_raw_fd(),
|
||||
wr.as_raw_fd(),
|
||||
body_offset as off_t,
|
||||
None,
|
||||
Some(headers.as_slice()),
|
||||
Some(trailers.as_slice()),
|
||||
SfFlags::empty(),
|
||||
0,
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
wr.shutdown(Shutdown::Both).unwrap();
|
||||
|
||||
// Prepare the expected result
|
||||
let expected_string = header_strings.concat()
|
||||
+ &body[body_offset..]
|
||||
+ &trailer_strings.concat();
|
||||
|
||||
// Verify the message that was sent
|
||||
assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
|
||||
|
||||
let mut read_string = String::new();
|
||||
let bytes_read = rd.read_to_string(&mut read_string).unwrap();
|
||||
assert_eq!(bytes_written as usize, bytes_read);
|
||||
assert_eq!(expected_string, read_string);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[test]
|
||||
fn test_sendfile_dragonfly() {
|
||||
// Declare the content
|
||||
let header_strings =
|
||||
vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
|
||||
let body = "Xabcdef123456";
|
||||
let body_offset = 1;
|
||||
let trailer_strings = vec!["\n", "Served by Make Believe\n"];
|
||||
|
||||
// Write the body to a file
|
||||
let mut tmp = tempfile().unwrap();
|
||||
tmp.write_all(body.as_bytes()).unwrap();
|
||||
|
||||
// Prepare headers and trailers for sendfile
|
||||
let headers: Vec<&[u8]> =
|
||||
header_strings.iter().map(|s| s.as_bytes()).collect();
|
||||
let trailers: Vec<&[u8]> =
|
||||
trailer_strings.iter().map(|s| s.as_bytes()).collect();
|
||||
|
||||
// Prepare socket pair
|
||||
let (mut rd, wr) = UnixStream::pair().unwrap();
|
||||
|
||||
// Call the test method
|
||||
let (res, bytes_written) = sendfile(
|
||||
tmp.as_raw_fd(),
|
||||
wr.as_raw_fd(),
|
||||
body_offset as off_t,
|
||||
None,
|
||||
Some(headers.as_slice()),
|
||||
Some(trailers.as_slice()),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
wr.shutdown(Shutdown::Both).unwrap();
|
||||
|
||||
// Prepare the expected result
|
||||
let expected_string = header_strings.concat()
|
||||
+ &body[body_offset..]
|
||||
+ &trailer_strings.concat();
|
||||
|
||||
// Verify the message that was sent
|
||||
assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
|
||||
|
||||
let mut read_string = String::new();
|
||||
let bytes_read = rd.read_to_string(&mut read_string).unwrap();
|
||||
assert_eq!(bytes_written as usize, bytes_read);
|
||||
assert_eq!(expected_string, read_string);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
#[test]
|
||||
fn test_sendfile_darwin() {
|
||||
// Declare the content
|
||||
let header_strings =
|
||||
vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
|
||||
let body = "Xabcdef123456";
|
||||
let body_offset = 1;
|
||||
let trailer_strings = vec!["\n", "Served by Make Believe\n"];
|
||||
|
||||
// Write the body to a file
|
||||
let mut tmp = tempfile().unwrap();
|
||||
tmp.write_all(body.as_bytes()).unwrap();
|
||||
|
||||
// Prepare headers and trailers for sendfile
|
||||
let headers: Vec<&[u8]> =
|
||||
header_strings.iter().map(|s| s.as_bytes()).collect();
|
||||
let trailers: Vec<&[u8]> =
|
||||
trailer_strings.iter().map(|s| s.as_bytes()).collect();
|
||||
|
||||
// Prepare socket pair
|
||||
let (mut rd, wr) = UnixStream::pair().unwrap();
|
||||
|
||||
// Call the test method
|
||||
let (res, bytes_written) = sendfile(
|
||||
tmp.as_raw_fd(),
|
||||
wr.as_raw_fd(),
|
||||
body_offset as off_t,
|
||||
None,
|
||||
Some(headers.as_slice()),
|
||||
Some(trailers.as_slice()),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
wr.shutdown(Shutdown::Both).unwrap();
|
||||
|
||||
// Prepare the expected result
|
||||
let expected_string = header_strings.concat()
|
||||
+ &body[body_offset..]
|
||||
+ &trailer_strings.concat();
|
||||
|
||||
// Verify the message that was sent
|
||||
assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
|
||||
|
||||
let mut read_string = String::new();
|
||||
let bytes_read = rd.read_to_string(&mut read_string).unwrap();
|
||||
assert_eq!(bytes_written as usize, bytes_read);
|
||||
assert_eq!(expected_string, read_string);
|
||||
}
|
||||
421
third-party/vendor/nix/test/test_stat.rs
vendored
Normal file
421
third-party/vendor/nix/test/test_stat.rs
vendored
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use std::os::unix::fs::symlink;
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::os::unix::prelude::AsRawFd;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use std::path::Path;
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
|
||||
use libc::mode_t;
|
||||
#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
|
||||
use libc::{S_IFLNK, S_IFMT};
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::errno::Errno;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::fcntl;
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd"
|
||||
))]
|
||||
use nix::sys::stat::lutimes;
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
use nix::sys::stat::utimensat;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::sys::stat::FchmodatFlags;
|
||||
use nix::sys::stat::Mode;
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
use nix::sys::stat::UtimensatFlags;
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::sys::stat::{self};
|
||||
use nix::sys::stat::{fchmod, stat};
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::sys::stat::{fchmodat, mkdirat};
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
use nix::sys::stat::{futimens, utimes};
|
||||
|
||||
#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
|
||||
use nix::sys::stat::FileStat;
|
||||
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
use nix::sys::time::{TimeSpec, TimeVal, TimeValLike};
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
use nix::unistd::chdir;
|
||||
|
||||
#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
|
||||
use nix::Result;
|
||||
|
||||
#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
|
||||
fn assert_stat_results(stat_result: Result<FileStat>) {
|
||||
let stats = stat_result.expect("stat call failed");
|
||||
assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent
|
||||
assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent
|
||||
assert!(stats.st_mode > 0); // must be positive integer
|
||||
assert_eq!(stats.st_nlink, 1); // there links created, must be 1
|
||||
assert_eq!(stats.st_size, 0); // size is 0 because we did not write anything to the file
|
||||
assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent
|
||||
assert!(stats.st_blocks <= 16); // Up to 16 blocks can be allocated for a blank file
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
|
||||
// (Android's st_blocks is ulonglong which is always non-negative.)
|
||||
#[cfg_attr(target_os = "android", allow(unused_comparisons))]
|
||||
#[allow(clippy::absurd_extreme_comparisons)] // Not absurd on all OSes
|
||||
fn assert_lstat_results(stat_result: Result<FileStat>) {
|
||||
let stats = stat_result.expect("stat call failed");
|
||||
assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent
|
||||
assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent
|
||||
assert!(stats.st_mode > 0); // must be positive integer
|
||||
|
||||
// st_mode is c_uint (u32 on Android) while S_IFMT is mode_t
|
||||
// (u16 on Android), and that will be a compile error.
|
||||
// On other platforms they are the same (either both are u16 or u32).
|
||||
assert_eq!(
|
||||
(stats.st_mode as usize) & (S_IFMT as usize),
|
||||
S_IFLNK as usize
|
||||
); // should be a link
|
||||
assert_eq!(stats.st_nlink, 1); // there links created, must be 1
|
||||
assert!(stats.st_size > 0); // size is > 0 because it points to another file
|
||||
assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent
|
||||
|
||||
// st_blocks depends on whether the machine's file system uses fast
|
||||
// or slow symlinks, so just make sure it's not negative
|
||||
assert!(stats.st_blocks >= 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
|
||||
fn test_stat_and_fstat() {
|
||||
use nix::sys::stat::fstat;
|
||||
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let filename = tempdir.path().join("foo.txt");
|
||||
let file = File::create(&filename).unwrap();
|
||||
|
||||
let stat_result = stat(&filename);
|
||||
assert_stat_results(stat_result);
|
||||
|
||||
let fstat_result = fstat(file.as_raw_fd());
|
||||
assert_stat_results(fstat_result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
|
||||
fn test_fstatat() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let filename = tempdir.path().join("foo.txt");
|
||||
File::create(&filename).unwrap();
|
||||
let dirfd =
|
||||
fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty());
|
||||
|
||||
let result =
|
||||
stat::fstatat(dirfd.unwrap(), &filename, fcntl::AtFlags::empty());
|
||||
assert_stat_results(result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
|
||||
fn test_stat_fstat_lstat() {
|
||||
use nix::sys::stat::{fstat, lstat};
|
||||
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let filename = tempdir.path().join("bar.txt");
|
||||
let linkname = tempdir.path().join("barlink");
|
||||
|
||||
File::create(&filename).unwrap();
|
||||
symlink("bar.txt", &linkname).unwrap();
|
||||
let link = File::open(&linkname).unwrap();
|
||||
|
||||
// should be the same result as calling stat,
|
||||
// since it's a regular file
|
||||
let stat_result = stat(&filename);
|
||||
assert_stat_results(stat_result);
|
||||
|
||||
let lstat_result = lstat(&linkname);
|
||||
assert_lstat_results(lstat_result);
|
||||
|
||||
let fstat_result = fstat(link.as_raw_fd());
|
||||
assert_stat_results(fstat_result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fchmod() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let filename = tempdir.path().join("foo.txt");
|
||||
let file = File::create(&filename).unwrap();
|
||||
|
||||
let mut mode1 = Mode::empty();
|
||||
mode1.insert(Mode::S_IRUSR);
|
||||
mode1.insert(Mode::S_IWUSR);
|
||||
fchmod(file.as_raw_fd(), mode1).unwrap();
|
||||
|
||||
let file_stat1 = stat(&filename).unwrap();
|
||||
assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits());
|
||||
|
||||
let mut mode2 = Mode::empty();
|
||||
mode2.insert(Mode::S_IROTH);
|
||||
fchmod(file.as_raw_fd(), mode2).unwrap();
|
||||
|
||||
let file_stat2 = stat(&filename).unwrap();
|
||||
assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_fchmodat() {
|
||||
let _dr = crate::DirRestore::new();
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let filename = "foo.txt";
|
||||
let fullpath = tempdir.path().join(filename);
|
||||
File::create(&fullpath).unwrap();
|
||||
|
||||
let dirfd =
|
||||
fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
|
||||
.unwrap();
|
||||
|
||||
let mut mode1 = Mode::empty();
|
||||
mode1.insert(Mode::S_IRUSR);
|
||||
mode1.insert(Mode::S_IWUSR);
|
||||
fchmodat(Some(dirfd), filename, mode1, FchmodatFlags::FollowSymlink)
|
||||
.unwrap();
|
||||
|
||||
let file_stat1 = stat(&fullpath).unwrap();
|
||||
assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits());
|
||||
|
||||
chdir(tempdir.path()).unwrap();
|
||||
|
||||
let mut mode2 = Mode::empty();
|
||||
mode2.insert(Mode::S_IROTH);
|
||||
fchmodat(None, filename, mode2, FchmodatFlags::FollowSymlink).unwrap();
|
||||
|
||||
let file_stat2 = stat(&fullpath).unwrap();
|
||||
assert_eq!(file_stat2.st_mode as mode_t & 0o7777, mode2.bits());
|
||||
}
|
||||
|
||||
/// Asserts that the atime and mtime in a file's metadata match expected values.
|
||||
///
|
||||
/// The atime and mtime are expressed with a resolution of seconds because some file systems
|
||||
/// (like macOS's HFS+) do not have higher granularity.
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
fn assert_times_eq(
|
||||
exp_atime_sec: u64,
|
||||
exp_mtime_sec: u64,
|
||||
attr: &fs::Metadata,
|
||||
) {
|
||||
assert_eq!(
|
||||
Duration::new(exp_atime_sec, 0),
|
||||
attr.accessed().unwrap().duration_since(UNIX_EPOCH).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Duration::new(exp_mtime_sec, 0),
|
||||
attr.modified().unwrap().duration_since(UNIX_EPOCH).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
fn test_utimes() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let fullpath = tempdir.path().join("file");
|
||||
drop(File::create(&fullpath).unwrap());
|
||||
|
||||
utimes(&fullpath, &TimeVal::seconds(9990), &TimeVal::seconds(5550))
|
||||
.unwrap();
|
||||
assert_times_eq(9990, 5550, &fs::metadata(&fullpath).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd"
|
||||
))]
|
||||
fn test_lutimes() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let target = tempdir.path().join("target");
|
||||
let fullpath = tempdir.path().join("symlink");
|
||||
drop(File::create(&target).unwrap());
|
||||
symlink(&target, &fullpath).unwrap();
|
||||
|
||||
let exp_target_metadata = fs::symlink_metadata(&target).unwrap();
|
||||
lutimes(&fullpath, &TimeVal::seconds(4560), &TimeVal::seconds(1230))
|
||||
.unwrap();
|
||||
assert_times_eq(4560, 1230, &fs::symlink_metadata(&fullpath).unwrap());
|
||||
|
||||
let target_metadata = fs::symlink_metadata(&target).unwrap();
|
||||
assert_eq!(
|
||||
exp_target_metadata.accessed().unwrap(),
|
||||
target_metadata.accessed().unwrap(),
|
||||
"atime of symlink target was unexpectedly modified"
|
||||
);
|
||||
assert_eq!(
|
||||
exp_target_metadata.modified().unwrap(),
|
||||
target_metadata.modified().unwrap(),
|
||||
"mtime of symlink target was unexpectedly modified"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
fn test_futimens() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let fullpath = tempdir.path().join("file");
|
||||
drop(File::create(&fullpath).unwrap());
|
||||
|
||||
let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty())
|
||||
.unwrap();
|
||||
|
||||
futimens(fd, &TimeSpec::seconds(10), &TimeSpec::seconds(20)).unwrap();
|
||||
assert_times_eq(10, 20, &fs::metadata(&fullpath).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
fn test_utimensat() {
|
||||
let _dr = crate::DirRestore::new();
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let filename = "foo.txt";
|
||||
let fullpath = tempdir.path().join(filename);
|
||||
drop(File::create(&fullpath).unwrap());
|
||||
|
||||
let dirfd =
|
||||
fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
|
||||
.unwrap();
|
||||
|
||||
utimensat(
|
||||
Some(dirfd),
|
||||
filename,
|
||||
&TimeSpec::seconds(12345),
|
||||
&TimeSpec::seconds(678),
|
||||
UtimensatFlags::FollowSymlink,
|
||||
)
|
||||
.unwrap();
|
||||
assert_times_eq(12345, 678, &fs::metadata(&fullpath).unwrap());
|
||||
|
||||
chdir(tempdir.path()).unwrap();
|
||||
|
||||
utimensat(
|
||||
None,
|
||||
filename,
|
||||
&TimeSpec::seconds(500),
|
||||
&TimeSpec::seconds(800),
|
||||
UtimensatFlags::FollowSymlink,
|
||||
)
|
||||
.unwrap();
|
||||
assert_times_eq(500, 800, &fs::metadata(&fullpath).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_mkdirat_success_path() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let filename = "example_subdir";
|
||||
let dirfd =
|
||||
fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
|
||||
.unwrap();
|
||||
mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed");
|
||||
assert!(Path::exists(&tempdir.path().join(filename)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
|
||||
fn test_mkdirat_success_mode() {
|
||||
let expected_bits =
|
||||
stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits();
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let filename = "example_subdir";
|
||||
let dirfd =
|
||||
fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
|
||||
.unwrap();
|
||||
mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed");
|
||||
let permissions = fs::metadata(tempdir.path().join(filename))
|
||||
.unwrap()
|
||||
.permissions();
|
||||
let mode = permissions.mode();
|
||||
assert_eq!(mode as mode_t, expected_bits)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
fn test_mkdirat_fail() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let not_dir_filename = "example_not_dir";
|
||||
let filename = "example_subdir_dir";
|
||||
let dirfd = fcntl::open(
|
||||
&tempdir.path().join(not_dir_filename),
|
||||
fcntl::OFlag::O_CREAT,
|
||||
stat::Mode::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err();
|
||||
assert_eq!(result, Errno::ENOTDIR);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "haiku",
|
||||
target_os = "redox"
|
||||
)))]
|
||||
fn test_mknod() {
|
||||
use stat::{lstat, mknod, SFlag};
|
||||
|
||||
let file_name = "test_file";
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let target = tempdir.path().join(file_name);
|
||||
mknod(&target, SFlag::S_IFREG, Mode::S_IRWXU, 0).unwrap();
|
||||
let mode = lstat(&target).unwrap().st_mode as mode_t;
|
||||
assert_eq!(mode & libc::S_IFREG, libc::S_IFREG);
|
||||
assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "haiku",
|
||||
target_os = "redox"
|
||||
)))]
|
||||
fn test_mknodat() {
|
||||
use fcntl::{AtFlags, OFlag};
|
||||
use nix::dir::Dir;
|
||||
use stat::{fstatat, mknodat, SFlag};
|
||||
|
||||
let file_name = "test_file";
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let target_dir =
|
||||
Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap();
|
||||
mknodat(
|
||||
target_dir.as_raw_fd(),
|
||||
file_name,
|
||||
SFlag::S_IFREG,
|
||||
Mode::S_IRWXU,
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
let mode = fstatat(
|
||||
target_dir.as_raw_fd(),
|
||||
file_name,
|
||||
AtFlags::AT_SYMLINK_NOFOLLOW,
|
||||
)
|
||||
.unwrap()
|
||||
.st_mode as mode_t;
|
||||
assert_eq!(mode & libc::S_IFREG, libc::S_IFREG);
|
||||
assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU);
|
||||
}
|
||||
59
third-party/vendor/nix/test/test_time.rs
vendored
Normal file
59
third-party/vendor/nix/test/test_time.rs
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
))]
|
||||
use nix::time::clock_getcpuclockid;
|
||||
use nix::time::{clock_gettime, ClockId};
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[test]
|
||||
pub fn test_clock_getres() {
|
||||
nix::time::clock_getres(ClockId::CLOCK_REALTIME).expect("assertion failed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_clock_gettime() {
|
||||
clock_gettime(ClockId::CLOCK_REALTIME).expect("assertion failed");
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
))]
|
||||
#[test]
|
||||
pub fn test_clock_getcpuclockid() {
|
||||
let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap();
|
||||
clock_gettime(clock_id).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
#[test]
|
||||
pub fn test_clock_id_res() {
|
||||
ClockId::CLOCK_REALTIME.res().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_clock_id_now() {
|
||||
ClockId::CLOCK_REALTIME.now().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
))]
|
||||
#[test]
|
||||
pub fn test_clock_id_pid_cpu_clock_id() {
|
||||
ClockId::pid_cpu_clock_id(nix::unistd::Pid::this())
|
||||
.map(ClockId::now)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
}
|
||||
102
third-party/vendor/nix/test/test_timer.rs
vendored
Normal file
102
third-party/vendor/nix/test/test_timer.rs
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
use nix::sys::signal::{
|
||||
sigaction, SaFlags, SigAction, SigEvent, SigHandler, SigSet, SigevNotify,
|
||||
Signal,
|
||||
};
|
||||
use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags};
|
||||
use nix::time::ClockId;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
const SIG: Signal = Signal::SIGALRM;
|
||||
static ALARM_CALLED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub extern "C" fn handle_sigalarm(raw_signal: libc::c_int) {
|
||||
let signal = Signal::try_from(raw_signal).unwrap();
|
||||
if signal == SIG {
|
||||
ALARM_CALLED.store(true, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alarm_fires() {
|
||||
// Avoid interfering with other signal using tests by taking a mutex shared
|
||||
// among other tests in this crate.
|
||||
let _m = crate::SIGNAL_MTX.lock();
|
||||
const TIMER_PERIOD: Duration = Duration::from_millis(100);
|
||||
|
||||
//
|
||||
// Setup
|
||||
//
|
||||
|
||||
// Create a handler for the test signal, `SIG`. The handler is responsible
|
||||
// for flipping `ALARM_CALLED`.
|
||||
let handler = SigHandler::Handler(handle_sigalarm);
|
||||
let signal_action =
|
||||
SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty());
|
||||
let old_handler = unsafe {
|
||||
sigaction(SIG, &signal_action)
|
||||
.expect("unable to set signal handler for alarm")
|
||||
};
|
||||
|
||||
// Create the timer. We use the monotonic clock here, though any would do
|
||||
// really. The timer is set to fire every 250 milliseconds with no delay for
|
||||
// the initial firing.
|
||||
let clockid = ClockId::CLOCK_MONOTONIC;
|
||||
let sigevent = SigEvent::new(SigevNotify::SigevSignal {
|
||||
signal: SIG,
|
||||
si_value: 0,
|
||||
});
|
||||
let mut timer =
|
||||
Timer::new(clockid, sigevent).expect("failed to create timer");
|
||||
let expiration = Expiration::Interval(TIMER_PERIOD.into());
|
||||
let flags = TimerSetTimeFlags::empty();
|
||||
timer.set(expiration, flags).expect("could not set timer");
|
||||
|
||||
//
|
||||
// Test
|
||||
//
|
||||
|
||||
// Determine that there's still an expiration tracked by the
|
||||
// timer. Depending on when this runs either an `Expiration::Interval` or
|
||||
// `Expiration::IntervalDelayed` will be present. That is, if the timer has
|
||||
// not fired yet we'll get our original `expiration`, else the one that
|
||||
// represents a delay to the next expiration. We're only interested in the
|
||||
// timer still being extant.
|
||||
match timer.get() {
|
||||
Ok(Some(exp)) => assert!(matches!(
|
||||
exp,
|
||||
Expiration::Interval(..) | Expiration::IntervalDelayed(..)
|
||||
)),
|
||||
_ => panic!("timer lost its expiration"),
|
||||
}
|
||||
|
||||
// Wait for 2 firings of the alarm before checking that it has fired and
|
||||
// been handled at least the once. If we wait for 3 seconds and the handler
|
||||
// is never called something has gone sideways and the test fails.
|
||||
let starttime = Instant::now();
|
||||
loop {
|
||||
thread::sleep(2 * TIMER_PERIOD);
|
||||
if ALARM_CALLED.load(Ordering::Acquire) {
|
||||
break;
|
||||
}
|
||||
if starttime.elapsed() > Duration::from_secs(3) {
|
||||
panic!("Timeout waiting for SIGALRM");
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup:
|
||||
// 1) deregister the OS's timer.
|
||||
// 2) Wait for a full timer period, since POSIX does not require that
|
||||
// disabling the timer will clear pending signals, and on NetBSD at least
|
||||
// it does not.
|
||||
// 2) Replace the old signal handler now that we've completed the test. If
|
||||
// the test fails this process panics, so the fact we might not get here
|
||||
// is okay.
|
||||
drop(timer);
|
||||
thread::sleep(TIMER_PERIOD);
|
||||
unsafe {
|
||||
sigaction(SIG, &old_handler).expect("unable to reset signal handler");
|
||||
}
|
||||
}
|
||||
1378
third-party/vendor/nix/test/test_unistd.rs
vendored
Normal file
1378
third-party/vendor/nix/test/test_unistd.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue