diff options
37 files changed, 576 insertions, 169 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 3a74a4a4..f4cf98da 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -2,27 +2,53 @@ cargo_cache: folder: $CARGO_HOME/registry fingerprint_script: cat Cargo.lock || echo "" +env: + # Build by default; don't just check + BUILD: build + RUSTFLAGS: -D warnings + RUSTDOCFLAGS: -D warnings + TOOL: cargo + # The MSRV + TOOLCHAIN: 1.46.0 + ZFLAGS: + +# Tests that don't require executing the build binaries +build: &BUILD + build_script: + - . $HOME/.cargo/env || true + - $TOOL +$TOOLCHAIN $BUILD $ZFLAGS --target $TARGET --all-targets + - $TOOL +$TOOLCHAIN doc $ZFLAGS --no-deps --target $TARGET + +# Tests that do require executing the binaries +test: &TEST + << : *BUILD + test_script: + - . $HOME/.cargo/env || true + - $TOOL +$TOOLCHAIN test --target $TARGET + # Test FreeBSD in a full VM. Test the i686 target too, in the # same VM. The binary will be built in 32-bit mode, but will execute on a # 64-bit kernel and in a 64-bit environment. Our tests don't execute any of # the system's binaries, so the environment shouldn't matter. task: name: FreeBSD amd64 & i686 + env: + TARGET: x86_64-unknown-freebsd freebsd_instance: image: freebsd-11-4-release-amd64 setup_script: - fetch https://sh.rustup.rs -o rustup.sh - - sh rustup.sh -y --profile=minimal --default-toolchain 1.46.0 + - sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN - $HOME/.cargo/bin/rustup target add i686-unknown-freebsd - amd64_test_script: - - . $HOME/.cargo/env - - cargo test + << : *TEST i386_test_script: - . $HOME/.cargo/env + - cargo build --target i686-unknown-freebsd + - cargo doc --no-deps --target i686-unknown-freebsd - cargo test --target i686-unknown-freebsd before_cache_script: rm -rf $CARGO_HOME/registry/index -# Test OSX and iOS in a full VM +# Test OSX in a full VM task: matrix: - name: OSX x86_64 @@ -32,13 +58,9 @@ task: image: catalina-xcode setup_script: - curl --proto '=https' --tlsv1.2 -sSf -o rustup.sh https://sh.rustup.rs - - sh rustup.sh -y --profile=minimal --default-toolchain 1.46.0 - - . $HOME/.cargo/env - - cargo install cross - script: + - sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN - . $HOME/.cargo/env - - cross build --target $TARGET - - cross test --target $TARGET + << : *TEST before_cache_script: rm -rf $CARGO_HOME/registry/index # Use cross for QEMU-based testing @@ -48,10 +70,9 @@ task: RUST_TEST_THREADS: 1 # QEMU works best with 1 thread HOME: /tmp/home PATH: $HOME/.cargo/bin:$PATH + RUSTFLAGS: --cfg qemu -D warnings + TOOL: cross matrix: - - name: Linux aarch64 - env: - TARGET: aarch64-unknown-linux-gnu - name: Linux arm gnueabi env: TARGET: arm-unknown-linux-gnueabi @@ -88,38 +109,40 @@ task: setup_script: - mkdir /tmp/home - curl --proto '=https' --tlsv1.2 -sSf -o rustup.sh https://sh.rustup.rs - - sh rustup.sh -y --profile=minimal --default-toolchain 1.46.0 + - sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN - . $HOME/.cargo/env - cargo install cross - script: - - . $HOME/.cargo/env || true - - cross build --target $TARGET - - cross test --target $TARGET + << : *TEST before_cache_script: rm -rf $CARGO_HOME/registry/index -# Tasks for Linux amd64 builds +# Tasks for Linux native builds task: matrix: - name: Rust Stable + container: + image: rust:latest env: TARGET: x86_64-unknown-linux-gnu - TOOLCHAIN: stable + TOOLCHAIN: + - name: Linux aarch64 + arm_container: + image: rust:1.46 + env: + RUSTFLAGS: --cfg graviton -D warnings + TARGET: aarch64-unknown-linux-gnu - name: Linux x86_64 + container: + image: rust:1.46 env: TARGET: x86_64-unknown-linux-gnu - TOOLCHAIN: 1.46.0 - name: Linux x86_64 musl + container: + image: rust:1.46 env: TARGET: x86_64-unknown-linux-musl - TOOLCHAIN: 1.46.0 - container: - image: rust:1.46 setup_script: - - rustup toolchain install $TOOLCHAIN - - rustup target add --toolchain $TOOLCHAIN $TARGET - script: - - cargo +$TOOLCHAIN build --target $TARGET --all-targets - - cargo +$TOOLCHAIN test --target $TARGET + - rustup target add $TARGET + << : *TEST before_cache_script: rm -rf $CARGO_HOME/registry/index # Tasks for cross-compiling, but no testing @@ -127,7 +150,7 @@ task: container: image: rust:1.46 env: - TOOLCHAIN: 1.46.0 + BUILD: check matrix: # Cross claims to support Android, but when it tries to run Nix's tests it # reports undefined symbol references. @@ -166,8 +189,7 @@ task: TARGET: aarch64-apple-ios # Rustup only supports cross-building from arbitrary hosts for iOS at # 1.49.0 and above. Below that it's possible to cross-build from an OSX - # host, but OSX VMs - # are more expensive than Linux VMs. + # host, but OSX VMs are more expensive than Linux VMs. TOOLCHAIN: 1.49.0 - name: iOS x86_64 env: @@ -202,9 +224,27 @@ task: setup_script: - rustup target add $TARGET - rustup toolchain install $TOOLCHAIN --profile minimal --target $TARGET - script: - - cargo +$TOOLCHAIN check --target $TARGET - - cargo +$TOOLCHAIN check --all-targets --target $TARGET + << : *BUILD + before_cache_script: rm -rf $CARGO_HOME/registry/index + +# Rust Tier 3 targets can't use Rustup +task: + container: + image: rustlang/rust:nightly + env: + BUILD: check + TOOLCHAIN: nightly + ZFLAGS: -Zbuild-std + matrix: + - name: DragonFly BSD x86_64 + env: + TARGET: x86_64-unknown-dragonfly + - name: OpenBSD x86_64 + env: + TARGET: x86_64-unknown-openbsd + setup_script: + - rustup component add rust-src + << : *BUILD before_cache_script: rm -rf $CARGO_HOME/registry/index # Test that we can build with the lowest version of all dependencies. @@ -212,6 +252,8 @@ task: # rand, can't build with their own minimal dependencies. task: name: Minver + env: + TOOLCHAIN: nightly container: image: rustlang/rust:nightly setup_script: diff --git a/CHANGELOG.md b/CHANGELOG.md index d01351f4..8865c59f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1335](https://github.com/nix-rust/nix/pull/1335)) - Exposed `SockAddr::from_raw_sockaddr` (#[1447](https://github.com/nix-rust/nix/pull/1447)) +- Added `TcpRepair` + (#[1503](https://github.com/nix-rust/nix/pull/1503)) +- Enabled `pwritev` and `preadv` for more operating systems. + (#[1511](https://github.com/nix-rust/nix/pull/1511)) - Added support for `TCP_MAXSEG` TCP Maximum Segment Size socket options (#[1292](https://github.com/nix-rust/nix/pull/1292)) @@ -76,6 +80,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Removed a couple of termios constants on redox that were never actually supported. (#[1483](https://github.com/nix-rust/nix/pull/1483)) + - Removed `nix::sys::signal::NSIG`. It was of dubious utility, and not correct for all platforms. (#[1484](https://github.com/nix-rust/nix/pull/1484)) @@ -87,6 +92,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Deprecated `SockAddr/InetAddr::to_str` in favor of `ToString::to_string` (#[1495](https://github.com/nix-rust/nix/pull/1495)) +- Removed `SigevNotify` on OpenBSD and Redox. + (#[1511](https://github.com/nix-rust/nix/pull/1511)) + ## [0.22.0] - 9 July 2021 ### Added - Added `if_nameindex` (#[1445](https://github.com/nix-rust/nix/pull/1445)) @@ -25,7 +25,7 @@ targets = [ ] [dependencies] -libc = { git = "https://github.com/rust-lang/libc", rev = "f5e31f208", features = [ "extra_traits" ] } +libc = { git = "https://github.com/rust-lang/libc", rev = "621a95373", features = [ "extra_traits" ] } bitflags = "1.3.1" cfg-if = "1.0" @@ -1,2 +1,5 @@ [build.env] -passthrough = ["RUST_TEST_THREADS"] +passthrough = [ + "RUSTFLAGS", + "RUST_TEST_THREADS" +] @@ -74,12 +74,15 @@ Tier 2: * s390x-unknown-linux-gnu * x86_64-apple-ios * x86_64-linux-android + * x86_64-unknown-illumos * x86_64-unknown-netbsd Tier 3: * x86_64-fuchsia - * x86_64-unknown-redox + * x86_64-unknown-dragonfly * x86_64-unknown-linux-gnux32 + * x86_64-unknown-openbsd + * x86_64-unknown-redox ## Usage @@ -4,6 +4,7 @@ status = [ "Android armv7", "Android i686", "Android x86_64", + "DragonFly BSD x86_64", "FreeBSD amd64 & i686", "Fuchsia x86_64", "Linux MIPS", @@ -25,12 +26,13 @@ status = [ "Linux x86_64", "Minver", "NetBSD x86_64", + "OpenBSD x86_64", "OSX x86_64", "Redox x86_64", "Rust Stable", "iOS aarch64", "iOS x86_64", - "illumos", + "Illumos", ] # Set bors's timeout to 1 hour @@ -1,3 +1,4 @@ +//! Environment variables use cfg_if::cfg_if; use std::fmt; @@ -5,15 +5,13 @@ #![crate_name = "nix"] #![cfg(unix)] #![allow(non_camel_case_types)] -// latest bitflags triggers a rustc bug with cross-crate macro expansions causing dead_code -// warnings even though the macro expands into something with allow(dead_code) -#![allow(dead_code)] #![cfg_attr(test, deny(warnings))] #![recursion_limit = "500"] #![deny(unused)] #![deny(unstable_features)] #![deny(missing_copy_implementations)] #![deny(missing_debug_implementations)] +#![warn(missing_docs)] // Re-exported external crates pub use libc; @@ -23,13 +21,14 @@ pub use libc; // Public crates #[cfg(not(target_os = "redox"))] +#[allow(missing_docs)] pub mod dir; pub mod env; +#[allow(missing_docs)] pub mod errno; -#[deny(missing_docs)] pub mod features; +#[allow(missing_docs)] pub mod fcntl; -#[deny(missing_docs)] #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", @@ -42,6 +41,7 @@ pub mod fcntl; pub mod ifaddrs; #[cfg(any(target_os = "android", target_os = "linux"))] +#[allow(missing_docs)] pub mod kmod; #[cfg(any(target_os = "android", target_os = "freebsd", @@ -52,23 +52,24 @@ pub mod mount; target_os = "fushsia", target_os = "linux", target_os = "netbsd"))] +#[allow(missing_docs)] pub mod mqueue; -#[deny(missing_docs)] #[cfg(not(target_os = "redox"))] pub mod net; -#[deny(missing_docs)] pub mod poll; -#[deny(missing_docs)] #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] pub mod pty; pub mod sched; pub mod sys; +#[allow(missing_docs)] pub mod time; // This can be implemented for other platforms as soon as libc // provides bindings for them. #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] +#[allow(missing_docs)] pub mod ucontext; +#[allow(missing_docs)] pub mod unistd; /* @@ -101,11 +102,17 @@ pub type Result<T> = result::Result<T, Errno>; /// ones. pub type Error = Errno; +/// Common trait used to represent file system paths by many Nix functions. pub trait NixPath { + /// Is the path empty? fn is_empty(&self) -> bool; + /// Length of the path in bytes fn len(&self) -> usize; + /// Execute a function with this path as a `CStr`. + /// + /// Mostly used internally by Nix. fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T; } diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs index f0a9443a..9913fc20 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd.rs @@ -347,6 +347,7 @@ impl<'a> Nmount<'a> { self } + /// Create a new `Nmount` struct with no options pub fn new() -> Self { Self::default() } diff --git a/src/mount/mod.rs b/src/mount/mod.rs index 8538bf3d..00303b6a 100644 --- a/src/mount/mod.rs +++ b/src/mount/mod.rs @@ -1,7 +1,10 @@ +//! Mount file systems #[cfg(any(target_os = "android", target_os = "linux"))] +#[allow(missing_docs)] mod linux; #[cfg(any(target_os = "android", target_os = "linux"))] +#[allow(missing_docs)] pub use self::linux::*; #[cfg(any(target_os = "dragonfly", diff --git a/src/sched.rs b/src/sched.rs index 575bf24b..69436fdf 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -1,3 +1,7 @@ +//! Execution scheduling +//! +//! See Also +//! [sched.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sched.h.html) use crate::{Errno, Result}; #[cfg(any(target_os = "android", target_os = "linux"))] @@ -16,33 +20,70 @@ mod sched_linux_like { // For some functions taking with a parameter of type CloneFlags, // only a subset of these flags have an effect. libc_bitflags! { + /// Options for use with [`clone`] pub struct CloneFlags: c_int { + /// The calling process and the child process run in the same + /// memory space. CLONE_VM; + /// The caller and the child process share the same filesystem + /// information. CLONE_FS; + /// The calling process and the child process share the same file + /// descriptor table. CLONE_FILES; + /// The calling process and the child process share the same table + /// of signal handlers. CLONE_SIGHAND; + /// If the calling process is being traced, then trace the child + /// also. CLONE_PTRACE; + /// The execution of the calling process is suspended until the + /// child releases its virtual memory resources via a call to + /// execve(2) or _exit(2) (as with vfork(2)). CLONE_VFORK; + /// The parent of the new child (as returned by getppid(2)) + /// will be the same as that of the calling process. CLONE_PARENT; + /// The child is placed in the same thread group as the calling + /// process. CLONE_THREAD; + /// The cloned child is started in a new mount namespace. CLONE_NEWNS; + /// The child and the calling process share a single list of System + /// V semaphore adjustment values CLONE_SYSVSEM; - CLONE_SETTLS; - CLONE_PARENT_SETTID; - CLONE_CHILD_CLEARTID; + // Not supported by Nix due to lack of varargs support in Rust FFI + // CLONE_SETTLS; + // Not supported by Nix due to lack of varargs support in Rust FFI + // CLONE_PARENT_SETTID; + // Not supported by Nix due to lack of varargs support in Rust FFI + // CLONE_CHILD_CLEARTID; + /// Unused since Linux 2.6.2 + #[deprecated(since = "0.23.0", note = "Deprecated by Linux 2.6.2")] CLONE_DETACHED; + /// A tracing process cannot force `CLONE_PTRACE` on this child + /// process. CLONE_UNTRACED; - CLONE_CHILD_SETTID; + // Not supported by Nix due to lack of varargs support in Rust FFI + // CLONE_CHILD_SETTID; + /// Create the process in a new cgroup namespace. CLONE_NEWCGROUP; + /// Create the process in a new UTS namespace. CLONE_NEWUTS; + /// Create the process in a new IPC namespace. CLONE_NEWIPC; + /// Create the process in a new user namespace. CLONE_NEWUSER; + /// Create the process in a new PID namespace. CLONE_NEWPID; + /// Create the process in a new network namespace. CLONE_NEWNET; + /// The new process shares an I/O context with the calling process. CLONE_IO; } } + /// Type for the function executed by [`clone`]. pub type CloneCb<'a> = Box<dyn FnMut() -> isize + 'a>; /// CpuSet represent a bit-mask of CPUs. @@ -212,12 +253,18 @@ mod sched_linux_like { Errno::result(res).map(Pid::from_raw) } + /// disassociate parts of the process execution context + /// + /// See also [unshare(2)](https://man7.org/linux/man-pages/man2/unshare.2.html) pub fn unshare(flags: CloneFlags) -> Result<()> { let res = unsafe { libc::unshare(flags.bits()) }; Errno::result(res).map(drop) } + /// reassociate thread with a namespace + /// + /// See also [setns(2)](https://man7.org/linux/man-pages/man2/setns.2.html) pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> { let res = unsafe { libc::setns(fd, nstype.bits()) }; diff --git a/src/sys/aio.rs b/src/sys/aio.rs index 71a2184d..fcee28c5 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -60,8 +60,11 @@ libc_enum! { #[repr(i32)] #[non_exhaustive] pub enum LioOpcode { + /// No operation LIO_NOP, + /// Write data as if by a call to [`AioCb::write`] LIO_WRITE, + /// Write data as if by a call to [`AioCb::read`] LIO_READ, } } @@ -840,6 +843,7 @@ unsafe impl<'a> Sync for LioCb<'a> {} #[cfg(not(any(target_os = "ios", target_os = "macos")))] impl<'a> LioCb<'a> { + /// Are no [`AioCb`]s contained? pub fn is_empty(&self) -> bool { self.aiocbs.is_empty() } diff --git a/src/sys/mman.rs b/src/sys/mman.rs index a8d6d7c9..33ac21de 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -65,8 +65,8 @@ libc_bitflags!{ MAP_LOCKED; /// Do not reserve swap space for this mapping. /// - /// This was removed in FreeBSD 11. - #[cfg(not(target_os = "freebsd"))] + /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. + #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))] MAP_NORESERVE; /// Populate page tables for a mapping. #[cfg(any(target_os = "android", target_os = "linux"))] @@ -122,8 +122,8 @@ libc_bitflags!{ MAP_NOSYNC; /// Rename private pages to a file. /// - /// This was removed in FreeBSD 11. - #[cfg(any(target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))] + /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. + #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] MAP_RENAME; /// Region may contain semaphores. #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] diff --git a/src/sys/mod.rs b/src/sys/mod.rs index cffefdc3..5d9821a7 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -1,3 +1,4 @@ +//! Mostly platform-specific functionality #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -7,6 +8,7 @@ pub mod aio; #[cfg(any(target_os = "android", target_os = "linux"))] +#[allow(missing_docs)] pub mod epoll; #[cfg(any(target_os = "dragonfly", @@ -15,9 +17,11 @@ pub mod epoll; target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] +#[allow(missing_docs)] pub mod event; #[cfg(any(target_os = "android", target_os = "linux"))] +#[allow(missing_docs)] pub mod eventfd; #[cfg(any(target_os = "android", @@ -34,12 +38,15 @@ pub mod eventfd; pub mod ioctl; #[cfg(target_os = "linux")] +#[allow(missing_docs)] pub mod memfd; #[cfg(not(target_os = "redox"))] +#[allow(missing_docs)] pub mod mman; #[cfg(target_os = "linux")] +#[allow(missing_docs)] pub mod personality; pub mod pthread; @@ -51,12 +58,14 @@ pub mod pthread; target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] +#[allow(missing_docs)] pub mod ptrace; #[cfg(target_os = "linux")] pub mod quota; #[cfg(any(target_os = "linux"))] +#[allow(missing_docs)] pub mod reboot; #[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))] @@ -75,11 +84,14 @@ pub mod sendfile; pub mod signal; #[cfg(any(target_os = "android", target_os = "linux"))] +#[allow(missing_docs)] pub mod signalfd; #[cfg(not(target_os = "redox"))] +#[allow(missing_docs)] pub mod socket; +#[allow(missing_docs)] pub mod stat; #[cfg(any(target_os = "android", @@ -95,10 +107,13 @@ pub mod statfs; pub mod statvfs; #[cfg(any(target_os = "android", target_os = "linux"))] +#[allow(missing_docs)] pub mod sysinfo; +#[allow(missing_docs)] pub mod termios; +#[allow(missing_docs)] pub mod time; pub mod uio; @@ -108,7 +123,9 @@ pub mod utsname; pub mod wait; #[cfg(any(target_os = "android", target_os = "linux"))] +#[allow(missing_docs)] pub mod inotify; #[cfg(target_os = "linux")] +#[allow(missing_docs)] pub mod timerfd; diff --git a/src/sys/pthread.rs b/src/sys/pthread.rs index 9163c8d1..d42e45d1 100644 --- a/src/sys/pthread.rs +++ b/src/sys/pthread.rs @@ -1,3 +1,5 @@ +//! Low level threading primitives + #[cfg(not(target_os = "redox"))] use crate::errno::Errno; #[cfg(not(target_os = "redox"))] @@ -6,6 +8,7 @@ use crate::Result; use crate::sys::signal::Signal; use libc::{self, pthread_t}; +/// Identifies an individual thread. pub type Pthread = pthread_t; /// Obtain ID of the calling thread (see diff --git a/src/sys/resource.rs b/src/sys/resource.rs index 8f71375b..dd7f8c5c 100644 --- a/src/sys/resource.rs +++ b/src/sys/resource.rs @@ -49,55 +49,93 @@ libc_enum! { ), repr(i32))] #[non_exhaustive] pub enum Resource { - #[cfg(not(any(target_os = "netbsd", target_os = "freebsd")))] + #[cfg(not(any( + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + )))] + /// The maximum amount (in bytes) of virtual memory the process is + /// allowed to map. RLIMIT_AS, + /// The largest size (in bytes) core(5) file that may be created. RLIMIT_CORE, + /// The maximum amount of cpu time (in seconds) to be used by each + /// process. RLIMIT_CPU, + /// The maximum size (in bytes) of the data segment for a process RLIMIT_DATA, + /// The largest size (in bytes) file that may be created. RLIMIT_FSIZE, + /// The maximum number of open files for this process. RLIMIT_NOFILE, + /// The maximum size (in bytes) of the stack segment for a process. RLIMIT_STACK, #[cfg(target_os = "freebsd")] + /// The maximum number of kqueues this user id is allowed to create. RLIMIT_KQUEUES, #[cfg(any(target_os = "android", target_os = "linux"))] + /// A limit on the combined number of flock locks and fcntl leases that + /// this process may establish. RLIMIT_LOCKS, #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))] + /// The maximum size (in bytes) which a process may lock into memory + /// using the mlock(2) system call. RLIMIT_MEMLOCK, #[cfg(any(target_os = "android", target_os = "linux"))] + /// A limit on the number of bytes that can be allocated for POSIX + /// message queues for the real user ID of the calling process. RLIMIT_MSGQUEUE, #[cfg(any(target_os = "android", target_os = "linux"))] + /// A ceiling to which the process's nice value can be raised using + /// setpriority or nice. RLIMIT_NICE, #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))] + /// The maximum number of simultaneous processes for this user id. RLIMIT_NPROC, #[cfg(target_os = "freebsd")] + /// The maximum number of pseudo-terminals this user id is allowed to + /// create. RLIMIT_NPTS, #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))] + /// When there is memory pressure and swap is available, prioritize + /// eviction of a process' resident pages beyond this amount (in bytes). RLIMIT_RSS, #[cfg(any(target_os = "android", target_os = "linux"))] + /// A ceiling on the real-time priority that may be set for this process + /// using sched_setscheduler and sched_set‐ param. RLIMIT_RTPRIO, #[cfg(any(target_os = "linux"))] + /// A limit (in microseconds) on the amount of CPU time that a process + /// scheduled under a real-time scheduling policy may con‐ sume without + /// making a blocking system call. RLIMIT_RTTIME, #[cfg(any(target_os = "android", target_os = "linux"))] + /// A limit on the number of signals that may be queued for the real + /// user ID of the calling process. RLIMIT_SIGPENDING, #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + /// The maximum size (in bytes) of socket buffer usage for this user. RLIMIT_SBSIZE, #[cfg(target_os = "freebsd")] + /// The maximum size (in bytes) of the swap space that may be reserved + /// or used by all of this user id's processes. RLIMIT_SWAP, #[cfg(target_os = "freebsd")] + /// An alias for RLIMIT_AS. RLIMIT_VMEM, } } diff --git a/src/sys/select.rs b/src/sys/select.rs index a8035f79..0a0e830d 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -1,3 +1,4 @@ +//! Portably monitor a group of file descriptors for readiness. use std::iter::FusedIterator; use std::mem; use std::ops::Range; @@ -11,11 +12,13 @@ use crate::sys::time::{TimeSpec, TimeVal}; pub use libc::FD_SETSIZE; +/// Contains a set of file descriptors used by [`select`] #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct FdSet(libc::fd_set); impl FdSet { + /// Create an empty `FdSet` pub fn new() -> FdSet { let mut fdset = mem::MaybeUninit::uninit(); unsafe { @@ -24,18 +27,22 @@ impl FdSet { } } + /// Add a file descriptor to an `FdSet` pub fn insert(&mut self, fd: RawFd) { unsafe { libc::FD_SET(fd, &mut self.0) }; } + /// Remove a file descriptor from an `FdSet` pub fn remove(&mut self, fd: RawFd) { unsafe { libc::FD_CLR(fd, &mut self.0) }; } + /// Test an `FdSet` for the presence of a certain file descriptor. pub fn contains(&self, fd: RawFd) -> bool { unsafe { libc::FD_ISSET(fd, &self.0) } } + /// Remove all file descriptors from this `FdSet`. pub fn clear(&mut self) { unsafe { libc::FD_ZERO(&mut self.0) }; } diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs index a12c0411..7a210c6f 100644 --- a/src/sys/sendfile.rs +++ b/src/sys/sendfile.rs @@ -1,3 +1,5 @@ +//! Send data from a file to a socket, bypassing userland. + use cfg_if::cfg_if; use std::os::unix::io::RawFd; use std::ptr; diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 95663687..1011930f 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -1,7 +1,7 @@ // Portions of this file are Copyright 2014 The Rust Project Developers. // See https://www.rust-lang.org/policies/licenses. -///! Operating system signals. +//! Operating system signals. use crate::{Error, Result}; use crate::errno::Errno; @@ -17,6 +17,7 @@ use std::ptr; pub use self::sigevent::*; libc_enum!{ + /// Types of operating system signals // Currently there is only one definition of c_int in libc, as well as only one // type for signal constants. // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately @@ -24,50 +25,83 @@ libc_enum!{ #[repr(i32)] #[non_exhaustive] pub enum Signal { + /// Hangup SIGHUP, + /// Interrupt SIGINT, + /// Quit SIGQUIT, + /// Illegal instruction (not reset when caught) SIGILL, + /// Trace trap (not reset when caught) SIGTRAP, + /// Abort SIGABRT, + /// Bus error SIGBUS, + /// Floating point exception SIGFPE, + /// Kill (cannot be caught or ignored) SIGKILL, + /// User defined signal 1 SIGUSR1, + /// Segmentation violation SIGSEGV, + /// User defined signal 2 SIGUSR2, + /// Write on a pipe with no one to read it SIGPIPE, + /// Alarm clock SIGALRM, + /// Software termination signal from kill SIGTERM, + /// Stack fault (obsolete) #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))] SIGSTKFLT, + /// To parent on child stop or exit SIGCHLD, + /// Continue a stopped process SIGCONT, + /// Sendable stop signal not from tty SIGSTOP, + /// Stop signal from tty SIGTSTP, + /// To readers pgrp upon background tty read SIGTTIN, + /// Like TTIN if (tp->t_local<OSTOP) SIGTTOU, + /// Urgent condition on IO channel SIGURG, + /// Exceeded CPU time limit SIGXCPU, + /// Exceeded file size limit SIGXFSZ, + /// Virtual time alarm SIGVTALRM, + /// Profiling time alarm SIGPROF, + /// Window size changes SIGWINCH, + /// Input/output possible signal SIGIO, #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] + /// Power failure imminent. SIGPWR, + /// Bad system call SIGSYS, #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", target_os = "redox")))] + /// Emulator trap SIGEMT, #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", target_os = "redox")))] + /// Information request SIGINFO, } impl TryFrom<i32> @@ -336,6 +370,7 @@ const SIGNALS: [Signal; 31] = [ SIGINFO]; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +/// Iterate through all signals defined by this operating system pub struct SignalIterator { next: usize, } @@ -355,13 +390,17 @@ impl Iterator for SignalIterator { } impl Signal { + /// Iterate through all signals defined by this OS pub const fn iterator() -> SignalIterator { SignalIterator{next: 0} } } +/// Alias for [`SIGABRT`] pub const SIGIOT : Signal = SIGABRT; +/// Alias for [`SIGIO`] pub const SIGPOLL : Signal = SIGIO; +/// Alias for [`SIGSYS`] pub const SIGUNUSED : Signal = SIGSYS; #[cfg(not(target_os = "redox"))] @@ -370,27 +409,48 @@ type SaFlags_t = libc::c_int; type SaFlags_t = libc::c_ulong; libc_bitflags!{ + /// Controls the behavior of a [`SigAction`] pub struct SaFlags: SaFlags_t { + /// When catching a [`Signal::SIGCHLD`] signal, the signal will be + /// generated only when a child process exits, not when a child process + /// stops. SA_NOCLDSTOP; + /// When catching a [`Signal::SIGCHLD`] signal, the system will not + /// create zombie processes when children of the calling process exit. SA_NOCLDWAIT; + /// Further occurrences of the delivered signal are not masked during + /// the execution of the handler. SA_NODEFER; + /// The system will deliver the signal to the process on a signal stack, + /// specified by each thread with sigaltstack(2). SA_ONSTACK; + /// The handler is reset back to the default at the moment the signal is + /// delivered. SA_RESETHAND; + /// Requests that certain system calls restart if interrupted by this + /// signal. See the man page for complete details. SA_RESTART; + /// This flag is controlled internally by Nix. SA_SIGINFO; } } libc_enum! { + /// Specifies how certain functions should manipulate a signal mask #[repr(i32)] #[non_exhaustive] pub enum SigmaskHow { + /// The new mask is the union of the current mask and the specified set. SIG_BLOCK, + /// The new mask is the intersection of the current mask and the + /// complement of the specified set. SIG_UNBLOCK, + /// The current mask is replaced by the specified set. SIG_SETMASK, } } +/// Specifies a set of [`Signal`]s that may be blocked, waited for, etc. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct SigSet { sigset: libc::sigset_t @@ -398,6 +458,7 @@ pub struct SigSet { impl SigSet { + /// Initialize to include all signals. pub fn all() -> SigSet { let mut sigset = mem::MaybeUninit::uninit(); let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) }; @@ -405,6 +466,7 @@ impl SigSet { unsafe{ SigSet { sigset: sigset.assume_init() } } } + /// Initialize to include nothing. pub fn empty() -> SigSet { let mut sigset = mem::MaybeUninit::uninit(); let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) }; @@ -412,18 +474,22 @@ impl SigSet { unsafe{ SigSet { sigset: sigset.assume_init() } } } + /// Add the specified signal to the set. pub fn add(&mut self, signal: Signal) { unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; } + /// Remove all signals from this set. pub fn clear(&mut self) { unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) }; } + /// Remove the specified signal from this set. pub fn remove(&mut self, signal: Signal) { unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; } + /// Return whether this set includes the specified signal. pub fn contains(&self, signal: Signal) -> bool { let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) }; @@ -434,6 +500,8 @@ impl SigSet { } } + /// Merge all of `other`'s signals into this set. + // TODO: use libc::sigorset on supported operating systems. pub fn extend(&mut self, other: &SigSet) { for signal in Signal::iterator() { if other.contains(signal) { @@ -787,6 +855,24 @@ pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut Si Errno::result(res).map(drop) } +/// Send a signal to a process +/// +/// # Arguments +/// +/// * `pid` - Specifies which processes should receive the signal. +/// - If positive, specifies an individual process +/// - If zero, the signal will be sent to all processes whose group +/// ID is equal to the process group ID of the sender. This is a +/// variant of [`killpg`]. +/// - If `-1` and the process has super-user privileges, the signal +/// is sent to all processes exclusing system processes. +/// - If less than `-1`, the signal is sent to all processes whose +/// process group ID is equal to the absolute value of `pid`. +/// * `signal` - Signal to send. If 0, error checking if performed but no +/// signal is actually sent. +/// +/// See Also +/// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html) pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> { let res = unsafe { libc::kill(pid.into(), match signal.into() { @@ -797,12 +883,16 @@ pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> { Errno::result(res).map(drop) } -/// Send a signal to a process group [(see -/// killpg(3))](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html). +/// Send a signal to a process group +/// +/// # Arguments /// -/// If `pgrp` less then or equal 1, the behavior is platform-specific. -/// If `signal` is `None`, `killpg` will only preform error checking and won't -/// send any signal. +/// * `pgrp` - Process group to signal. If less then or equal 1, the behavior +/// is platform-specific. +/// * `signal` - Signal to send. If `None`, `killpg` will only preform error +/// checking and won't send any signal. +/// +/// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html). #[cfg(not(target_os = "fuchsia"))] pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> { let res = unsafe { libc::killpg(pgrp.into(), @@ -814,6 +904,9 @@ pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> { Errno::result(res).map(drop) } +/// Send a signal to the current thread +/// +/// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html) pub fn raise(signal: Signal) -> Result<()> { let res = unsafe { libc::raise(signal as libc::c_int) }; @@ -821,36 +914,51 @@ pub fn raise(signal: Signal) -> Result<()> { } +/// Identifies a thread for [`SigevNotify::SigevThreadId`] #[cfg(target_os = "freebsd")] pub type type_of_thread_id = libc::lwpid_t; +/// Identifies a thread for [`SigevNotify::SigevThreadId`] #[cfg(target_os = "linux")] pub type type_of_thread_id = libc::pid_t; -/// Used to request asynchronous notification of certain events, for example, -/// with POSIX AIO, POSIX message queues, and POSIX timers. +/// Specifies the notification method used by a [`SigEvent`] // sigval is actually a union of a int and a void*. But it's never really used // as a pointer, because neither libc nor the kernel ever dereference it. nix // therefore presents it as an intptr_t, which is how kevent uses it. +#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum SigevNotify { /// No notification will be delivered SigevNone, - /// The signal given by `signal` will be delivered to the process. The - /// value in `si_value` will be present in the `si_value` field of the - /// `siginfo_t` structure of the queued signal. - SigevSignal { signal: Signal, si_value: libc::intptr_t }, + /// Notify by delivering a signal to the process. + SigevSignal { + /// Signal to deliver + signal: Signal, + /// Will be present in the `si_value` field of the [`libc::siginfo_t`] + /// structure of the queued signal. + si_value: libc::intptr_t + }, // Note: SIGEV_THREAD is not implemented because libc::sigevent does not // expose a way to set the union members needed by SIGEV_THREAD. - /// A new `kevent` is posted to the kqueue `kq`. The `kevent`'s `udata` - /// field will contain the value in `udata`. + /// Notify by delivering an event to a kqueue. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevKevent { kq: RawFd, udata: libc::intptr_t }, - /// The signal `signal` is queued to the thread whose LWP ID is given in - /// `thread_id`. The value stored in `si_value` will be present in the - /// `si_value` of the `siginfo_t` structure of the queued signal. + SigevKevent { + /// File descriptor of the kqueue to notify. + kq: RawFd, + /// Will be contained in the kevent's `udata` field. + udata: libc::intptr_t + }, + /// Notify by delivering a signal to a thread. #[cfg(any(target_os = "freebsd", target_os = "linux"))] - SigevThreadId { signal: Signal, thread_id: type_of_thread_id, - si_value: libc::intptr_t }, + SigevThreadId { + /// Signal to send + signal: Signal, + /// LWP ID of the thread to notify + thread_id: type_of_thread_id, + /// Will be present in the `si_value` field of the [`libc::siginfo_t`] + /// structure of the queued signal. + si_value: libc::intptr_t + }, } #[cfg(not(any(target_os = "openbsd", target_os = "redox")))] @@ -932,6 +1040,7 @@ mod sigevent { fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) { } + /// Return a copy of the inner structure pub fn sigevent(&self) -> libc::sigevent { self.sigevent } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index f701a731..33585bb9 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -526,15 +526,12 @@ impl<'a> Iterator for CmsgIterator<'a> { #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] pub enum ControlMessageOwned { - /// Received version of - /// [`ControlMessage::ScmRights`][#enum.ControlMessage.html#variant.ScmRights] + /// Received version of [`ControlMessage::ScmRights`] ScmRights(Vec<RawFd>), - /// Received version of - /// [`ControlMessage::ScmCredentials`][#enum.ControlMessage.html#variant.ScmCredentials] + /// Received version of [`ControlMessage::ScmCredentials`] #[cfg(any(target_os = "android", target_os = "linux"))] ScmCredentials(UnixCredentials), - /// Received version of - /// [`ControlMessage::ScmCreds`][#enum.ControlMessage.html#variant.ScmCreds] + /// Received version of [`ControlMessage::ScmCreds`] #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ScmCreds(UnixCredentials), /// A message of type `SCM_TIMESTAMP`, containing the time the @@ -808,7 +805,7 @@ pub enum ControlMessage<'a> { /// /// Credentials are always overwritten by the kernel, so this variant does have /// any data, unlike the receive-side - /// [`ControlMessageOwned::ScmCreds`][#enum.ControlMessageOwned.html#variant.ScmCreds]. + /// [`ControlMessageOwned::ScmCreds`]. /// /// For further information, please refer to the /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page. diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 90f3cb3d..67f5f71e 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -274,6 +274,10 @@ cfg_if! { } #[cfg(not(target_os = "openbsd"))] sockopt_impl!(Both, TcpKeepCount, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32); +#[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "linux"))] +sockopt_impl!(Both, TcpRepair, libc::IPPROTO_TCP, libc::TCP_REPAIR, u32); #[cfg(not(target_os = "openbsd"))] sockopt_impl!(Both, TcpKeepInterval, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32); #[cfg(any(target_os = "fuchsia", target_os = "linux"))] diff --git a/src/sys/stat.rs b/src/sys/stat.rs index ed62b12d..c8f10419 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -256,6 +256,7 @@ pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> { } /// Flags for `utimensat` function. +// TODO: replace with fcntl::AtFlags #[derive(Clone, Copy, Debug)] pub enum UtimensatFlags { FollowSymlink, diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 27b72592..829be57f 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -1,3 +1,6 @@ +//! Get filesystem statistics, non-portably +//! +//! See [`statvfs`](crate::sys::statvfs) for a portable alternative. use std::fmt::{self, Debug}; use std::mem; use std::os::unix::io::AsRawFd; @@ -6,11 +9,14 @@ use std::ffi::CStr; use crate::{NixPath, Result, errno::Errno}; +/// Identifies a mounted file system #[cfg(target_os = "android")] pub type fsid_t = libc::__fsid_t; +/// Identifies a mounted file system #[cfg(not(target_os = "android"))] pub type fsid_t = libc::fsid_t; +/// Describes a mounted file system #[derive(Clone, Copy)] #[repr(transparent)] pub struct Statfs(libc::statfs); @@ -26,6 +32,7 @@ type fs_type_t = libc::c_ulong; #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))] type fs_type_t = libc::__fsword_t; +/// Describes the file system type as known by the operating system. #[cfg(any( target_os = "freebsd", target_os = "android", @@ -36,63 +43,94 @@ type fs_type_t = libc::__fsword_t; #[derive(Eq, Copy, Clone, PartialEq, Debug)] pub struct FsType(pub fs_type_t); +// These constants are defined without documentation in the Linux headers, so we +// can't very well document them here. #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const OVERLAYFS_SUPER_MAGIC: FsType = FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[allow(missing_docs)] pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t); @@ -451,6 +489,14 @@ impl Debug for Statfs { } } +/// Describes a mounted file system. +/// +/// The result is OS-dependent. For a portabable alternative, see +/// [`statvfs`](crate::sys::statvfs::statvfs). +/// +/// # Arguments +/// +/// `path` - Path to any file within the file system to describe pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> { unsafe { let mut stat = mem::MaybeUninit::<libc::statfs>::uninit(); @@ -459,6 +505,14 @@ pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> { } } +/// Describes a mounted file system. +/// +/// The result is OS-dependent. For a portabable alternative, see +/// [`fstatvfs`](crate::sys::statvfs::fstatvfs). +/// +/// # Arguments +/// +/// `fd` - File descriptor of any open file within the file system to describe pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> { unsafe { let mut stat = mem::MaybeUninit::<libc::statfs>::uninit(); diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 48a0efd8..3abcde24 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -1,5 +1,4 @@ -// Silence invalid warnings due to rust-lang/rust#16719 -#![allow(improper_ctypes)] +//! Vectored I/O use crate::Result; use crate::errno::Errno; @@ -7,12 +6,18 @@ use libc::{self, c_int, c_void, size_t, off_t}; use std::marker::PhantomData; use std::os::unix::io::RawFd; +/// Low-level vectored write to a raw file descriptor +/// +/// See also [writev(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html) pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result<usize> { let res = unsafe { libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; Errno::result(res).map(|r| r as usize) } +/// Low-level vectored read from a raw file descriptor +/// +/// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html) pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> { let res = unsafe { libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; @@ -25,11 +30,7 @@ pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> { /// or an error occurs. The file offset is not changed. /// /// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd"))] +#[cfg(not(target_os = "redox"))] pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], offset: off_t) -> Result<usize> { let res = unsafe { @@ -46,11 +47,7 @@ pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], /// changed. /// /// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd"))] +#[cfg(not(target_os = "redox"))] pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>], offset: off_t) -> Result<usize> { let res = unsafe { @@ -60,6 +57,10 @@ pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>], Errno::result(res).map(|r| r as usize) } +/// Low-level write to a file, with specified offset. +/// +/// See also [pwrite(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html) +// TODO: move to unistd pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> { let res = unsafe { libc::pwrite(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, @@ -69,6 +70,10 @@ pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> { Errno::result(res).map(|r| r as usize) } +/// Low-level write to a file, with specified offset. +/// +/// See also [pread(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html) +// TODO: move to unistd pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{ let res = unsafe { libc::pread(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t, @@ -166,11 +171,17 @@ pub fn process_vm_readv( Errno::result(res).map(|r| r as usize) } +/// A vector of buffers. +/// +/// Vectored I/O methods like [`writev`] and [`readv`] use this structure for +/// both reading and writing. Each `IoVec` specifies the base address and +/// length of an area in memory. #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct IoVec<T>(pub(crate) libc::iovec, PhantomData<T>); impl<T> IoVec<T> { + /// View the `IoVec` as a Rust slice. #[inline] pub fn as_slice(&self) -> &[u8] { use std::slice; @@ -192,6 +203,7 @@ impl<'a> IoVec<&'a [u8]> { }, PhantomData) } + /// Create an `IoVec` from a Rust slice. pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> { IoVec(libc::iovec { iov_base: buf.as_ptr() as *mut c_void, @@ -201,6 +213,7 @@ impl<'a> IoVec<&'a [u8]> { } impl<'a> IoVec<&'a mut [u8]> { + /// Create an `IoVec` from a mutable Rust slice. pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> { IoVec(libc::iovec { iov_base: buf.as_ptr() as *mut c_void, diff --git a/src/sys/utsname.rs b/src/sys/utsname.rs index bf1a814d..98edee04 100644 --- a/src/sys/utsname.rs +++ b/src/sys/utsname.rs @@ -1,34 +1,42 @@ +//! Get system identification use std::mem; use libc::{self, c_char}; use std::ffi::CStr; use std::str::from_utf8_unchecked; +/// Describes the running system. Return type of [`uname`]. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct UtsName(libc::utsname); impl UtsName { + /// Name of the operating system implementation pub fn sysname(&self) -> &str { to_str(&(&self.0.sysname as *const c_char ) as *const *const c_char) } + /// Network name of this machine. pub fn nodename(&self) -> &str { to_str(&(&self.0.nodename as *const c_char ) as *const *const c_char) } + /// Release level of the operating system. pub fn release(&self) -> &str { to_str(&(&self.0.release as *const c_char ) as *const *const c_char) } + /// Version level of the operating system. pub fn version(&self) -> &str { to_str(&(&self.0.version as *const c_char ) as *const *const c_char) } + /// Machine hardware platform. pub fn machine(&self) -> &str { to_str(&(&self.0.machine as *const c_char ) as *const *const c_char) } } +/// Get system identification pub fn uname() -> UtsName { unsafe { let mut ret = mem::MaybeUninit::uninit(); diff --git a/src/sys/wait.rs b/src/sys/wait.rs index 6c5c0f0e..ee49e37d 100644 --- a/src/sys/wait.rs +++ b/src/sys/wait.rs @@ -1,3 +1,4 @@ +//! Wait for a process to change status use crate::errno::Errno; use crate::sys::signal::Signal; use crate::unistd::Pid; @@ -7,9 +8,17 @@ use libc::{self, c_int}; use std::convert::TryFrom; libc_bitflags!( + /// Controls the behavior of [`waitpid`]. pub struct WaitPidFlag: c_int { + /// Do not block when there are no processes wishing to report status. WNOHANG; + /// Report the status of selected processes which are stopped due to a + /// [`SIGTTIN`](crate::sys::signal::Signal::SIGTTIN), + /// [`SIGTTOU`](crate::sys::signal::Signal::SIGTTOU), + /// [`SIGTSTP`](crate::sys::signal::Signal::SIGTSTP), or + /// [`SIGSTOP`](crate::sys::signal::Signal::SIGSTOP) signal. WUNTRACED; + /// Report the status of selected processes which have terminated. #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "haiku", @@ -19,7 +28,11 @@ libc_bitflags!( target_os = "macos", target_os = "netbsd"))] WEXITED; + /// Report the status of selected processes that have continued from a + /// job control stop by receiving a + /// [`SIGCONT`](crate::sys::signal::Signal::SIGCONT) signal. WCONTINUED; + /// An alias for WUNTRACED. #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "haiku", @@ -45,6 +58,7 @@ libc_bitflags!( /// Wait on all children, regardless of type #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] __WALL; + /// Wait for "clone" children only. #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] __WCLONE; } @@ -213,6 +227,9 @@ impl WaitStatus { } } +/// Wait for a process to change status +/// +/// See also [waitpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html) pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Result<WaitStatus> { use self::WaitStatus::*; @@ -237,6 +254,9 @@ pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Re } } +/// Wait for any child process to change status or a signal is received. +/// +/// See also [wait(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html) pub fn wait() -> Result<WaitStatus> { waitpid(None, None) } diff --git a/src/unistd.rs b/src/unistd.rs index e42f83a5..25b20051 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2742,7 +2742,7 @@ impl From<User> for libc::passwd { pw_age: CString::new("").unwrap().into_raw(), #[cfg(target_os = "illumos")] pw_comment: CString::new("").unwrap().into_raw(), - #[cfg(target_os = "freebsd")] + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] pw_fields: 0, } } diff --git a/test/common/mod.rs b/test/common/mod.rs index cdc32582..84a0b4fa 100644 --- a/test/common/mod.rs +++ b/test/common/mod.rs @@ -14,19 +14,19 @@ use cfg_if::cfg_if; cfg_if! { if #[cfg(any(target_os = "android", target_os = "linux"))] { #[macro_export] macro_rules! require_capability { - ($capname:ident) => { + ($name:expr, $capname:ident) => { use ::caps::{Capability, CapSet, has_cap}; if !has_cap(None, CapSet::Effective, Capability::$capname) .unwrap() { - skip!("Insufficient capabilities. Skipping test."); + skip!("{} requires capability {}. Skipping test.", $name, Capability::$capname); } } } } else if #[cfg(not(target_os = "redox"))] { #[macro_export] macro_rules! require_capability { - ($capname:ident) => {} + ($name:expr, $capname:ident) => {} } } } diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs index ceb39b9b..1c72e7c2 100644 --- a/test/sys/test_ptrace.rs +++ b/test/sys/test_ptrace.rs @@ -13,7 +13,7 @@ use crate::*; fn test_ptrace() { // Just make sure ptrace can be called at all, for now. // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS - require_capability!(CAP_SYS_PTRACE); + require_capability!("test_ptrace", CAP_SYS_PTRACE); let err = ptrace::attach(getpid()).unwrap_err(); assert!(err == Errno::EPERM || err == Errno::EINVAL || err == Errno::ENOSYS); @@ -23,7 +23,7 @@ fn test_ptrace() { #[test] #[cfg(any(target_os = "android", target_os = "linux"))] fn test_ptrace_setoptions() { - require_capability!(CAP_SYS_PTRACE); + require_capability!("test_ptrace_setoptions", CAP_SYS_PTRACE); let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err(); assert!(err != Errno::EOPNOTSUPP); } @@ -32,7 +32,7 @@ fn test_ptrace_setoptions() { #[test] #[cfg(any(target_os = "android", target_os = "linux"))] fn test_ptrace_getevent() { - require_capability!(CAP_SYS_PTRACE); + require_capability!("test_ptrace_getevent", CAP_SYS_PTRACE); let err = ptrace::getevent(getpid()).unwrap_err(); assert!(err != Errno::EOPNOTSUPP); } @@ -41,7 +41,7 @@ fn test_ptrace_getevent() { #[test] #[cfg(any(target_os = "android", target_os = "linux"))] fn test_ptrace_getsiginfo() { - require_capability!(CAP_SYS_PTRACE); + require_capability!("test_ptrace_getsiginfo", CAP_SYS_PTRACE); if let Err(Errno::EOPNOTSUPP) = ptrace::getsiginfo(getpid()) { panic!("ptrace_getsiginfo returns Errno::EOPNOTSUPP!"); } @@ -51,7 +51,7 @@ fn test_ptrace_getsiginfo() { #[test] #[cfg(any(target_os = "android", target_os = "linux"))] fn test_ptrace_setsiginfo() { - require_capability!(CAP_SYS_PTRACE); + require_capability!("test_ptrace_setsiginfo", CAP_SYS_PTRACE); let siginfo = unsafe { mem::zeroed() }; if let Err(Errno::EOPNOTSUPP) = ptrace::setsiginfo(getpid(), &siginfo) { panic!("ptrace_setsiginfo returns Errno::EOPNOTSUPP!"); @@ -67,7 +67,7 @@ fn test_ptrace_cont() { use nix::unistd::fork; use nix::unistd::ForkResult::*; - require_capability!(CAP_SYS_PTRACE); + require_capability!("test_ptrace_cont", CAP_SYS_PTRACE); let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); @@ -125,7 +125,7 @@ fn test_ptrace_interrupt() { use std::thread::sleep; use std::time::Duration; - require_capability!(CAP_SYS_PTRACE); + require_capability!("test_ptrace_interrupt", CAP_SYS_PTRACE); let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); @@ -171,7 +171,7 @@ fn test_ptrace_syscall() { use nix::unistd::getpid; use nix::unistd::ForkResult::*; - require_capability!(CAP_SYS_PTRACE); + require_capability!("test_ptrace_syscall", CAP_SYS_PTRACE); let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 92bb30e0..aceffccb 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -288,9 +288,9 @@ mod recvfrom { use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment}; #[test] - // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU - // support is suspected. - #[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)] + // Disable the test under emulation because it fails in Cirrus-CI. Lack + // of QEMU support is suspected. + #[cfg_attr(qemu, ignore)] pub fn gso() { require_kernel_version!(udp_offload::gso, ">= 4.18"); @@ -342,9 +342,9 @@ mod recvfrom { } #[test] - // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU - // support is suspected. - #[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)] + // Disable the test on emulated platforms because it fails in Cirrus-CI. + // Lack of QEMU support is suspected. + #[cfg_attr(qemu, ignore)] pub fn gro() { require_kernel_version!(udp_offload::gro, ">= 5.3"); @@ -583,7 +583,7 @@ pub fn test_recvmsg_ebadf() { // Disable the test on emulated platforms due to a bug in QEMU versions < // 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 -#[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)] +#[cfg_attr(qemu, ignore)] #[test] pub fn test_scm_rights() { use nix::sys::uio::IoVec; @@ -637,8 +637,8 @@ pub fn test_scm_rights() { } // Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross -#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "i686")), ignore)] #[cfg(any(target_os = "linux", target_os= "android"))] +#[cfg_attr(qemu, ignore)] #[test] pub fn test_af_alg_cipher() { use libc; @@ -705,9 +705,10 @@ pub fn test_af_alg_cipher() { assert_eq!(decrypted, payload); } -// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross -#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "i686")), ignore)] +// 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_attr(qemu, ignore)] #[test] pub fn test_af_alg_aead() { use libc::{ALG_OP_DECRYPT, ALG_OP_ENCRYPT}; @@ -910,7 +911,7 @@ pub fn test_sendmsg_ipv6packetinfo() { /// Tests that passing multiple fds using a single `ControlMessage` works. // Disable the test on emulated platforms due to a bug in QEMU versions < // 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808 -#[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)] +#[cfg_attr(qemu, ignore)] #[test] fn test_scm_rights_single_cmsg_multiple_fds() { use std::os::unix::net::UnixDatagram; @@ -1057,9 +1058,9 @@ 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"))] -// qemu's handling of multiple cmsgs is bugged, ignore tests on non-x86 +// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation // see https://bugs.launchpad.net/qemu/+bug/1781280 -#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "x86")), ignore)] +#[cfg_attr(qemu, ignore)] #[test] fn test_scm_credentials_and_rights() { use libc; @@ -1071,9 +1072,9 @@ 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"))] -// qemu's handling of multiple cmsgs is bugged, ignore tests on non-x86 +// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation // see https://bugs.launchpad.net/qemu/+bug/1781280 -#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "x86")), ignore)] +#[cfg_attr(qemu, ignore)] #[test] fn test_too_large_cmsgspace() { let space = vec![0u8; 1024]; @@ -1262,10 +1263,13 @@ fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddr target_os = "netbsd", ))] // qemu doesn't seem to be emulating this correctly in these architectures -#[cfg_attr(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc64", +#[cfg_attr(all( + qemu, + any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + ) ), ignore)] #[test] pub fn test_recv_ipv4pktinfo() { @@ -1352,10 +1356,13 @@ pub fn test_recv_ipv4pktinfo() { target_os = "openbsd", ))] // qemu doesn't seem to be emulating this correctly in these architectures -#[cfg_attr(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc64", +#[cfg_attr(all( + qemu, + any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + ) ), ignore)] #[test] pub fn test_recvif() { @@ -1463,10 +1470,13 @@ pub fn test_recvif() { target_os = "openbsd", ))] // qemu doesn't seem to be emulating this correctly in these architectures -#[cfg_attr(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc64", +#[cfg_attr(all( + qemu, + any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + ) ), ignore)] #[test] pub fn test_recv_ipv6pktinfo() { @@ -1544,6 +1554,7 @@ pub fn test_recv_ipv6pktinfo() { } #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(graviton, ignore = "Not supported by the CI environment")] #[test] pub fn test_vsock() { use libc; @@ -1588,9 +1599,9 @@ pub fn test_vsock() { thr.join().unwrap(); } -// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU -// support is suspected. -#[cfg_attr(not(any(target_arch = "x86_64")), ignore)] +// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack +// of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] #[cfg(all(target_os = "linux"))] #[test] fn test_recvmsg_timestampns() { @@ -1639,9 +1650,9 @@ fn test_recvmsg_timestampns() { nix::unistd::close(in_socket).unwrap(); } -// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU -// support is suspected. -#[cfg_attr(not(any(target_arch = "x86_64")), ignore)] +// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack +// of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] #[cfg(all(target_os = "linux"))] #[test] fn test_recvmmsg_timestampns() { @@ -1696,9 +1707,9 @@ fn test_recvmmsg_timestampns() { nix::unistd::close(in_socket).unwrap(); } -// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU -// support is suspected. -#[cfg_attr(not(any(target_arch = "x86_64")), ignore)] +// 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"))] #[test] fn test_recvmsg_rxq_ovfl() { diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 72c9a315..45e969f4 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -49,7 +49,7 @@ pub fn test_local_peercred_stream() { fn is_so_mark_functional() { use nix::sys::socket::sockopt; - require_capability!(CAP_NET_ADMIN); + require_capability!("is_so_mark_functional", CAP_NET_ADMIN); let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); setsockopt(s, sockopt::Mark, &1337).unwrap(); diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index 9dd4f01d..8f8ba5e4 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -205,15 +205,15 @@ fn test_preadv() { #[test] #[cfg(target_os = "linux")] -// FIXME: qemu-user doesn't implement process_vm_readv/writev on most arches -#[cfg_attr(not(any(target_arch = "x86", target_arch = "x86_64")), ignore)] +// qemu-user doesn't implement process_vm_readv/writev on most arches +#[cfg_attr(qemu, ignore)] fn test_process_vm_readv() { use nix::unistd::ForkResult::*; use nix::sys::signal::*; use nix::sys::wait::*; use crate::*; - require_capability!(CAP_SYS_PTRACE); + require_capability!("test_process_vm_readv", CAP_SYS_PTRACE); let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); // Pre-allocate memory in the child, since allocation isn't safe diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs index 2d26fb8e..4a5b9661 100644 --- a/test/sys/test_wait.rs +++ b/test/sys/test_wait.rs @@ -96,7 +96,7 @@ mod ptrace { #[test] fn test_wait_ptrace() { - require_capability!(CAP_SYS_PTRACE); + require_capability!("test_wait_ptrace", CAP_SYS_PTRACE); let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test"); match unsafe{fork()}.expect("Error: Fork Failed") { diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index e74a8598..c19a1b0a 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -236,14 +236,8 @@ mod linux_android { /// The from_offset should be updated by the call to reflect /// the 3 bytes read (6). #[test] - // QEMU does not support copy_file_range. Skip platforms that use QEMU in CI - #[cfg_attr(all(target_os = "linux", any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc64" - )), ignore)] + // QEMU does not support copy_file_range. Skip under qemu + #[cfg_attr(qemu, ignore)] fn test_copy_file_range() { const CONTENTS: &[u8] = b"foobarbaz"; diff --git a/test/test_kmod/mod.rs b/test/test_kmod/mod.rs index 76263305..e53e7a9e 100644 --- a/test/test_kmod/mod.rs +++ b/test/test_kmod/mod.rs @@ -41,7 +41,7 @@ use std::io::Read; #[test] fn test_finit_and_delete_module() { - require_capability!(CAP_SYS_MODULE); + require_capability!("test_finit_and_delete_module", CAP_SYS_MODULE); let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); @@ -58,8 +58,8 @@ fn test_finit_and_delete_module() { } #[test] -fn test_finit_and_delete_modul_with_params() { - require_capability!(CAP_SYS_MODULE); +fn test_finit_and_delete_module_with_params() { + require_capability!("test_finit_and_delete_module_with_params", CAP_SYS_MODULE); let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); @@ -80,7 +80,7 @@ fn test_finit_and_delete_modul_with_params() { #[test] fn test_init_and_delete_module() { - require_capability!(CAP_SYS_MODULE); + require_capability!("test_init_and_delete_module", CAP_SYS_MODULE); let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); @@ -100,7 +100,7 @@ fn test_init_and_delete_module() { #[test] fn test_init_and_delete_module_with_params() { - require_capability!(CAP_SYS_MODULE); + require_capability!("test_init_and_delete_module_with_params", CAP_SYS_MODULE); let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); @@ -121,7 +121,7 @@ fn test_init_and_delete_module_with_params() { #[test] fn test_finit_module_invalid() { - require_capability!(CAP_SYS_MODULE); + require_capability!("test_finit_module_invalid", CAP_SYS_MODULE); let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); @@ -135,7 +135,7 @@ fn test_finit_module_invalid() { #[test] fn test_finit_module_twice_and_delete_module() { - require_capability!(CAP_SYS_MODULE); + require_capability!("test_finit_module_twice_and_delete_module", CAP_SYS_MODULE); let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); @@ -157,7 +157,7 @@ fn test_finit_module_twice_and_delete_module() { #[test] fn test_delete_module_not_loaded() { - require_capability!(CAP_SYS_MODULE); + require_capability!("test_delete_module_not_loaded", CAP_SYS_MODULE); let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test"); let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test"); diff --git a/test/test_mq.rs b/test/test_mq.rs index d0826923..430df5dd 100644 --- a/test/test_mq.rs +++ b/test/test_mq.rs @@ -60,7 +60,11 @@ fn test_mq_getattr() { // FIXME: Fix failures for mips in QEMU #[test] #[cfg(not(any(target_os = "netbsd")))] -#[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)] +#[cfg_attr(all( + qemu, + any(target_arch = "mips", target_arch = "mips64") + ), ignore +)] fn test_mq_setattr() { use nix::mqueue::{mq_getattr, mq_setattr}; const MSG_SIZE: mq_attr_member_t = 32; @@ -97,7 +101,11 @@ fn test_mq_setattr() { // FIXME: Fix failures for mips in QEMU #[test] #[cfg(not(any(target_os = "netbsd")))] -#[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)] +#[cfg_attr(all( + qemu, + any(target_arch = "mips", target_arch = "mips64") + ), ignore +)] fn test_mq_set_nonblocking() { use nix::mqueue::{mq_getattr, mq_set_nonblock, mq_remove_nonblock}; const MSG_SIZE: mq_attr_member_t = 32; diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 37e7a9b3..cb23ba75 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -549,7 +549,7 @@ cfg_if!{ if #[cfg(any(target_os = "android", target_os = "linux"))] { macro_rules! require_acct{ () => { - require_capability!(CAP_SYS_PACCT); + require_capability!("test_acct", CAP_SYS_PACCT); } } } else if #[cfg(target_os = "freebsd")] { @@ -1040,7 +1040,7 @@ fn test_user_into_passwd() { fn test_setfsuid() { use std::os::unix::fs::PermissionsExt; use std::{fs, io, thread}; - require_capability!(CAP_SETUID); + require_capability!("test_setfsuid", CAP_SETUID); // get the UID of the "nobody" user let nobody = User::from_name("nobody").unwrap().unwrap(); |