summaryrefslogtreecommitdiffstats
path: root/third_party/rust/nix/test/sys
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/nix/test/sys')
-rw-r--r--third_party/rust/nix/test/sys/mod.rs54
-rw-r--r--third_party/rust/nix/test/sys/test_aio.rs66
-rw-r--r--third_party/rust/nix/test/sys/test_aio_drop.rs3
-rw-r--r--third_party/rust/nix/test/sys/test_event.rs41
-rw-r--r--third_party/rust/nix/test/sys/test_fanotify.rs149
-rw-r--r--third_party/rust/nix/test/sys/test_ioctl.rs33
-rw-r--r--third_party/rust/nix/test/sys/test_mman.rs55
-rw-r--r--third_party/rust/nix/test/sys/test_ptrace.rs12
-rw-r--r--third_party/rust/nix/test/sys/test_resource.rs43
-rw-r--r--third_party/rust/nix/test/sys/test_select.rs247
-rw-r--r--third_party/rust/nix/test/sys/test_signal.rs320
-rw-r--r--third_party/rust/nix/test/sys/test_signalfd.rs63
-rw-r--r--third_party/rust/nix/test/sys/test_socket.rs474
-rw-r--r--third_party/rust/nix/test/sys/test_sockopt.rs454
-rw-r--r--third_party/rust/nix/test/sys/test_statfs.rs99
-rw-r--r--third_party/rust/nix/test/sys/test_statvfs.rs13
-rw-r--r--third_party/rust/nix/test/sys/test_termios.rs13
-rw-r--r--third_party/rust/nix/test/sys/test_time.rs91
-rw-r--r--third_party/rust/nix/test/sys/test_timer.rs102
-rw-r--r--third_party/rust/nix/test/sys/test_uio.rs36
-rw-r--r--third_party/rust/nix/test/sys/test_utsname.rs17
-rw-r--r--third_party/rust/nix/test/sys/test_wait.rs16
22 files changed, 2128 insertions, 273 deletions
diff --git a/third_party/rust/nix/test/sys/mod.rs b/third_party/rust/nix/test/sys/mod.rs
index 20312120a6..fb3f6be0e5 100644
--- a/third_party/rust/nix/test/sys/mod.rs
+++ b/third_party/rust/nix/test/sys/mod.rs
@@ -7,16 +7,16 @@ mod test_signal;
// cases on DragonFly.
#[cfg(any(
target_os = "freebsd",
- target_os = "ios",
+ apple_targets,
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"
+ target_os = "haiku",
+ target_os = "hurd"
)))]
mod test_ioctl;
#[cfg(not(target_os = "redox"))]
@@ -30,7 +30,7 @@ mod test_socket;
#[cfg(not(any(target_os = "redox")))]
mod test_sockopt;
mod test_stat;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
mod test_sysinfo;
#[cfg(not(any(
target_os = "redox",
@@ -41,20 +41,44 @@ mod test_termios;
mod test_uio;
mod test_wait;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
mod test_epoll;
#[cfg(target_os = "linux")]
+mod test_fanotify;
+#[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"
-))]
+
+#[cfg(any(linux_android, freebsdlike, netbsdlike, apple_targets))]
mod test_ptrace;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
mod test_timerfd;
+
+#[cfg(all(
+ any(
+ target_os = "freebsd",
+ solarish,
+ target_os = "linux",
+ target_os = "netbsd"
+ ),
+ feature = "time",
+ feature = "signal"
+))]
+mod test_timer;
+
+#[cfg(bsd)]
+mod test_event;
+mod test_statvfs;
+mod test_time;
+mod test_utsname;
+
+#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "openbsd"))]
+mod test_statfs;
+
+#[cfg(not(any(
+ target_os = "redox",
+ target_os = "fuchsia",
+ solarish,
+ target_os = "haiku"
+)))]
+mod test_resource;
diff --git a/third_party/rust/nix/test/sys/test_aio.rs b/third_party/rust/nix/test/sys/test_aio.rs
index 5035b5a08f..ba5ad02ec3 100644
--- a/third_party/rust/nix/test/sys/test_aio.rs
+++ b/third_party/rust/nix/test/sys/test_aio.rs
@@ -67,7 +67,7 @@ mod aio_fsync {
// Skip on Linux, because Linux's AIO implementation can't detect errors
// synchronously
#[test]
- #[cfg(any(target_os = "freebsd", target_os = "macos"))]
+ #[cfg(any(target_os = "freebsd", apple_targets))]
fn error() {
use std::mem;
@@ -157,7 +157,7 @@ mod aio_read {
// Skip on Linux, because Linux's AIO implementation can't detect errors
// synchronously
#[test]
- #[cfg(any(target_os = "freebsd", target_os = "macos"))]
+ #[cfg(any(target_os = "freebsd", apple_targets))]
fn error() {
const INITIAL: &[u8] = b"abcdef123456";
let mut rbuf = vec![0; 4];
@@ -411,7 +411,7 @@ mod aio_write {
// Skip on Linux, because Linux's AIO implementation can't detect errors
// synchronously
#[test]
- #[cfg(any(target_os = "freebsd", target_os = "macos"))]
+ #[cfg(any(target_os = "freebsd", apple_targets))]
fn error() {
let wbuf = "CDEF".to_string().into_bytes();
let mut aiow = Box::pin(AioWrite::new(
@@ -498,7 +498,9 @@ mod aio_writev {
any(
all(target_env = "musl", target_arch = "x86_64"),
target_arch = "mips",
- target_arch = "mips64"
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
),
ignore
)]
@@ -567,12 +569,6 @@ fn test_aio_cancel_all() {
}
#[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";
@@ -622,3 +618,53 @@ fn test_aio_suspend() {
assert_eq!(wcb.as_mut().aio_return().unwrap(), WBUF.len());
assert_eq!(rcb.as_mut().aio_return().unwrap(), rlen);
}
+
+/// aio_suspend relies on casting Rust Aio* struct pointers to libc::aiocb
+/// pointers. This test ensures that such casts are valid.
+#[test]
+fn casting() {
+ let sev = SigevNotify::SigevNone;
+ let aiof = AioFsync::new(666, AioFsyncMode::O_SYNC, 0, sev);
+ assert_eq!(
+ aiof.as_ref() as *const libc::aiocb,
+ &aiof as *const AioFsync as *const libc::aiocb
+ );
+
+ let mut rbuf = [];
+ let aior = AioRead::new(666, 0, &mut rbuf, 0, sev);
+ assert_eq!(
+ aior.as_ref() as *const libc::aiocb,
+ &aior as *const AioRead as *const libc::aiocb
+ );
+
+ let wbuf = [];
+ let aiow = AioWrite::new(666, 0, &wbuf, 0, sev);
+ assert_eq!(
+ aiow.as_ref() as *const libc::aiocb,
+ &aiow as *const AioWrite as *const libc::aiocb
+ );
+}
+
+#[cfg(target_os = "freebsd")]
+#[test]
+fn casting_vectored() {
+ use std::io::{IoSlice, IoSliceMut};
+
+ let sev = SigevNotify::SigevNone;
+
+ let mut rbuf = [];
+ let mut rbufs = [IoSliceMut::new(&mut rbuf)];
+ let aiorv = AioReadv::new(666, 0, &mut rbufs[..], 0, sev);
+ assert_eq!(
+ aiorv.as_ref() as *const libc::aiocb,
+ &aiorv as *const AioReadv as *const libc::aiocb
+ );
+
+ let wbuf = [];
+ let wbufs = [IoSlice::new(&wbuf)];
+ let aiowv = AioWritev::new(666, 0, &wbufs, 0, sev);
+ assert_eq!(
+ aiowv.as_ref() as *const libc::aiocb,
+ &aiowv as *const AioWritev as *const libc::aiocb
+ );
+}
diff --git a/third_party/rust/nix/test/sys/test_aio_drop.rs b/third_party/rust/nix/test/sys/test_aio_drop.rs
index bbe6623fd7..54106dd168 100644
--- a/third_party/rust/nix/test/sys/test_aio_drop.rs
+++ b/third_party/rust/nix/test/sys/test_aio_drop.rs
@@ -8,8 +8,7 @@
not(target_env = "uclibc"),
any(
target_os = "linux",
- target_os = "ios",
- target_os = "macos",
+ apple_targets,
target_os = "freebsd",
target_os = "netbsd"
)
diff --git a/third_party/rust/nix/test/sys/test_event.rs b/third_party/rust/nix/test/sys/test_event.rs
new file mode 100644
index 0000000000..a10b1e5d12
--- /dev/null
+++ b/third_party/rust/nix/test/sys/test_event.rs
@@ -0,0 +1,41 @@
+use libc::intptr_t;
+use nix::sys::event::{EventFilter, EventFlag, FilterFlag, KEvent};
+
+#[test]
+fn test_struct_kevent() {
+ use std::mem;
+
+ let udata: intptr_t = 12345;
+ let data: intptr_t = 0x1337;
+
+ let actual = KEvent::new(
+ 0xdead_beef,
+ EventFilter::EVFILT_READ,
+ EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
+ FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
+ data,
+ udata,
+ );
+ assert_eq!(0xdead_beef, actual.ident());
+ assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap());
+ assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits());
+ assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits());
+ assert_eq!(data, actual.data());
+ assert_eq!(udata, actual.udata());
+ assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>());
+}
+
+#[test]
+fn test_kevent_filter() {
+ let udata: intptr_t = 12345;
+
+ let actual = KEvent::new(
+ 0xdead_beef,
+ EventFilter::EVFILT_READ,
+ EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
+ FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
+ 0x1337,
+ udata,
+ );
+ assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap());
+}
diff --git a/third_party/rust/nix/test/sys/test_fanotify.rs b/third_party/rust/nix/test/sys/test_fanotify.rs
new file mode 100644
index 0000000000..20226c272a
--- /dev/null
+++ b/third_party/rust/nix/test/sys/test_fanotify.rs
@@ -0,0 +1,149 @@
+use crate::*;
+use nix::sys::fanotify::{
+ EventFFlags, Fanotify, FanotifyResponse, InitFlags, MarkFlags, MaskFlags,
+ Response,
+};
+use std::fs::{read_link, File, OpenOptions};
+use std::io::ErrorKind;
+use std::io::{Read, Write};
+use std::os::fd::AsRawFd;
+use std::thread;
+
+#[test]
+/// Run fanotify tests sequentially to avoid tmp files races
+pub fn test_fanotify() {
+ require_capability!("test_fanotify", CAP_SYS_ADMIN);
+
+ test_fanotify_notifications();
+ test_fanotify_responses();
+}
+
+fn test_fanotify_notifications() {
+ let group =
+ Fanotify::init(InitFlags::FAN_CLASS_NOTIF, EventFFlags::O_RDONLY)
+ .unwrap();
+ let tempdir = tempfile::tempdir().unwrap();
+ let tempfile = tempdir.path().join("test");
+ OpenOptions::new()
+ .write(true)
+ .create_new(true)
+ .open(&tempfile)
+ .unwrap();
+
+ group
+ .mark(
+ MarkFlags::FAN_MARK_ADD,
+ MaskFlags::FAN_OPEN | MaskFlags::FAN_MODIFY | MaskFlags::FAN_CLOSE,
+ None,
+ Some(&tempfile),
+ )
+ .unwrap();
+
+ // modify test file
+ {
+ let mut f = OpenOptions::new().write(true).open(&tempfile).unwrap();
+ f.write_all(b"hello").unwrap();
+ }
+
+ let mut events = group.read_events().unwrap();
+ assert_eq!(events.len(), 1, "should have read exactly one event");
+ let event = events.pop().unwrap();
+ assert!(event.check_version());
+ assert_eq!(
+ event.mask(),
+ MaskFlags::FAN_OPEN
+ | MaskFlags::FAN_MODIFY
+ | MaskFlags::FAN_CLOSE_WRITE
+ );
+ let fd_opt = event.fd();
+ let fd = fd_opt.as_ref().unwrap();
+ let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap();
+ assert_eq!(path, tempfile);
+
+ // read test file
+ {
+ let mut f = File::open(&tempfile).unwrap();
+ let mut s = String::new();
+ f.read_to_string(&mut s).unwrap();
+ }
+
+ let mut events = group.read_events().unwrap();
+ assert_eq!(events.len(), 1, "should have read exactly one event");
+ let event = events.pop().unwrap();
+ assert!(event.check_version());
+ assert_eq!(
+ event.mask(),
+ MaskFlags::FAN_OPEN | MaskFlags::FAN_CLOSE_NOWRITE
+ );
+ let fd_opt = event.fd();
+ let fd = fd_opt.as_ref().unwrap();
+ let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap();
+ assert_eq!(path, tempfile);
+}
+
+fn test_fanotify_responses() {
+ let group =
+ Fanotify::init(InitFlags::FAN_CLASS_CONTENT, EventFFlags::O_RDONLY)
+ .unwrap();
+ let tempdir = tempfile::tempdir().unwrap();
+ let tempfile = tempdir.path().join("test");
+ OpenOptions::new()
+ .write(true)
+ .create_new(true)
+ .open(&tempfile)
+ .unwrap();
+
+ group
+ .mark(
+ MarkFlags::FAN_MARK_ADD,
+ MaskFlags::FAN_OPEN_PERM,
+ None,
+ Some(&tempfile),
+ )
+ .unwrap();
+
+ let file_thread = thread::spawn({
+ let tempfile = tempfile.clone();
+
+ move || {
+ // first open, should fail
+ let Err(e) = File::open(&tempfile) else {
+ panic!("The first open should fail");
+ };
+ assert_eq!(e.kind(), ErrorKind::PermissionDenied);
+
+ // second open, should succeed
+ File::open(&tempfile).unwrap();
+ }
+ });
+
+ // Deny the first open try
+ let mut events = group.read_events().unwrap();
+ assert_eq!(events.len(), 1, "should have read exactly one event");
+ let event = events.pop().unwrap();
+ assert!(event.check_version());
+ assert_eq!(event.mask(), MaskFlags::FAN_OPEN_PERM);
+ let fd_opt = event.fd();
+ let fd = fd_opt.as_ref().unwrap();
+ let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap();
+ assert_eq!(path, tempfile);
+ group
+ .write_response(FanotifyResponse::new(*fd, Response::FAN_DENY))
+ .unwrap();
+
+ // Allow the second open try
+ let mut events = group.read_events().unwrap();
+ assert_eq!(events.len(), 1, "should have read exactly one event");
+ let event = events.pop().unwrap();
+ assert!(event.check_version());
+ assert_eq!(event.mask(), MaskFlags::FAN_OPEN_PERM);
+ let fd_opt = event.fd();
+ let fd = fd_opt.as_ref().unwrap();
+ let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap();
+ assert_eq!(path, tempfile);
+ group
+ .write_response(FanotifyResponse::new(*fd, Response::FAN_ALLOW))
+ .unwrap();
+
+ file_thread.join().unwrap();
+}
diff --git a/third_party/rust/nix/test/sys/test_ioctl.rs b/third_party/rust/nix/test/sys/test_ioctl.rs
index 40f60cfdbc..08843bf61c 100644
--- a/third_party/rust/nix/test/sys/test_ioctl.rs
+++ b/third_party/rust/nix/test/sys/test_ioctl.rs
@@ -28,7 +28,7 @@ ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32);
// 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"))]
+#[cfg(linux_android)]
mod linux {
// The cast is not unnecessary on all platforms.
#[allow(clippy::unnecessary_cast)]
@@ -36,7 +36,9 @@ mod linux {
fn test_op_none() {
if cfg!(any(
target_arch = "mips",
+ target_arch = "mips32r6",
target_arch = "mips64",
+ target_arch = "mips64r6",
target_arch = "powerpc",
target_arch = "powerpc64"
)) {
@@ -54,7 +56,9 @@ mod linux {
fn test_op_write() {
if cfg!(any(
target_arch = "mips",
+ target_arch = "mips32r6",
target_arch = "mips64",
+ target_arch = "mips64r6",
target_arch = "powerpc",
target_arch = "powerpc64"
)) {
@@ -69,7 +73,11 @@ mod linux {
#[cfg(target_pointer_width = "64")]
#[test]
fn test_op_write_64() {
- if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) {
+ if cfg!(any(
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "powerpc64"
+ )) {
assert_eq!(
request_code_write!(b'z', 10, 1u64 << 32) as u32,
0x8000_7A0A
@@ -88,7 +96,9 @@ mod linux {
fn test_op_read() {
if cfg!(any(
target_arch = "mips",
+ target_arch = "mips32r6",
target_arch = "mips64",
+ target_arch = "mips64r6",
target_arch = "powerpc",
target_arch = "powerpc64"
)) {
@@ -103,7 +113,11 @@ mod linux {
#[cfg(target_pointer_width = "64")]
#[test]
fn test_op_read_64() {
- if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) {
+ if cfg!(any(
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "powerpc64"
+ )) {
assert_eq!(
request_code_read!(b'z', 10, 1u64 << 32) as u32,
0x4000_7A0A
@@ -134,14 +148,7 @@ mod linux {
}
}
-#[cfg(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd"
-))]
+#[cfg(bsd)]
mod bsd {
#[test]
fn test_op_none() {
@@ -149,7 +156,7 @@ mod bsd {
assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
}
- #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+ #[cfg(freebsdlike)]
#[test]
fn test_op_write_int() {
assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604);
@@ -193,7 +200,7 @@ mod bsd {
}
}
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
mod linux_ioctls {
use std::mem;
use std::os::unix::io::AsRawFd;
diff --git a/third_party/rust/nix/test/sys/test_mman.rs b/third_party/rust/nix/test/sys/test_mman.rs
index b4674e53fa..3689f642be 100644
--- a/third_party/rust/nix/test/sys/test_mman.rs
+++ b/third_party/rust/nix/test/sys/test_mman.rs
@@ -1,44 +1,44 @@
-use nix::sys::mman::{mmap, MapFlags, ProtFlags};
-use std::{num::NonZeroUsize, os::unix::io::BorrowedFd};
+#![allow(clippy::redundant_slicing)]
+
+use nix::sys::mman::{mmap_anonymous, MapFlags, ProtFlags};
+use std::num::NonZeroUsize;
#[test]
fn test_mmap_anonymous() {
unsafe {
- let ptr = mmap::<BorrowedFd>(
+ let mut ptr = mmap_anonymous(
None,
NonZeroUsize::new(1).unwrap(),
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
- MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
- None,
- 0,
+ MapFlags::MAP_PRIVATE,
)
- .unwrap() as *mut u8;
- assert_eq!(*ptr, 0x00u8);
- *ptr = 0xffu8;
- assert_eq!(*ptr, 0xffu8);
+ .unwrap()
+ .cast::<u8>();
+ assert_eq!(*ptr.as_ref(), 0x00u8);
+ *ptr.as_mut() = 0xffu8;
+ assert_eq!(*ptr.as_ref(), 0xffu8);
}
}
#[test]
#[cfg(any(target_os = "linux", target_os = "netbsd"))]
fn test_mremap_grow() {
- use nix::libc::{c_void, size_t};
+ use nix::libc::size_t;
use nix::sys::mman::{mremap, MRemapFlags};
+ use std::ptr::NonNull;
const ONE_K: size_t = 1024;
let one_k_non_zero = NonZeroUsize::new(ONE_K).unwrap();
let slice: &mut [u8] = unsafe {
- let mem = mmap::<BorrowedFd>(
+ let mem = mmap_anonymous(
None,
one_k_non_zero,
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
- MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE,
- None,
- 0,
+ MapFlags::MAP_PRIVATE,
)
.unwrap();
- std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
+ std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
};
assert_eq!(slice[ONE_K - 1], 0x00);
slice[ONE_K - 1] = 0xFF;
@@ -47,7 +47,7 @@ fn test_mremap_grow() {
let slice: &mut [u8] = unsafe {
#[cfg(target_os = "linux")]
let mem = mremap(
- slice.as_mut_ptr() as *mut c_void,
+ NonNull::from(&mut slice[..]).cast(),
ONE_K,
10 * ONE_K,
MRemapFlags::MREMAP_MAYMOVE,
@@ -56,14 +56,14 @@ fn test_mremap_grow() {
.unwrap();
#[cfg(target_os = "netbsd")]
let mem = mremap(
- slice.as_mut_ptr() as *mut c_void,
+ NonNull::from(&mut slice[..]).cast(),
ONE_K,
10 * ONE_K,
MRemapFlags::MAP_REMAPDUP,
None,
)
.unwrap();
- std::slice::from_raw_parts_mut(mem as *mut u8, 10 * ONE_K)
+ std::slice::from_raw_parts_mut(mem.cast().as_ptr(), 10 * ONE_K)
};
// The first KB should still have the old data in it.
@@ -80,23 +80,22 @@ fn test_mremap_grow() {
// 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::libc::size_t;
use nix::sys::mman::{mremap, MRemapFlags};
use std::num::NonZeroUsize;
+ use std::ptr::NonNull;
const ONE_K: size_t = 1024;
let ten_one_k = NonZeroUsize::new(10 * ONE_K).unwrap();
let slice: &mut [u8] = unsafe {
- let mem = mmap::<BorrowedFd>(
+ let mem = mmap_anonymous(
None,
ten_one_k,
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
- MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE,
- None,
- 0,
+ MapFlags::MAP_PRIVATE,
)
.unwrap();
- std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
+ std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
};
assert_eq!(slice[ONE_K - 1], 0x00);
slice[ONE_K - 1] = 0xFF;
@@ -104,7 +103,7 @@ fn test_mremap_shrink() {
let slice: &mut [u8] = unsafe {
let mem = mremap(
- slice.as_mut_ptr() as *mut c_void,
+ NonNull::from(&mut slice[..]).cast(),
ten_one_k.into(),
ONE_K,
MRemapFlags::empty(),
@@ -113,8 +112,8 @@ fn test_mremap_shrink() {
.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)
+ assert_eq!(mem.as_ptr(), NonNull::from(&mut slice[..]).cast().as_ptr());
+ std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
};
// The first KB should still be accessible and have the old data in it.
diff --git a/third_party/rust/nix/test/sys/test_ptrace.rs b/third_party/rust/nix/test/sys/test_ptrace.rs
index 530560fe17..246b35445d 100644
--- a/third_party/rust/nix/test/sys/test_ptrace.rs
+++ b/third_party/rust/nix/test/sys/test_ptrace.rs
@@ -6,11 +6,11 @@
use memoffset::offset_of;
use nix::errno::Errno;
use nix::sys::ptrace;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
use nix::sys::ptrace::Options;
use nix::unistd::getpid;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
use std::mem;
use crate::*;
@@ -28,7 +28,7 @@ fn test_ptrace() {
// Just make sure ptrace_setoptions can be called at all, for now.
#[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
fn test_ptrace_setoptions() {
require_capability!("test_ptrace_setoptions", CAP_SYS_PTRACE);
let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD)
@@ -38,7 +38,7 @@ fn test_ptrace_setoptions() {
// Just make sure ptrace_getevent can be called at all, for now.
#[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
fn test_ptrace_getevent() {
require_capability!("test_ptrace_getevent", CAP_SYS_PTRACE);
let err = ptrace::getevent(getpid()).unwrap_err();
@@ -47,7 +47,7 @@ fn test_ptrace_getevent() {
// Just make sure ptrace_getsiginfo can be called at all, for now.
#[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
fn test_ptrace_getsiginfo() {
require_capability!("test_ptrace_getsiginfo", CAP_SYS_PTRACE);
if let Err(Errno::EOPNOTSUPP) = ptrace::getsiginfo(getpid()) {
@@ -57,7 +57,7 @@ fn test_ptrace_getsiginfo() {
// Just make sure ptrace_setsiginfo can be called at all, for now.
#[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
fn test_ptrace_setsiginfo() {
require_capability!("test_ptrace_setsiginfo", CAP_SYS_PTRACE);
let siginfo = unsafe { mem::zeroed() };
diff --git a/third_party/rust/nix/test/sys/test_resource.rs b/third_party/rust/nix/test/sys/test_resource.rs
new file mode 100644
index 0000000000..8b12a9495b
--- /dev/null
+++ b/third_party/rust/nix/test/sys/test_resource.rs
@@ -0,0 +1,43 @@
+use nix::sys::resource::{getrlimit, setrlimit, Resource};
+use nix::sys::resource::{getrusage, UsageWho};
+
+/// 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]
+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);
+}
+
+#[test]
+pub fn test_self_cpu_time() {
+ // Make sure some CPU time is used.
+ let mut numbers: Vec<i32> = (1..1_000_000).collect();
+ numbers.iter_mut().for_each(|item| *item *= 2);
+
+ // FIXME: this is here to help ensure the compiler does not optimize the whole
+ // thing away. Replace the assert with test::black_box once stabilized.
+ assert_eq!(numbers[100..200].iter().sum::<i32>(), 30_100);
+
+ let usage = getrusage(UsageWho::RUSAGE_SELF)
+ .expect("Failed to call getrusage for SELF");
+ let rusage = usage.as_ref();
+
+ let user = usage.user_time();
+ assert!(user.tv_sec() > 0 || user.tv_usec() > 0);
+ assert_eq!(user.tv_sec(), rusage.ru_utime.tv_sec);
+ assert_eq!(user.tv_usec(), rusage.ru_utime.tv_usec);
+}
diff --git a/third_party/rust/nix/test/sys/test_select.rs b/third_party/rust/nix/test/sys/test_select.rs
index 79f75de3b4..e39a31923a 100644
--- a/third_party/rust/nix/test/sys/test_select.rs
+++ b/third_party/rust/nix/test/sys/test_select.rs
@@ -1,22 +1,20 @@
use nix::sys::select::*;
use nix::sys::signal::SigSet;
-use nix::sys::time::{TimeSpec, TimeValLike};
+use nix::sys::time::{TimeSpec, TimeVal, TimeValLike};
use nix::unistd::{pipe, write};
-use std::os::unix::io::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd};
+use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
#[test]
pub fn test_pselect() {
let _mtx = crate::SIGNAL_MTX.lock();
let (r1, w1) = pipe().unwrap();
- write(w1, b"hi!").unwrap();
- let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
+ write(&w1, b"hi!").unwrap();
let (r2, _w2) = pipe().unwrap();
- let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
let mut fd_set = FdSet::new();
- fd_set.insert(&r1);
- fd_set.insert(&r2);
+ fd_set.insert(r1.as_fd());
+ fd_set.insert(r2.as_fd());
let timeout = TimeSpec::seconds(10);
let sigmask = SigSet::empty();
@@ -24,21 +22,19 @@ pub fn test_pselect() {
1,
pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap()
);
- assert!(fd_set.contains(&r1));
- assert!(!fd_set.contains(&r2));
+ assert!(fd_set.contains(r1.as_fd()));
+ assert!(!fd_set.contains(r2.as_fd()));
}
#[test]
pub fn test_pselect_nfds2() {
let (r1, w1) = pipe().unwrap();
- write(w1, b"hi!").unwrap();
- let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
+ write(&w1, b"hi!").unwrap();
let (r2, _w2) = pipe().unwrap();
- let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
let mut fd_set = FdSet::new();
- fd_set.insert(&r1);
- fd_set.insert(&r2);
+ fd_set.insert(r1.as_fd());
+ fd_set.insert(r2.as_fd());
let timeout = TimeSpec::seconds(10);
assert_eq!(
@@ -53,8 +49,8 @@ pub fn test_pselect_nfds2() {
)
.unwrap()
);
- assert!(fd_set.contains(&r1));
- assert!(!fd_set.contains(&r2));
+ assert!(fd_set.contains(r1.as_fd()));
+ assert!(!fd_set.contains(r2.as_fd()));
}
macro_rules! generate_fdset_bad_fd_tests {
@@ -64,7 +60,7 @@ macro_rules! generate_fdset_bad_fd_tests {
#[should_panic]
fn $method() {
let bad_fd = unsafe{BorrowedFd::borrow_raw($fd)};
- FdSet::new().$method(&bad_fd);
+ FdSet::new().$method(bad_fd);
}
)*
}
@@ -72,7 +68,6 @@ macro_rules! generate_fdset_bad_fd_tests {
mod test_fdset_too_large_fd {
use super::*;
- use std::convert::TryInto;
generate_fdset_bad_fd_tests!(
FD_SETSIZE.try_into().unwrap(),
insert,
@@ -80,3 +75,219 @@ mod test_fdset_too_large_fd {
contains,
);
}
+
+#[test]
+fn fdset_insert() {
+ let mut fd_set = FdSet::new();
+
+ for i in 0..FD_SETSIZE {
+ let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+ assert!(!fd_set.contains(borrowed_i));
+ }
+
+ let fd_seven = unsafe { BorrowedFd::borrow_raw(7) };
+ fd_set.insert(fd_seven);
+
+ assert!(fd_set.contains(fd_seven));
+}
+
+#[test]
+fn fdset_remove() {
+ let mut fd_set = FdSet::new();
+
+ for i in 0..FD_SETSIZE {
+ let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+ assert!(!fd_set.contains(borrowed_i));
+ }
+
+ let fd_seven = unsafe { BorrowedFd::borrow_raw(7) };
+ fd_set.insert(fd_seven);
+ fd_set.remove(fd_seven);
+
+ for i in 0..FD_SETSIZE {
+ let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+ assert!(!fd_set.contains(borrowed_i));
+ }
+}
+
+#[test]
+#[allow(non_snake_case)]
+fn fdset_clear() {
+ let mut fd_set = FdSet::new();
+ let fd_one = unsafe { BorrowedFd::borrow_raw(1) };
+ let fd_FD_SETSIZE_divided_by_two =
+ unsafe { BorrowedFd::borrow_raw((FD_SETSIZE / 2) as RawFd) };
+ let fd_FD_SETSIZE_minus_one =
+ unsafe { BorrowedFd::borrow_raw((FD_SETSIZE - 1) as RawFd) };
+ fd_set.insert(fd_one);
+ fd_set.insert(fd_FD_SETSIZE_divided_by_two);
+ fd_set.insert(fd_FD_SETSIZE_minus_one);
+
+ fd_set.clear();
+
+ for i in 0..FD_SETSIZE {
+ let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+ assert!(!fd_set.contains(borrowed_i));
+ }
+}
+
+#[test]
+fn fdset_highest() {
+ let mut set = FdSet::new();
+ assert_eq!(
+ set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+ None
+ );
+ let fd_zero = unsafe { BorrowedFd::borrow_raw(0) };
+ let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) };
+ set.insert(fd_zero);
+ assert_eq!(
+ set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+ Some(0)
+ );
+ set.insert(fd_ninety);
+ assert_eq!(
+ set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+ Some(90)
+ );
+ set.remove(fd_zero);
+ assert_eq!(
+ set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+ Some(90)
+ );
+ set.remove(fd_ninety);
+ assert_eq!(
+ set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+ None
+ );
+
+ let fd_four = unsafe { BorrowedFd::borrow_raw(4) };
+ let fd_five = unsafe { BorrowedFd::borrow_raw(5) };
+ let fd_seven = unsafe { BorrowedFd::borrow_raw(7) };
+ set.insert(fd_four);
+ set.insert(fd_five);
+ set.insert(fd_seven);
+ assert_eq!(
+ set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+ Some(7)
+ );
+}
+
+#[test]
+fn fdset_fds() {
+ let mut set = FdSet::new();
+ let fd_zero = unsafe { BorrowedFd::borrow_raw(0) };
+ let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) };
+ assert_eq!(
+ set.fds(None)
+ .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+ .collect::<Vec<_>>(),
+ vec![]
+ );
+ set.insert(fd_zero);
+ assert_eq!(
+ set.fds(None)
+ .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+ .collect::<Vec<_>>(),
+ vec![0]
+ );
+ set.insert(fd_ninety);
+ assert_eq!(
+ set.fds(None)
+ .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+ .collect::<Vec<_>>(),
+ vec![0, 90]
+ );
+
+ // highest limit
+ assert_eq!(
+ set.fds(Some(89))
+ .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+ .collect::<Vec<_>>(),
+ vec![0]
+ );
+ assert_eq!(
+ set.fds(Some(90))
+ .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+ .collect::<Vec<_>>(),
+ vec![0, 90]
+ );
+}
+
+#[test]
+fn test_select() {
+ let (r1, w1) = pipe().unwrap();
+ let (r2, _w2) = pipe().unwrap();
+
+ write(&w1, b"hi!").unwrap();
+ let mut fd_set = FdSet::new();
+ fd_set.insert(r1.as_fd());
+ fd_set.insert(r2.as_fd());
+
+ let mut timeout = TimeVal::seconds(10);
+ assert_eq!(
+ 1,
+ select(None, &mut fd_set, None, None, &mut timeout).unwrap()
+ );
+ assert!(fd_set.contains(r1.as_fd()));
+ assert!(!fd_set.contains(r2.as_fd()));
+}
+
+#[test]
+fn test_select_nfds() {
+ let (r1, w1) = pipe().unwrap();
+ let (r2, _w2) = pipe().unwrap();
+
+ write(&w1, b"hi!").unwrap();
+ let mut fd_set = FdSet::new();
+ fd_set.insert(r1.as_fd());
+ fd_set.insert(r2.as_fd());
+
+ let mut timeout = TimeVal::seconds(10);
+ {
+ assert_eq!(
+ 1,
+ select(
+ Some(
+ fd_set
+ .highest()
+ .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+ .unwrap()
+ + 1
+ ),
+ &mut fd_set,
+ None,
+ None,
+ &mut timeout
+ )
+ .unwrap()
+ );
+ }
+ assert!(fd_set.contains(r1.as_fd()));
+ assert!(!fd_set.contains(r2.as_fd()));
+}
+
+#[test]
+fn test_select_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.as_fd());
+ fd_set.insert(r2.as_fd());
+
+ let mut timeout = TimeVal::seconds(10);
+ assert_eq!(
+ 1,
+ select(
+ std::cmp::max(r1.as_raw_fd(), r2.as_raw_fd()) + 1,
+ &mut fd_set,
+ None,
+ None,
+ &mut timeout
+ )
+ .unwrap()
+ );
+ assert!(fd_set.contains(r1.as_fd()));
+ assert!(!fd_set.contains(r2.as_fd()));
+}
diff --git a/third_party/rust/nix/test/sys/test_signal.rs b/third_party/rust/nix/test/sys/test_signal.rs
index ca25ff9ab0..bf607497be 100644
--- a/third_party/rust/nix/test/sys/test_signal.rs
+++ b/third_party/rust/nix/test/sys/test_signal.rs
@@ -1,9 +1,10 @@
-#[cfg(not(target_os = "redox"))]
use nix::errno::Errno;
use nix::sys::signal::*;
use nix::unistd::*;
-use std::convert::TryFrom;
+use std::hash::{Hash, Hasher};
use std::sync::atomic::{AtomicBool, Ordering};
+#[cfg(not(target_os = "redox"))]
+use std::thread;
#[test]
fn test_kill_none() {
@@ -124,7 +125,7 @@ fn test_signal() {
raise(Signal::SIGINT).unwrap();
assert!(SIGNALED.load(Ordering::Relaxed));
- #[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
+ #[cfg(not(solarish))]
assert_eq!(
unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
handler
@@ -132,7 +133,7 @@ fn test_signal() {
// 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"))]
+ #[cfg(solarish)]
assert_eq!(
unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
SigHandler::SigDfl
@@ -141,3 +142,314 @@ fn test_signal() {
// Restore default signal handler
unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap();
}
+
+#[test]
+fn test_contains() {
+ let mut mask = SigSet::empty();
+ mask.add(SIGUSR1);
+
+ assert!(mask.contains(SIGUSR1));
+ assert!(!mask.contains(SIGUSR2));
+
+ let all = SigSet::all();
+ assert!(all.contains(SIGUSR1));
+ assert!(all.contains(SIGUSR2));
+}
+
+#[test]
+fn test_clear() {
+ let mut set = SigSet::all();
+ set.clear();
+ for signal in Signal::iterator() {
+ assert!(!set.contains(signal));
+ }
+}
+
+#[test]
+fn test_from_str_round_trips() {
+ for signal in Signal::iterator() {
+ assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
+ assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
+ }
+}
+
+#[test]
+fn test_from_str_invalid_value() {
+ let errval = Err(Errno::EINVAL);
+ assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
+ assert_eq!("kill".parse::<Signal>(), errval);
+ assert_eq!("9".parse::<Signal>(), errval);
+}
+
+#[test]
+fn test_extend() {
+ let mut one_signal = SigSet::empty();
+ one_signal.add(SIGUSR1);
+
+ let mut two_signals = SigSet::empty();
+ two_signals.add(SIGUSR2);
+ two_signals.extend(&one_signal);
+
+ assert!(two_signals.contains(SIGUSR1));
+ assert!(two_signals.contains(SIGUSR2));
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn test_thread_signal_set_mask() {
+ thread::spawn(|| {
+ let prev_mask = SigSet::thread_get_mask()
+ .expect("Failed to get existing signal mask!");
+
+ let mut test_mask = prev_mask;
+ test_mask.add(SIGUSR1);
+
+ test_mask.thread_set_mask().expect("assertion failed");
+ let new_mask =
+ SigSet::thread_get_mask().expect("Failed to get new mask!");
+
+ assert!(new_mask.contains(SIGUSR1));
+ assert!(!new_mask.contains(SIGUSR2));
+
+ prev_mask
+ .thread_set_mask()
+ .expect("Failed to revert signal mask!");
+ })
+ .join()
+ .unwrap();
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn test_thread_signal_block() {
+ thread::spawn(|| {
+ let mut mask = SigSet::empty();
+ mask.add(SIGUSR1);
+
+ mask.thread_block().expect("assertion failed");
+
+ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
+ })
+ .join()
+ .unwrap();
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn test_thread_signal_unblock() {
+ thread::spawn(|| {
+ let mut mask = SigSet::empty();
+ mask.add(SIGUSR1);
+
+ mask.thread_unblock().expect("assertion failed");
+
+ assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
+ })
+ .join()
+ .unwrap();
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn test_thread_signal_swap() {
+ thread::spawn(|| {
+ let mut mask = SigSet::empty();
+ mask.add(SIGUSR1);
+ mask.thread_block().unwrap();
+
+ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
+
+ let mut mask2 = SigSet::empty();
+ mask2.add(SIGUSR2);
+
+ let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap();
+
+ assert!(oldmask.contains(SIGUSR1));
+ assert!(!oldmask.contains(SIGUSR2));
+
+ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
+ })
+ .join()
+ .unwrap();
+}
+
+#[test]
+fn test_from_and_into_iterator() {
+ let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]);
+ let signals = sigset.into_iter().collect::<Vec<Signal>>();
+ assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]);
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn test_sigaction() {
+ thread::spawn(|| {
+ extern "C" fn test_sigaction_handler(_: libc::c_int) {}
+ extern "C" fn test_sigaction_action(
+ _: libc::c_int,
+ _: *mut libc::siginfo_t,
+ _: *mut libc::c_void,
+ ) {
+ }
+
+ let handler_sig = SigHandler::Handler(test_sigaction_handler);
+
+ let flags =
+ SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO;
+
+ let mut mask = SigSet::empty();
+ mask.add(SIGUSR1);
+
+ let action_sig = SigAction::new(handler_sig, flags, mask);
+
+ assert_eq!(
+ action_sig.flags(),
+ SaFlags::SA_ONSTACK | SaFlags::SA_RESTART
+ );
+ assert_eq!(action_sig.handler(), handler_sig);
+
+ mask = action_sig.mask();
+ assert!(mask.contains(SIGUSR1));
+ assert!(!mask.contains(SIGUSR2));
+
+ let handler_act = SigHandler::SigAction(test_sigaction_action);
+ let action_act = SigAction::new(handler_act, flags, mask);
+ assert_eq!(action_act.handler(), handler_act);
+
+ let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
+ assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
+
+ let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
+ assert_eq!(action_ign.handler(), SigHandler::SigIgn);
+ })
+ .join()
+ .unwrap();
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn test_sigwait() {
+ thread::spawn(|| {
+ let mut mask = SigSet::empty();
+ mask.add(SIGUSR1);
+ mask.add(SIGUSR2);
+ mask.thread_block().unwrap();
+
+ raise(SIGUSR1).unwrap();
+ assert_eq!(mask.wait().unwrap(), SIGUSR1);
+ })
+ .join()
+ .unwrap();
+}
+
+#[cfg(any(
+ bsd,
+ linux_android,
+ solarish,
+ target_os = "haiku",
+ target_os = "hurd",
+ target_os = "aix",
+ target_os = "fushsia"
+))]
+#[test]
+fn test_sigsuspend() {
+ // This test change signal handler
+ let _m = crate::SIGNAL_MTX.lock();
+ static SIGNAL_RECIEVED: AtomicBool = AtomicBool::new(false);
+ extern "C" fn test_sigsuspend_handler(_: libc::c_int) {
+ assert!(!SIGNAL_RECIEVED.swap(true, Ordering::SeqCst));
+ }
+ thread::spawn(|| {
+ const SIGNAL: Signal = Signal::SIGUSR1;
+
+ // Add signal mask to this thread
+ let mut signal_set = SigSet::empty();
+ signal_set.add(SIGNAL);
+ signal_set.thread_block().unwrap();
+
+ // Set signal handler and save old one.
+ let act = SigAction::new(
+ SigHandler::Handler(test_sigsuspend_handler),
+ SaFlags::empty(),
+ SigSet::empty(),
+ );
+ let old_act = unsafe { sigaction(SIGNAL, &act) }
+ .expect("expect to be able to set new action and get old action");
+
+ raise(SIGNAL).expect("expect be able to send signal");
+ // Now `SIGNAL` was sended but it is blocked.
+ let mut not_wait_set = SigSet::all();
+ not_wait_set.remove(SIGNAL);
+ // signal handler must run in SigSet::suspend()
+ assert!(!SIGNAL_RECIEVED.load(Ordering::SeqCst));
+ not_wait_set.suspend().unwrap();
+ assert!(SIGNAL_RECIEVED.load(Ordering::SeqCst));
+
+ // Restore the signal handler.
+ unsafe { sigaction(SIGNAL, &old_act) }
+ .expect("expect to be able to restore old action ");
+ })
+ .join()
+ .unwrap();
+}
+
+#[test]
+fn test_from_sigset_t_unchecked() {
+ let src_set = SigSet::empty();
+ let set = unsafe { SigSet::from_sigset_t_unchecked(*src_set.as_ref()) };
+
+ for signal in Signal::iterator() {
+ assert!(!set.contains(signal));
+ }
+
+ let src_set = SigSet::all();
+ let set = unsafe { SigSet::from_sigset_t_unchecked(*src_set.as_ref()) };
+
+ for signal in Signal::iterator() {
+ assert!(set.contains(signal));
+ }
+}
+
+#[test]
+fn test_eq_empty() {
+ let set0 = SigSet::empty();
+ let set1 = SigSet::empty();
+ assert_eq!(set0, set1);
+}
+
+#[test]
+fn test_eq_all() {
+ let set0 = SigSet::all();
+ let set1 = SigSet::all();
+ assert_eq!(set0, set1);
+}
+
+#[test]
+fn test_hash_empty() {
+ use std::collections::hash_map::DefaultHasher;
+
+ let set0 = SigSet::empty();
+ let mut h0 = DefaultHasher::new();
+ set0.hash(&mut h0);
+
+ let set1 = SigSet::empty();
+ let mut h1 = DefaultHasher::new();
+ set1.hash(&mut h1);
+
+ assert_eq!(h0.finish(), h1.finish());
+}
+
+#[test]
+fn test_hash_all() {
+ use std::collections::hash_map::DefaultHasher;
+
+ let set0 = SigSet::all();
+ let mut h0 = DefaultHasher::new();
+ set0.hash(&mut h0);
+
+ let set1 = SigSet::all();
+ let mut h1 = DefaultHasher::new();
+ set1.hash(&mut h1);
+
+ assert_eq!(h0.finish(), h1.finish());
+}
diff --git a/third_party/rust/nix/test/sys/test_signalfd.rs b/third_party/rust/nix/test/sys/test_signalfd.rs
index 87153c9572..4e0971aba7 100644
--- a/third_party/rust/nix/test/sys/test_signalfd.rs
+++ b/third_party/rust/nix/test/sys/test_signalfd.rs
@@ -1,6 +1,40 @@
use std::convert::TryFrom;
#[test]
+fn create_signalfd() {
+ use nix::sys::{signal::SigSet, signalfd::SignalFd};
+
+ let mask = SigSet::empty();
+ SignalFd::new(&mask).unwrap();
+}
+
+#[test]
+fn create_signalfd_with_opts() {
+ use nix::sys::{
+ signal::SigSet,
+ signalfd::{SfdFlags, SignalFd},
+ };
+
+ let mask = SigSet::empty();
+ SignalFd::with_flags(&mask, SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK)
+ .unwrap();
+}
+
+#[test]
+fn read_empty_signalfd() {
+ use nix::sys::{
+ signal::SigSet,
+ signalfd::{SfdFlags, SignalFd},
+ };
+
+ let mask = SigSet::empty();
+ let mut fd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
+
+ let res = fd.read_signal();
+ assert!(res.unwrap().is_none());
+}
+
+#[test]
fn test_signalfd() {
use nix::sys::signal::{self, raise, SigSet, Signal};
use nix::sys::signalfd::SignalFd;
@@ -25,3 +59,32 @@ fn test_signalfd() {
let signo = Signal::try_from(res.ssi_signo as i32).unwrap();
assert_eq!(signo, signal::SIGUSR1);
}
+
+/// Update the signal mask of an already existing signalfd.
+#[test]
+fn test_signalfd_setmask() {
+ 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();
+
+ let mut fd = SignalFd::new(&mask).unwrap();
+
+ mask.add(signal::SIGUSR1);
+ mask.thread_block().unwrap();
+ fd.set_mask(&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);
+}
diff --git a/third_party/rust/nix/test/sys/test_socket.rs b/third_party/rust/nix/test/sys/test_socket.rs
index ed1686e87d..90b8a6f528 100644
--- a/third_party/rust/nix/test/sys/test_socket.rs
+++ b/third_party/rust/nix/test/sys/test_socket.rs
@@ -1,4 +1,4 @@
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
use crate::*;
use libc::c_char;
use nix::sys::socket::{getsockname, AddressFamily, UnixAddr};
@@ -21,7 +21,7 @@ pub fn test_timestamping() {
};
use std::io::{IoSlice, IoSliceMut};
- let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap();
+ let sock_addr = SockaddrIn::from_str("127.0.0.1:6797").unwrap();
let ssock = socket(
AddressFamily::Inet,
@@ -72,15 +72,134 @@ pub fn test_timestamping() {
assert!(std::time::Duration::from(diff).as_secs() < 60);
}
+#[cfg(target_os = "freebsd")]
+#[test]
+pub fn test_timestamping_realtime() {
+ use nix::sys::socket::{
+ recvmsg, sendmsg, setsockopt, socket, sockopt::ReceiveTimestamp,
+ sockopt::TsClock, ControlMessageOwned, MsgFlags, SockFlag, SockType,
+ SockaddrIn, SocketTimestamp,
+ };
+ use std::io::{IoSlice, IoSliceMut};
+
+ let sock_addr = SockaddrIn::from_str("127.0.0.1:6792").unwrap();
+
+ let ssock = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .expect("send socket failed");
+
+ let rsock = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap();
+
+ setsockopt(&rsock, ReceiveTimestamp, &true).unwrap();
+ setsockopt(&rsock, TsClock, &SocketTimestamp::SO_TS_REALTIME).unwrap();
+
+ let sbuf = [0u8; 2048];
+ let mut rbuf = [0u8; 2048];
+ let flags = MsgFlags::empty();
+ let iov1 = [IoSlice::new(&sbuf)];
+ let mut iov2 = [IoSliceMut::new(&mut rbuf)];
+
+ let mut cmsg = cmsg_space!(nix::sys::time::TimeVal);
+ sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
+ let recv =
+ recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags)
+ .unwrap();
+
+ let mut ts = None;
+ for c in recv.cmsgs() {
+ if let ControlMessageOwned::ScmRealtime(timeval) = c {
+ ts = Some(timeval);
+ }
+ }
+ let ts = ts.expect("ScmRealtime is present");
+ let sys_time =
+ ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME)
+ .unwrap();
+ let diff = if ts > sys_time {
+ ts - sys_time
+ } else {
+ sys_time - ts
+ };
+ assert!(std::time::Duration::from(diff).as_secs() < 60);
+}
+
+#[cfg(target_os = "freebsd")]
+#[test]
+pub fn test_timestamping_monotonic() {
+ use nix::sys::socket::{
+ recvmsg, sendmsg, setsockopt, socket, sockopt::ReceiveTimestamp,
+ sockopt::TsClock, ControlMessageOwned, MsgFlags, SockFlag, SockType,
+ SockaddrIn, SocketTimestamp,
+ };
+ use std::io::{IoSlice, IoSliceMut};
+
+ let sock_addr = SockaddrIn::from_str("127.0.0.1:6803").unwrap();
+
+ let ssock = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .expect("send socket failed");
+
+ let rsock = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap();
+
+ setsockopt(&rsock, ReceiveTimestamp, &true).unwrap();
+ setsockopt(&rsock, TsClock, &SocketTimestamp::SO_TS_MONOTONIC).unwrap();
+
+ let sbuf = [0u8; 2048];
+ let mut rbuf = [0u8; 2048];
+ let flags = MsgFlags::empty();
+ let iov1 = [IoSlice::new(&sbuf)];
+ let mut iov2 = [IoSliceMut::new(&mut rbuf)];
+
+ let mut cmsg = cmsg_space!(nix::sys::time::TimeVal);
+ sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
+ let recv =
+ recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags)
+ .unwrap();
+
+ let mut ts = None;
+ for c in recv.cmsgs() {
+ if let ControlMessageOwned::ScmMonotonic(timeval) = c {
+ ts = Some(timeval);
+ }
+ }
+ let ts = ts.expect("ScmMonotonic is present");
+ let sys_time =
+ ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_MONOTONIC)
+ .unwrap();
+ let diff = sys_time - ts; // Monotonic clock sys_time must be greater
+ assert!(std::time::Duration::from(diff).as_secs() < 60);
+}
+
#[test]
pub fn test_path_to_sock_addr() {
let path = "/foo/bar";
let actual = Path::new(path);
let addr = UnixAddr::new(actual).unwrap();
- let expect: &[c_char] = unsafe {
- slice::from_raw_parts(path.as_ptr() as *const c_char, path.len())
- };
+ let expect: &[c_char] =
+ unsafe { slice::from_raw_parts(path.as_ptr().cast(), path.len()) };
assert_eq!(unsafe { &(*addr.as_ptr()).sun_path[..8] }, expect);
assert_eq!(addr.path(), Some(actual));
@@ -105,7 +224,7 @@ pub fn test_addr_equality_path() {
assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
}
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
#[test]
pub fn test_abstract_sun_path_too_long() {
let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough");
@@ -113,7 +232,7 @@ pub fn test_abstract_sun_path_too_long() {
addr.expect_err("assertion failed");
}
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
#[test]
pub fn test_addr_equality_abstract() {
let name = String::from("nix\0abstract\0test");
@@ -129,7 +248,7 @@ pub fn test_addr_equality_abstract() {
}
// Test getting/setting abstract addresses (without unix socket creation)
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
#[test]
pub fn test_abstract_uds_addr() {
let empty = String::new();
@@ -151,7 +270,7 @@ pub fn test_abstract_uds_addr() {
}
// Test getting an unnamed address (without unix socket creation)
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
#[test]
pub fn test_unnamed_uds_addr() {
use crate::nix::sys::socket::SockaddrLike;
@@ -200,7 +319,7 @@ pub fn test_socketpair() {
SockFlag::empty(),
)
.unwrap();
- write(fd1.as_raw_fd(), b"hello").unwrap();
+ write(&fd1, b"hello").unwrap();
let mut buf = [0; 5];
read(fd2.as_raw_fd(), &mut buf).unwrap();
@@ -315,7 +434,7 @@ mod recvfrom {
#[test]
pub fn udp() {
- let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap();
+ let std_sa = SocketAddrV4::from_str("127.0.0.1:6795").unwrap();
let sock_addr = SockaddrIn::from(std_sa);
let rsock = socket(
AddressFamily::Inet,
@@ -437,12 +556,7 @@ mod recvfrom {
}
}
- #[cfg(any(
- target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "netbsd",
- ))]
+ #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
#[test]
pub fn udp_sendmmsg() {
use std::io::IoSlice;
@@ -504,12 +618,7 @@ mod recvfrom {
assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap());
}
- #[cfg(any(
- target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "netbsd",
- ))]
+ #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
#[test]
pub fn udp_recvmmsg() {
use nix::sys::socket::{recvmmsg, MsgFlags};
@@ -565,7 +674,7 @@ mod recvfrom {
let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
rsock.as_raw_fd(),
&mut data,
- msgs.iter(),
+ msgs.iter_mut(),
MsgFlags::empty(),
None,
)
@@ -585,12 +694,7 @@ mod recvfrom {
send_thread.join().unwrap();
}
- #[cfg(any(
- target_os = "linux",
- target_os = "android",
- target_os = "freebsd",
- target_os = "netbsd",
- ))]
+ #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
#[test]
pub fn udp_recvmmsg_dontwait_short_read() {
use nix::sys::socket::{recvmmsg, MsgFlags};
@@ -653,7 +757,7 @@ mod recvfrom {
let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
rsock.as_raw_fd(),
&mut data,
- msgs.iter(),
+ msgs.iter_mut(),
MsgFlags::MSG_DONTWAIT,
None,
)
@@ -674,10 +778,10 @@ mod recvfrom {
#[test]
pub fn udp_inet6() {
let addr = std::net::Ipv6Addr::from_str("::1").unwrap();
- let rport = 6789;
+ let rport = 6796;
let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0);
let raddr = SockaddrIn6::from(rstd_sa);
- let sport = 6790;
+ let sport = 6798;
let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0);
let saddr = SockaddrIn6::from(sstd_sa);
let rsock = socket(
@@ -757,7 +861,7 @@ pub fn test_scm_rights() {
{
let iov = [IoSlice::new(b"hello")];
- let fds = [r];
+ let fds = [r.as_raw_fd()];
let cmsg = ControlMessage::ScmRights(&fds);
assert_eq!(
sendmsg::<()>(
@@ -770,7 +874,6 @@ pub fn test_scm_rights() {
.unwrap(),
5
);
- close(r).unwrap();
}
{
@@ -803,16 +906,15 @@ pub fn test_scm_rights() {
let received_r = received_r.expect("Did not receive passed fd");
// Ensure that the received file descriptor works
- write(w.as_raw_fd(), b"world").unwrap();
+ write(&w, b"world").unwrap();
let mut buf = [0u8; 5];
read(received_r.as_raw_fd(), &mut buf).unwrap();
assert_eq!(&buf[..], b"world");
close(received_r).unwrap();
- close(w).unwrap();
}
// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
#[cfg_attr(qemu, ignore)]
#[test]
pub fn test_af_alg_cipher() {
@@ -905,7 +1007,7 @@ pub fn test_af_alg_cipher() {
// Disable the test on emulated platforms due to not enabled support of AF_ALG
// in QEMU from rust cross
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
#[cfg_attr(qemu, ignore)]
#[test]
pub fn test_af_alg_aead() {
@@ -1039,7 +1141,7 @@ pub fn test_af_alg_aead() {
// This would be a more interesting test if we could assume that the test host
// has more than one IP address (since we could select a different address to
// test from).
-#[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd"))]
+#[cfg(any(target_os = "linux", apple_targets, target_os = "netbsd"))]
#[test]
pub fn test_sendmsg_ipv4packetinfo() {
use cfg_if::cfg_if;
@@ -1101,7 +1203,7 @@ pub fn test_sendmsg_ipv4packetinfo() {
// test from).
#[cfg(any(
target_os = "linux",
- target_os = "macos",
+ apple_targets,
target_os = "netbsd",
target_os = "freebsd"
))]
@@ -1158,12 +1260,7 @@ pub fn test_sendmsg_ipv6packetinfo() {
//
// Note that binding to 0.0.0.0 is *required* on FreeBSD; sendmsg
// returns EINVAL otherwise. (See FreeBSD's ip(4) man page.)
-#[cfg(any(
- target_os = "netbsd",
- target_os = "freebsd",
- target_os = "openbsd",
- target_os = "dragonfly",
-))]
+#[cfg(any(freebsdlike, netbsdlike))]
#[test]
pub fn test_sendmsg_ipv4sendsrcaddr() {
use nix::sys::socket::{
@@ -1302,7 +1399,7 @@ pub fn test_sendmsg_empty_cmsgs() {
)
.unwrap();
- for _ in msg.cmsgs() {
+ if msg.cmsgs().next().is_some() {
panic!("unexpected cmsg");
}
assert!(!msg
@@ -1312,19 +1409,14 @@ pub fn test_sendmsg_empty_cmsgs() {
}
}
-#[cfg(any(
- target_os = "android",
- target_os = "linux",
- target_os = "freebsd",
- target_os = "dragonfly",
-))]
+#[cfg(any(linux_android, freebsdlike))]
#[test]
fn test_scm_credentials() {
use nix::sys::socket::{
recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage,
ControlMessageOwned, MsgFlags, SockFlag, SockType, UnixCredentials,
};
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(linux_android)]
use nix::sys::socket::{setsockopt, sockopt::PassCred};
use nix::unistd::{getgid, getpid, getuid};
use std::io::{IoSlice, IoSliceMut};
@@ -1336,16 +1428,16 @@ fn test_scm_credentials() {
SockFlag::empty(),
)
.unwrap();
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(linux_android)]
setsockopt(&recv, PassCred, &true).unwrap();
{
let iov = [IoSlice::new(b"hello")];
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(linux_android)]
let cred = UnixCredentials::new();
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(linux_android)]
let cmsg = ControlMessage::ScmCredentials(&cred);
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+ #[cfg(freebsdlike)]
let cmsg = ControlMessage::ScmCreds;
assert_eq!(
sendmsg::<()>(
@@ -1376,9 +1468,9 @@ fn test_scm_credentials() {
for cmsg in msg.cmsgs() {
let cred = match cmsg {
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(linux_android)]
ControlMessageOwned::ScmCredentials(cred) => cred,
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+ #[cfg(freebsdlike)]
ControlMessageOwned::ScmCreds(cred) => cred,
other => panic!("unexpected cmsg {other:?}"),
};
@@ -1398,7 +1490,7 @@ fn test_scm_credentials() {
/// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single
/// `sendmsg` call.
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation
// see https://bugs.launchpad.net/qemu/+bug/1781280
#[cfg_attr(qemu, ignore)]
@@ -1410,7 +1502,7 @@ fn test_scm_credentials_and_rights() {
/// Ensure that passing a an oversized control message buffer to recvmsg
/// still works.
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation
// see https://bugs.launchpad.net/qemu/+bug/1781280
#[cfg_attr(qemu, ignore)]
@@ -1420,7 +1512,7 @@ fn test_too_large_cmsgspace() {
test_impl_scm_credentials_and_rights(space);
}
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
use libc::ucred;
use nix::sys::socket::sockopt::PassCred;
@@ -1451,7 +1543,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
gid: getgid().as_raw(),
}
.into();
- let fds = [r];
+ let fds = [r.as_raw_fd()];
let cmsgs = [
ControlMessage::ScmCredentials(&cred),
ControlMessage::ScmRights(&fds),
@@ -1467,7 +1559,6 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
.unwrap(),
5
);
- close(r).unwrap();
}
{
@@ -1510,18 +1601,19 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
let received_r = received_r.expect("Did not receive passed fd");
// Ensure that the received file descriptor works
- write(w.as_raw_fd(), b"world").unwrap();
+ write(&w, b"world").unwrap();
let mut buf = [0u8; 5];
read(received_r.as_raw_fd(), &mut buf).unwrap();
assert_eq!(&buf[..], b"world");
close(received_r).unwrap();
- close(w).unwrap();
}
// Test creating and using named unix domain sockets
#[test]
pub fn test_named_unixdomain() {
- use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr};
+ use nix::sys::socket::{
+ accept, bind, connect, listen, socket, Backlog, UnixAddr,
+ };
use nix::sys::socket::{SockFlag, SockType};
use nix::unistd::{read, write};
use std::thread;
@@ -1537,7 +1629,7 @@ pub fn test_named_unixdomain() {
.expect("socket failed");
let sockaddr = UnixAddr::new(&sockname).unwrap();
bind(s1.as_raw_fd(), &sockaddr).expect("bind failed");
- listen(&s1, 10).expect("listen failed");
+ listen(&s1, Backlog::new(10).unwrap()).expect("listen failed");
let thr = thread::spawn(move || {
let s2 = socket(
@@ -1548,7 +1640,7 @@ pub fn test_named_unixdomain() {
)
.expect("socket failed");
connect(s2.as_raw_fd(), &sockaddr).expect("connect failed");
- write(s2.as_raw_fd(), b"hello").expect("write failed");
+ write(&s2, b"hello").expect("write failed");
});
let s3 = accept(s1.as_raw_fd()).expect("accept failed");
@@ -1560,8 +1652,16 @@ pub fn test_named_unixdomain() {
assert_eq!(&buf[..], b"hello");
}
+#[test]
+pub fn test_listen_wrongbacklog() {
+ use nix::sys::socket::Backlog;
+
+ assert!(Backlog::new(libc::SOMAXCONN + 1).is_err());
+ assert!(Backlog::new(-2).is_err());
+}
+
// Test using unnamed unix domain addresses
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
#[test]
pub fn test_unnamed_unixdomain() {
use nix::sys::socket::{getsockname, socketpair};
@@ -1581,7 +1681,7 @@ pub fn test_unnamed_unixdomain() {
}
// Test creating and using unnamed unix domain addresses for autobinding sockets
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
#[test]
pub fn test_unnamed_unixdomain_autobind() {
use nix::sys::socket::{bind, getsockname, socket};
@@ -1609,7 +1709,7 @@ pub fn test_unnamed_unixdomain_autobind() {
}
// Test creating and using named system control sockets
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(apple_targets)]
#[test]
pub fn test_syscontrol() {
use nix::errno::Errno;
@@ -1635,15 +1735,7 @@ pub fn test_syscontrol() {
// connect(fd.as_raw_fd(), &sockaddr).expect("connect failed");
}
-#[cfg(any(
- target_os = "android",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd",
-))]
+#[cfg(any(bsd, linux_android))]
fn loopback_address(
family: AddressFamily,
) -> Option<nix::ifaddrs::InterfaceAddress> {
@@ -1670,20 +1762,16 @@ fn loopback_address(
})
}
-#[cfg(any(
- target_os = "android",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
- target_os = "netbsd",
-))]
+#[cfg(any(linux_android, apple_targets, target_os = "netbsd"))]
// qemu doesn't seem to be emulating this correctly in these architectures
#[cfg_attr(
all(
qemu,
any(
target_arch = "mips",
+ target_arch = "mips32r6",
target_arch = "mips64",
+ target_arch = "mips64r6",
target_arch = "powerpc64",
)
),
@@ -1765,20 +1853,16 @@ pub fn test_recv_ipv4pktinfo() {
}
}
-#[cfg(any(
- target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd",
-))]
+#[cfg(bsd)]
// qemu doesn't seem to be emulating this correctly in these architectures
#[cfg_attr(
all(
qemu,
any(
target_arch = "mips",
+ target_arch = "mips32r6",
target_arch = "mips64",
+ target_arch = "mips64r6",
target_arch = "powerpc64",
)
),
@@ -1883,7 +1967,7 @@ pub fn test_recvif() {
}
}
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg_attr(qemu, ignore)]
#[test]
pub fn test_recvif_ipv4() {
@@ -1969,7 +2053,7 @@ pub fn test_recvif_ipv4() {
}
}
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg_attr(qemu, ignore)]
#[test]
pub fn test_recvif_ipv6() {
@@ -2055,22 +2139,16 @@ pub fn test_recvif_ipv6() {
}
}
-#[cfg(any(
- target_os = "android",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd",
-))]
+#[cfg(any(linux_android, target_os = "freebsd", apple_targets, netbsdlike))]
// qemu doesn't seem to be emulating this correctly in these architectures
#[cfg_attr(
all(
qemu,
any(
target_arch = "mips",
+ target_arch = "mips32r6",
target_arch = "mips64",
+ target_arch = "mips64r6",
target_arch = "powerpc64",
)
),
@@ -2152,7 +2230,7 @@ pub fn test_recv_ipv6pktinfo() {
}
}
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
#[test]
pub fn test_vsock() {
use nix::sys::socket::SockaddrLike;
@@ -2192,7 +2270,7 @@ pub fn test_vsock() {
assert_eq!(addr3.as_ref().svm_port, addr1.port());
}
-#[cfg(target_os = "macos")]
+#[cfg(apple_targets)]
#[test]
pub fn test_vsock() {
use nix::sys::socket::SockaddrLike;
@@ -2329,12 +2407,17 @@ fn test_recvmmsg_timestampns() {
// Receive the message
let mut buffer = vec![0u8; message.len()];
let cmsgspace = nix::cmsg_space!(TimeSpec);
- let iov = vec![[IoSliceMut::new(&mut buffer)]];
+ let mut iov = vec![[IoSliceMut::new(&mut buffer)]];
let mut data = MultiHeaders::preallocate(1, Some(cmsgspace));
- let r: Vec<RecvMsg<()>> =
- recvmmsg(in_socket.as_raw_fd(), &mut data, iov.iter(), flags, None)
- .unwrap()
- .collect();
+ let r: Vec<RecvMsg<()>> = recvmmsg(
+ in_socket.as_raw_fd(),
+ &mut data,
+ iov.iter_mut(),
+ flags,
+ None,
+ )
+ .unwrap()
+ .collect();
let rtime = match r[0].cmsgs().next() {
Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime,
Some(_) => panic!("Unexpected control message"),
@@ -2353,7 +2436,7 @@ fn test_recvmmsg_timestampns() {
// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack
// of QEMU support is suspected.
#[cfg_attr(qemu, ignore)]
-#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "fuchsia"))]
#[test]
fn test_recvmsg_rxq_ovfl() {
use nix::sys::socket::sockopt::{RcvBuf, RxqOvfl};
@@ -2447,7 +2530,7 @@ fn test_recvmsg_rxq_ovfl() {
assert_eq!(drop_counter, 1);
}
-#[cfg(any(target_os = "linux", target_os = "android",))]
+#[cfg(linux_android)]
mod linux_errqueue {
use super::FromStr;
use nix::sys::socket::*;
@@ -2685,3 +2768,160 @@ pub fn test_txtime() {
recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, None, MsgFlags::empty())
.unwrap();
}
+
+// cfg needed for capability check.
+#[cfg(linux_android)]
+#[test]
+fn test_icmp_protocol() {
+ use nix::sys::socket::{
+ sendto, socket, AddressFamily, MsgFlags, SockFlag, SockProtocol,
+ SockType, SockaddrIn,
+ };
+
+ require_capability!("test_icmp_protocol", CAP_NET_RAW);
+
+ let owned_fd = socket(
+ AddressFamily::Inet,
+ SockType::Raw,
+ SockFlag::empty(),
+ SockProtocol::Icmp,
+ )
+ .unwrap();
+
+ // Send a minimal ICMP packet with no payload.
+ let packet = [
+ 0x08, // Type
+ 0x00, // Code
+ 0x84, 0x85, // Checksum
+ 0x73, 0x8a, // ID
+ 0x00, 0x00, // Sequence Number
+ ];
+
+ let dest_addr = SockaddrIn::new(127, 0, 0, 1, 0);
+ sendto(owned_fd.as_raw_fd(), &packet, &dest_addr, MsgFlags::empty())
+ .unwrap();
+}
+
+// test contains both recvmmsg and timestaping which is linux only
+// there are existing tests for recvmmsg only in tests/
+#[cfg_attr(qemu, ignore)]
+#[cfg(target_os = "linux")]
+#[test]
+fn test_recvmm2() -> nix::Result<()> {
+ use nix::sys::{
+ socket::{
+ bind, recvmmsg, sendmsg, setsockopt, socket, sockopt::Timestamping,
+ AddressFamily, ControlMessageOwned, MsgFlags, MultiHeaders,
+ SockFlag, SockType, SockaddrIn, TimestampingFlag, Timestamps,
+ },
+ time::TimeSpec,
+ };
+ use std::io::{IoSlice, IoSliceMut};
+ use std::os::unix::io::AsRawFd;
+ use std::str::FromStr;
+
+ let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap();
+
+ let ssock = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )?;
+
+ let rsock = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::SOCK_NONBLOCK,
+ None,
+ )?;
+
+ bind(rsock.as_raw_fd(), &sock_addr)?;
+
+ setsockopt(&rsock, Timestamping, &TimestampingFlag::all())?;
+
+ let sbuf = (0..400).map(|i| i as u8).collect::<Vec<_>>();
+
+ let mut recv_buf = vec![0; 1024];
+
+ let mut recv_iovs = Vec::new();
+ let mut pkt_iovs = Vec::new();
+
+ for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() {
+ pkt_iovs.push(IoSliceMut::new(chunk));
+ if ix % 2 == 1 {
+ recv_iovs.push(pkt_iovs);
+ pkt_iovs = Vec::new();
+ }
+ }
+ drop(pkt_iovs);
+
+ let flags = MsgFlags::empty();
+ let iov1 = [IoSlice::new(&sbuf)];
+
+ let cmsg = cmsg_space!(Timestamps);
+ sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
+
+ let mut data = MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg));
+
+ let t = TimeSpec::from_duration(std::time::Duration::from_secs(10));
+
+ let recv = recvmmsg(
+ rsock.as_raw_fd(),
+ &mut data,
+ recv_iovs.iter_mut(),
+ flags,
+ Some(t),
+ )?;
+
+ for rmsg in recv {
+ #[cfg(not(any(qemu, target_arch = "aarch64")))]
+ let mut saw_time = false;
+ let mut recvd = 0;
+ for cmsg in rmsg.cmsgs() {
+ if let ControlMessageOwned::ScmTimestampsns(timestamps) = cmsg {
+ let ts = timestamps.system;
+
+ let sys_time = nix::time::clock_gettime(
+ nix::time::ClockId::CLOCK_REALTIME,
+ )?;
+ let diff = if ts > sys_time {
+ ts - sys_time
+ } else {
+ sys_time - ts
+ };
+ assert!(std::time::Duration::from(diff).as_secs() < 60);
+ #[cfg(not(any(qemu, target_arch = "aarch64")))]
+ {
+ saw_time = true;
+ }
+ }
+ }
+
+ #[cfg(not(any(qemu, target_arch = "aarch64")))]
+ assert!(saw_time);
+
+ for iov in rmsg.iovs() {
+ recvd += iov.len();
+ }
+ assert_eq!(recvd, 400);
+ }
+
+ Ok(())
+}
+
+#[cfg(not(target_os = "redox"))]
+#[test]
+fn can_use_cmsg_space() {
+ let _ = cmsg_space!(u8);
+}
+
+#[cfg(not(any(linux_android, target_os = "redox", target_os = "haiku")))]
+#[test]
+fn can_open_routing_socket() {
+ use nix::sys::socket::{socket, AddressFamily, SockFlag, SockType};
+
+ let _ =
+ socket(AddressFamily::Route, SockType::Raw, SockFlag::empty(), None)
+ .expect("Failed to open routing socket");
+}
diff --git a/third_party/rust/nix/test/sys/test_sockopt.rs b/third_party/rust/nix/test/sys/test_sockopt.rs
index 0e34917325..a99d4e39ed 100644
--- a/third_party/rust/nix/test/sys/test_sockopt.rs
+++ b/third_party/rust/nix/test/sys/test_sockopt.rs
@@ -1,14 +1,14 @@
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
use crate::*;
use nix::sys::socket::{
getsockopt, setsockopt, socket, sockopt, AddressFamily, SockFlag,
SockProtocol, SockType,
};
use rand::{thread_rng, Rng};
-use std::os::unix::io::AsRawFd;
+use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd};
// NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not.
-#[cfg(any(target_os = "dragonfly", target_os = "freebsd",))]
+#[cfg(freebsdlike)]
#[test]
pub fn test_local_peercred_seqpacket() {
use nix::{
@@ -29,12 +29,7 @@ pub fn test_local_peercred_seqpacket() {
assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
}
-#[cfg(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "macos",
- target_os = "ios"
-))]
+#[cfg(any(freebsdlike, apple_targets))]
#[test]
pub fn test_local_peercred_stream() {
use nix::{
@@ -55,7 +50,7 @@ pub fn test_local_peercred_stream() {
assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
}
-#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[cfg(apple_targets)]
#[test]
pub fn test_local_peer_pid() {
use nix::sys::socket::socketpair;
@@ -108,15 +103,42 @@ fn test_so_buf() {
assert!(actual >= bufsize);
}
+#[cfg(target_os = "freebsd")]
+#[test]
+fn test_so_listen_q_limit() {
+ use nix::sys::socket::{bind, listen, Backlog, SockaddrIn};
+ use std::net::SocketAddrV4;
+ use std::str::FromStr;
+
+ let std_sa = SocketAddrV4::from_str("127.0.0.1:4004").unwrap();
+ let sock_addr = SockaddrIn::from(std_sa);
+
+ let rsock = socket(
+ AddressFamily::Inet,
+ SockType::Stream,
+ SockFlag::empty(),
+ SockProtocol::Tcp,
+ )
+ .unwrap();
+ bind(rsock.as_raw_fd(), &sock_addr).unwrap();
+ let pre_limit = getsockopt(&rsock, sockopt::ListenQLimit).unwrap();
+ assert_eq!(pre_limit, 0);
+ listen(&rsock, Backlog::new(42).unwrap()).unwrap();
+ let post_limit = getsockopt(&rsock, sockopt::ListenQLimit).unwrap();
+ assert_eq!(post_limit, 42);
+}
+
#[test]
fn test_so_tcp_maxseg() {
- use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn};
+ use nix::sys::socket::{
+ accept, bind, connect, getsockname, listen, Backlog, SockaddrIn,
+ };
use nix::unistd::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 std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap();
+ let mut sock_addr = SockaddrIn::from(std_sa);
let rsock = socket(
AddressFamily::Inet,
@@ -126,13 +148,14 @@ fn test_so_tcp_maxseg() {
)
.unwrap();
bind(rsock.as_raw_fd(), &sock_addr).unwrap();
- listen(&rsock, 10).unwrap();
+ sock_addr = getsockname(rsock.as_raw_fd()).unwrap();
+ listen(&rsock, Backlog::new(10).unwrap()).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"))] {
+ if #[cfg(linux_android)] {
let segsize: u32 = 873;
assert!(initial < segsize);
setsockopt(&rsock, sockopt::TcpMaxSeg, &segsize).unwrap();
@@ -151,12 +174,13 @@ fn test_so_tcp_maxseg() {
.unwrap();
connect(ssock.as_raw_fd(), &sock_addr).unwrap();
let rsess = accept(rsock.as_raw_fd()).unwrap();
- write(rsess, b"hello").unwrap();
+ let rsess = unsafe { OwnedFd::from_raw_fd(rsess) };
+ 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"))] {
+ if #[cfg(linux_android)] {
assert!((segsize - 100) <= actual);
assert!(actual <= segsize);
} else {
@@ -181,11 +205,10 @@ fn test_so_type() {
/// 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",))]
+#[cfg(linux_android)]
#[test]
fn test_so_type_unknown() {
use nix::errno::Errno;
- use std::os::unix::io::{FromRawFd, OwnedFd};
require_capability!("test_so_type", CAP_NET_RAW);
let raw_fd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) };
@@ -229,7 +252,7 @@ fn test_tcp_congestion() {
}
#[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
fn test_bindtodevice() {
skip_if_not_root!("test_bindtodevice");
@@ -259,12 +282,7 @@ fn test_so_tcp_keepalive() {
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"
- ))]
+ #[cfg(any(linux_android, freebsdlike))]
{
let x = getsockopt(&fd, sockopt::TcpKeepIdle).unwrap();
setsockopt(&fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap();
@@ -281,14 +299,14 @@ fn test_so_tcp_keepalive() {
}
#[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
#[cfg_attr(qemu, ignore)]
fn test_get_mtu() {
use nix::sys::socket::{bind, connect, SockaddrIn};
use std::net::SocketAddrV4;
use std::str::FromStr;
- let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap();
+ let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap();
let std_sb = SocketAddrV4::from_str("127.0.0.1:4002").unwrap();
let usock = socket(
@@ -308,7 +326,7 @@ fn test_get_mtu() {
}
#[test]
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
fn test_ttl_opts() {
let fd4 = socket(
AddressFamily::Inet,
@@ -331,7 +349,48 @@ fn test_ttl_opts() {
}
#[test]
-#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
+fn test_multicast_ttl_opts_ipv4() {
+ let fd4 = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ setsockopt(&fd4, sockopt::IpMulticastTtl, &2)
+ .expect("setting ipmulticastttl on an inet socket should succeed");
+}
+
+#[test]
+#[cfg(linux_android)]
+fn test_multicast_ttl_opts_ipv6() {
+ let fd6 = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ setsockopt(&fd6, sockopt::IpMulticastTtl, &2)
+ .expect("setting ipmulticastttl on an inet6 socket should succeed");
+}
+
+#[test]
+fn test_ipv6_multicast_hops() {
+ let fd6 = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ setsockopt(&fd6, sockopt::Ipv6MulticastHops, &7)
+ .expect("setting ipv6multicasthops on an inet6 socket should succeed");
+}
+
+#[test]
+#[cfg(apple_targets)]
fn test_dontfrag_opts() {
let fd4 = socket(
AddressFamily::Inet,
@@ -361,12 +420,7 @@ fn test_dontfrag_opts() {
}
#[test]
-#[cfg(any(
- target_os = "android",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
-))]
+#[cfg(any(linux_android, apple_targets))]
// Disable the test under emulation because it fails in Cirrus-CI. Lack
// of QEMU support is suspected.
#[cfg_attr(qemu, ignore)]
@@ -446,3 +500,331 @@ fn test_ipv6_tclass() {
setsockopt(&fd, sockopt::Ipv6TClass, &class).unwrap();
assert_eq!(getsockopt(&fd, sockopt::Ipv6TClass).unwrap(), class);
}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_receive_timestamp() {
+ let fd = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+ assert!(getsockopt(&fd, sockopt::ReceiveTimestamp).unwrap());
+}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_ts_clock_realtime_micro() {
+ use nix::sys::socket::SocketTimestamp;
+
+ let fd = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+
+ // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
+ setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+
+ setsockopt(
+ &fd,
+ sockopt::TsClock,
+ &SocketTimestamp::SO_TS_REALTIME_MICRO,
+ )
+ .unwrap();
+ assert_eq!(
+ getsockopt(&fd, sockopt::TsClock).unwrap(),
+ SocketTimestamp::SO_TS_REALTIME_MICRO
+ );
+}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_ts_clock_bintime() {
+ use nix::sys::socket::SocketTimestamp;
+
+ let fd = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+
+ // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
+ setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+
+ setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_BINTIME).unwrap();
+ assert_eq!(
+ getsockopt(&fd, sockopt::TsClock).unwrap(),
+ SocketTimestamp::SO_TS_BINTIME
+ );
+}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_ts_clock_realtime() {
+ use nix::sys::socket::SocketTimestamp;
+
+ let fd = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+
+ // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
+ setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+
+ setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_REALTIME)
+ .unwrap();
+ assert_eq!(
+ getsockopt(&fd, sockopt::TsClock).unwrap(),
+ SocketTimestamp::SO_TS_REALTIME
+ );
+}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_ts_clock_monotonic() {
+ use nix::sys::socket::SocketTimestamp;
+
+ let fd = socket(
+ AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+
+ // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
+ setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+
+ setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_MONOTONIC)
+ .unwrap();
+ assert_eq!(
+ getsockopt(&fd, sockopt::TsClock).unwrap(),
+ SocketTimestamp::SO_TS_MONOTONIC
+ );
+}
+
+#[test]
+#[cfg(linux_android)]
+// Disable the test under emulation because it fails with ENOPROTOOPT in CI
+// on cross target. Lack of QEMU support is suspected.
+#[cfg_attr(qemu, ignore)]
+fn test_ip_bind_address_no_port() {
+ let fd = socket(
+ AddressFamily::Inet,
+ SockType::Stream,
+ SockFlag::empty(),
+ SockProtocol::Tcp,
+ )
+ .unwrap();
+ setsockopt(&fd, sockopt::IpBindAddressNoPort, &true).expect(
+ "setting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
+ );
+ assert!(getsockopt(&fd, sockopt::IpBindAddressNoPort).expect(
+ "getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
+ ));
+ setsockopt(&fd, sockopt::IpBindAddressNoPort, &false).expect(
+ "unsetting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
+ );
+ assert!(!getsockopt(&fd, sockopt::IpBindAddressNoPort).expect(
+ "getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
+ ));
+}
+
+#[test]
+#[cfg(linux_android)]
+fn test_tcp_fast_open_connect() {
+ let fd = socket(
+ AddressFamily::Inet,
+ SockType::Stream,
+ SockFlag::empty(),
+ SockProtocol::Tcp,
+ )
+ .unwrap();
+ setsockopt(&fd, sockopt::TcpFastOpenConnect, &true).expect(
+ "setting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
+ );
+ assert!(getsockopt(&fd, sockopt::TcpFastOpenConnect).expect(
+ "getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
+ ));
+ setsockopt(&fd, sockopt::TcpFastOpenConnect, &false).expect(
+ "unsetting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
+ );
+ assert!(!getsockopt(&fd, sockopt::TcpFastOpenConnect).expect(
+ "getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
+ ));
+}
+
+#[cfg(linux_android)]
+#[test]
+fn can_get_peercred_on_unix_socket() {
+ use nix::sys::socket::{socketpair, sockopt, SockFlag, SockType};
+
+ let (a, b) = socketpair(
+ AddressFamily::Unix,
+ SockType::Stream,
+ None,
+ SockFlag::empty(),
+ )
+ .unwrap();
+ let a_cred = getsockopt(&a, sockopt::PeerCredentials).unwrap();
+ let b_cred = getsockopt(&b, sockopt::PeerCredentials).unwrap();
+ assert_eq!(a_cred, b_cred);
+ assert_ne!(a_cred.pid(), 0);
+}
+
+#[test]
+fn is_socket_type_unix() {
+ use nix::sys::socket::{socketpair, sockopt, SockFlag, SockType};
+
+ let (a, _b) = socketpair(
+ AddressFamily::Unix,
+ SockType::Stream,
+ None,
+ SockFlag::empty(),
+ )
+ .unwrap();
+ let a_type = getsockopt(&a, sockopt::SockType).unwrap();
+ assert_eq!(a_type, SockType::Stream);
+}
+
+#[test]
+fn is_socket_type_dgram() {
+ use nix::sys::socket::{
+ getsockopt, sockopt, AddressFamily, SockFlag, SockType,
+ };
+
+ let s = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ let s_type = getsockopt(&s, sockopt::SockType).unwrap();
+ assert_eq!(s_type, SockType::Datagram);
+}
+
+#[cfg(any(target_os = "freebsd", target_os = "linux"))]
+#[test]
+fn can_get_listen_on_tcp_socket() {
+ use nix::sys::socket::{
+ getsockopt, listen, socket, sockopt, AddressFamily, Backlog, SockFlag,
+ SockType,
+ };
+
+ let s = socket(
+ AddressFamily::Inet,
+ SockType::Stream,
+ SockFlag::empty(),
+ None,
+ )
+ .unwrap();
+ let s_listening = getsockopt(&s, sockopt::AcceptConn).unwrap();
+ assert!(!s_listening);
+ listen(&s, Backlog::new(10).unwrap()).unwrap();
+ let s_listening2 = getsockopt(&s, sockopt::AcceptConn).unwrap();
+ assert!(s_listening2);
+}
+
+#[cfg(target_os = "linux")]
+// Some architectures running under cross don't support `setsockopt(SOL_TCP, TCP_ULP)`
+// because the cross image is based on Ubuntu 16.04 which predates TCP ULP support
+// (it was added in kernel v4.13 released in 2017). For these architectures,
+// the `setsockopt(SOL_TCP, TCP_ULP, "tls", sizeof("tls"))` call succeeds
+// but the subsequent `setsockopt(SOL_TLS, TLS_TX, ...)` call fails with `ENOPROTOOPT`.
+// It's as if the first `setsockopt` call enabled some other option, not `TCP_ULP`.
+// For example, `strace` says:
+//
+// [pid 813] setsockopt(4, SOL_TCP, 0x1f /* TCP_??? */, [7564404], 4) = 0
+//
+// It's not clear why `setsockopt(SOL_TCP, TCP_ULP)` succeeds if the container image libc doesn't support it,
+// but in any case we can't run the test on such an architecture, so skip it.
+#[cfg_attr(qemu, ignore)]
+#[test]
+fn test_ktls() {
+ use nix::sys::socket::{
+ accept, bind, connect, getsockname, listen, Backlog, SockaddrIn,
+ };
+ use std::net::SocketAddrV4;
+ use std::str::FromStr;
+
+ let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap();
+ let mut sock_addr = SockaddrIn::from(std_sa);
+
+ let rsock = socket(
+ AddressFamily::Inet,
+ SockType::Stream,
+ SockFlag::empty(),
+ SockProtocol::Tcp,
+ )
+ .unwrap();
+ bind(rsock.as_raw_fd(), &sock_addr).unwrap();
+ sock_addr = getsockname(rsock.as_raw_fd()).unwrap();
+ listen(&rsock, Backlog::new(10).unwrap()).unwrap();
+
+ let ssock = socket(
+ AddressFamily::Inet,
+ SockType::Stream,
+ SockFlag::empty(),
+ SockProtocol::Tcp,
+ )
+ .unwrap();
+ connect(ssock.as_raw_fd(), &sock_addr).unwrap();
+
+ let _rsess = accept(rsock.as_raw_fd()).unwrap();
+
+ match setsockopt(&ssock, sockopt::TcpUlp::default(), b"tls") {
+ Ok(()) => (),
+
+ // TLS ULP is not enabled, so we can't test kTLS.
+ Err(nix::Error::ENOENT) => skip!("TLS ULP is not enabled"),
+
+ Err(err) => panic!("{err:?}"),
+ }
+
+ // In real life we would do a TLS handshake and extract the protocol version and secrets.
+ // For this test we just make some up.
+
+ let tx = sockopt::TlsCryptoInfo::Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128 {
+ info: libc::tls_crypto_info {
+ version: libc::TLS_1_2_VERSION,
+ cipher_type: libc::TLS_CIPHER_AES_GCM_128,
+ },
+ iv: *b"\x04\x05\x06\x07\x08\x09\x0a\x0b",
+ key: *b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ salt: *b"\x00\x01\x02\x03",
+ rec_seq: *b"\x00\x00\x00\x00\x00\x00\x00\x00",
+ });
+ setsockopt(&ssock, sockopt::TcpTlsTx, &tx)
+ .expect("setting TLS_TX after enabling TLS ULP should succeed");
+
+ let rx = sockopt::TlsCryptoInfo::Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128 {
+ info: libc::tls_crypto_info {
+ version: libc::TLS_1_2_VERSION,
+ cipher_type: libc::TLS_CIPHER_AES_GCM_128,
+ },
+ iv: *b"\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb",
+ key: *b"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
+ salt: *b"\xf0\xf1\xf2\xf3",
+ rec_seq: *b"\x00\x00\x00\x00\x00\x00\x00\x00",
+ });
+ match setsockopt(&ssock, sockopt::TcpTlsRx, &rx) {
+ Ok(()) => (),
+ Err(nix::Error::ENOPROTOOPT) => {
+ // TLS_TX was added in v4.13 and TLS_RX in v4.17, so we appear to be between that range.
+ // It's good enough that TLS_TX worked, so let the test succeed.
+ }
+ Err(err) => panic!("{err:?}"),
+ }
+}
diff --git a/third_party/rust/nix/test/sys/test_statfs.rs b/third_party/rust/nix/test/sys/test_statfs.rs
new file mode 100644
index 0000000000..66b3f2ce96
--- /dev/null
+++ b/third_party/rust/nix/test/sys/test_statfs.rs
@@ -0,0 +1,99 @@
+use nix::sys::statfs::*;
+use nix::sys::statvfs::*;
+use std::fs::File;
+use std::path::Path;
+
+fn check_fstatfs(path: &str) {
+ if !Path::new(path).exists() {
+ return;
+ }
+ let vfs = statvfs(path.as_bytes()).unwrap();
+ let file = File::open(path).unwrap();
+ let fs = fstatfs(&file).unwrap();
+ assert_fs_equals(fs, vfs);
+}
+
+fn check_statfs(path: &str) {
+ if !Path::new(path).exists() {
+ return;
+ }
+ let vfs = statvfs(path.as_bytes()).unwrap();
+ let fs = statfs(path.as_bytes()).unwrap();
+ assert_fs_equals(fs, vfs);
+}
+
+fn check_fstatfs_strict(path: &str) {
+ if !Path::new(path).exists() {
+ return;
+ }
+ let vfs = statvfs(path.as_bytes());
+ let file = File::open(path).unwrap();
+ let fs = fstatfs(&file);
+ assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
+}
+
+fn check_statfs_strict(path: &str) {
+ if !Path::new(path).exists() {
+ return;
+ }
+ let vfs = statvfs(path.as_bytes());
+ let fs = statfs(path.as_bytes());
+ assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
+}
+
+// The cast is not unnecessary on all platforms.
+#[allow(clippy::unnecessary_cast)]
+fn assert_fs_equals(fs: Statfs, vfs: Statvfs) {
+ assert_eq!(fs.files() as u64, vfs.files() as u64);
+ assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
+ assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
+}
+
+#[test]
+fn statfs_call() {
+ check_statfs("/tmp");
+ check_statfs("/dev");
+ check_statfs("/run");
+ check_statfs("/");
+}
+
+#[test]
+fn fstatfs_call() {
+ check_fstatfs("/tmp");
+ check_fstatfs("/dev");
+ check_fstatfs("/run");
+ check_fstatfs("/");
+}
+
+// This test is ignored because files_free/blocks_free can change after statvfs call and before
+// statfs call.
+#[test]
+#[ignore]
+fn statfs_call_strict() {
+ check_statfs_strict("/tmp");
+ check_statfs_strict("/dev");
+ check_statfs_strict("/run");
+ check_statfs_strict("/");
+}
+
+// This test is ignored because files_free/blocks_free can change after statvfs call and before
+// fstatfs call.
+#[test]
+#[ignore]
+fn fstatfs_call_strict() {
+ check_fstatfs_strict("/tmp");
+ check_fstatfs_strict("/dev");
+ check_fstatfs_strict("/run");
+ check_fstatfs_strict("/");
+}
+
+// The cast is not unnecessary on all platforms.
+#[allow(clippy::unnecessary_cast)]
+fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) {
+ assert_eq!(fs.files_free() as u64, vfs.files_free() as u64);
+ assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64);
+ assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64);
+ assert_eq!(fs.files() as u64, vfs.files() as u64);
+ assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
+ assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
+}
diff --git a/third_party/rust/nix/test/sys/test_statvfs.rs b/third_party/rust/nix/test/sys/test_statvfs.rs
new file mode 100644
index 0000000000..5c80965253
--- /dev/null
+++ b/third_party/rust/nix/test/sys/test_statvfs.rs
@@ -0,0 +1,13 @@
+use nix::sys::statvfs::*;
+use std::fs::File;
+
+#[test]
+fn statvfs_call() {
+ statvfs(&b"/"[..]).unwrap();
+}
+
+#[test]
+fn fstatvfs_call() {
+ let root = File::open("/").unwrap();
+ fstatvfs(&root).unwrap();
+}
diff --git a/third_party/rust/nix/test/sys/test_termios.rs b/third_party/rust/nix/test/sys/test_termios.rs
index 83919378a7..35cc7ab739 100644
--- a/third_party/rust/nix/test/sys/test_termios.rs
+++ b/third_party/rust/nix/test/sys/test_termios.rs
@@ -4,17 +4,26 @@ use tempfile::tempfile;
use nix::errno::Errno;
use nix::fcntl;
use nix::pty::openpty;
-use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags};
+use nix::sys::termios::{self, tcgetattr, BaudRate, LocalFlags, OutputFlags};
use nix::unistd::{read, write};
/// Helper function analogous to `std::io::Write::write_all`, but for `Fd`s
fn write_all<Fd: AsFd>(f: Fd, buf: &[u8]) {
let mut len = 0;
while len < buf.len() {
- len += write(f.as_fd().as_raw_fd(), &buf[len..]).unwrap();
+ len += write(f.as_fd(), &buf[len..]).unwrap();
}
}
+#[test]
+fn test_baudrate_try_from() {
+ assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0));
+ #[cfg(not(target_os = "haiku"))]
+ BaudRate::try_from(999999999).expect_err("assertion failed");
+ #[cfg(target_os = "haiku")]
+ BaudRate::try_from(99).expect_err("assertion failed");
+}
+
// Test tcgetattr on a terminal
#[test]
fn test_tcgetattr_pty() {
diff --git a/third_party/rust/nix/test/sys/test_time.rs b/third_party/rust/nix/test/sys/test_time.rs
new file mode 100644
index 0000000000..0510225a92
--- /dev/null
+++ b/third_party/rust/nix/test/sys/test_time.rs
@@ -0,0 +1,91 @@
+use nix::sys::time::{TimeSpec, TimeVal, TimeValLike};
+use std::time::Duration;
+
+#[test]
+pub fn test_timespec() {
+ assert_ne!(TimeSpec::seconds(1), TimeSpec::zero());
+ assert_eq!(
+ TimeSpec::seconds(1) + TimeSpec::seconds(2),
+ TimeSpec::seconds(3)
+ );
+ assert_eq!(
+ TimeSpec::minutes(3) + TimeSpec::seconds(2),
+ TimeSpec::seconds(182)
+ );
+}
+
+#[test]
+pub fn test_timespec_from() {
+ let duration = Duration::new(123, 123_456_789);
+ let timespec = TimeSpec::nanoseconds(123_123_456_789);
+
+ assert_eq!(TimeSpec::from(duration), timespec);
+ assert_eq!(Duration::from(timespec), duration);
+}
+
+#[test]
+pub fn test_timespec_neg() {
+ let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
+ let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123);
+
+ assert_eq!(a, -b);
+}
+
+#[test]
+pub fn test_timespec_ord() {
+ assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000));
+ assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001));
+ assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999));
+ assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999));
+ assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001));
+}
+
+#[test]
+pub fn test_timespec_fmt() {
+ assert_eq!(TimeSpec::zero().to_string(), "0 seconds");
+ assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds");
+ assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds");
+ assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds");
+ assert_eq!(TimeSpec::nanoseconds(42).to_string(), "0.000000042 seconds");
+ assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds");
+}
+
+#[test]
+pub fn test_timeval() {
+ assert_ne!(TimeVal::seconds(1), TimeVal::zero());
+ assert_eq!(
+ TimeVal::seconds(1) + TimeVal::seconds(2),
+ TimeVal::seconds(3)
+ );
+ assert_eq!(
+ TimeVal::minutes(3) + TimeVal::seconds(2),
+ TimeVal::seconds(182)
+ );
+}
+
+#[test]
+pub fn test_timeval_ord() {
+ assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000));
+ assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001));
+ assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999));
+ assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999));
+ assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001));
+}
+
+#[test]
+pub fn test_timeval_neg() {
+ let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
+ let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);
+
+ assert_eq!(a, -b);
+}
+
+#[test]
+pub fn test_timeval_fmt() {
+ assert_eq!(TimeVal::zero().to_string(), "0 seconds");
+ assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
+ assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
+ assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
+ assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds");
+ assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
+}
diff --git a/third_party/rust/nix/test/sys/test_timer.rs b/third_party/rust/nix/test/sys/test_timer.rs
new file mode 100644
index 0000000000..ffd146867b
--- /dev/null
+++ b/third_party/rust/nix/test/sys/test_timer.rs
@@ -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");
+ }
+}
diff --git a/third_party/rust/nix/test/sys/test_uio.rs b/third_party/rust/nix/test/sys/test_uio.rs
index fc09465f19..d035a7bb04 100644
--- a/third_party/rust/nix/test/sys/test_uio.rs
+++ b/third_party/rust/nix/test/sys/test_uio.rs
@@ -4,7 +4,7 @@ use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use std::fs::OpenOptions;
use std::io::IoSlice;
-use std::os::unix::io::{FromRawFd, OwnedFd};
+use std::os::unix::io::AsRawFd;
use std::{cmp, iter};
#[cfg(not(target_os = "redox"))]
@@ -44,22 +44,17 @@ fn test_writev() {
// FileDesc will close its filedesc (reader).
let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect();
- // Temporary workaround to cope with the existing RawFd pipe(2), should be
- // removed when pipe(2) becomes I/O-safe.
- let writer = unsafe { OwnedFd::from_raw_fd(writer) };
-
// 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_res = read(reader.as_raw_fd(), &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(reader).expect("closed reader");
}
#[test]
@@ -92,10 +87,6 @@ fn test_readv() {
// Blocking io, should write all data.
write(writer, &to_write).expect("write failed");
- // Temporary workaround to cope with the existing RawFd pipe(2), should be
- // removed when pipe(2) becomes I/O-safe.
- let reader = unsafe { OwnedFd::from_raw_fd(reader) };
-
let read = readv(&reader, &mut iovecs[..]).expect("read failed");
// Check whether we've read all data
assert_eq!(to_write.len(), read);
@@ -108,7 +99,6 @@ fn test_readv() {
assert_eq!(read_buf.len(), to_write.len());
// Check equality of written and read data
assert_eq!(&read_buf, &to_write);
- close(writer).expect("couldn't close writer");
}
#[test]
@@ -150,7 +140,11 @@ fn test_pread() {
}
#[test]
-#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
+#[cfg(not(any(
+ target_os = "redox",
+ target_os = "haiku",
+ target_os = "solaris"
+)))]
fn test_pwritev() {
use std::io::Read;
@@ -185,7 +179,11 @@ fn test_pwritev() {
}
#[test]
-#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
+#[cfg(not(any(
+ target_os = "redox",
+ target_os = "haiku",
+ target_os = "solaris"
+)))]
fn test_preadv() {
use std::io::Write;
@@ -230,6 +228,7 @@ fn test_process_vm_readv() {
use nix::sys::signal::*;
use nix::sys::wait::*;
use nix::unistd::ForkResult::*;
+ use std::os::unix::io::AsRawFd;
require_capability!("test_process_vm_readv", CAP_SYS_PTRACE);
let _m = crate::FORK_MTX.lock();
@@ -241,10 +240,10 @@ fn test_process_vm_readv() {
let (r, w) = pipe().unwrap();
match unsafe { fork() }.expect("Error: Fork Failed") {
Parent { child } => {
- close(w).unwrap();
+ drop(w);
// wait for child
- read(r, &mut [0u8]).unwrap();
- close(r).unwrap();
+ read(r.as_raw_fd(), &mut [0u8]).unwrap();
+ drop(r);
let ptr = vector.as_ptr() as usize;
let remote_iov = RemoteIoVec { base: ptr, len: 5 };
@@ -263,12 +262,11 @@ fn test_process_vm_readv() {
assert_eq!(20u8, buf.iter().sum());
}
Child => {
- let _ = close(r);
+ drop(r);
for i in &mut vector {
*i += 1;
}
let _ = write(w, b"\0");
- let _ = close(w);
loop {
pause();
}
diff --git a/third_party/rust/nix/test/sys/test_utsname.rs b/third_party/rust/nix/test/sys/test_utsname.rs
new file mode 100644
index 0000000000..8f84ac074f
--- /dev/null
+++ b/third_party/rust/nix/test/sys/test_utsname.rs
@@ -0,0 +1,17 @@
+#[cfg(target_os = "linux")]
+#[test]
+pub fn test_uname_linux() {
+ assert_eq!(nix::sys::utsname::uname().unwrap().sysname(), "Linux");
+}
+
+#[cfg(apple_targets)]
+#[test]
+pub fn test_uname_darwin() {
+ assert_eq!(nix::sys::utsname::uname().unwrap().sysname(), "Darwin");
+}
+
+#[cfg(target_os = "freebsd")]
+#[test]
+pub fn test_uname_freebsd() {
+ assert_eq!(nix::sys::utsname::uname().unwrap().sysname(), "FreeBSD");
+}
diff --git a/third_party/rust/nix/test/sys/test_wait.rs b/third_party/rust/nix/test/sys/test_wait.rs
index d472f1ec19..365b0165f8 100644
--- a/third_party/rust/nix/test/sys/test_wait.rs
+++ b/third_party/rust/nix/test/sys/test_wait.rs
@@ -33,7 +33,12 @@ fn test_wait_signal() {
//target_os = "haiku",
all(target_os = "linux", not(target_env = "uclibc")),
))]
-#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
+#[cfg(not(any(
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
+)))]
fn test_waitid_signal() {
let _m = crate::FORK_MTX.lock();
@@ -76,7 +81,12 @@ fn test_wait_exit() {
target_os = "haiku",
all(target_os = "linux", not(target_env = "uclibc")),
))]
-#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
+#[cfg(not(any(
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6"
+)))]
fn test_waitid_exit() {
let _m = crate::FORK_MTX.lock();
@@ -140,7 +150,7 @@ fn test_waitid_pid() {
}
}
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
// FIXME: qemu-user doesn't implement ptrace on most arches
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod ptrace {