diff --git a/.cirrus.yml b/.cirrus.yml index bc8f21de54..29175a2764 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -2,6 +2,9 @@ cargo_cache: folder: $CARGO_HOME/registry fingerprint_script: cat Cargo.lock || echo "" +env: + RUSTFLAGS: -D warnings + RUSTDOCFLAGS: -D warnings # 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 @@ -17,9 +20,11 @@ task: amd64_test_script: - . $HOME/.cargo/env - cargo test + - cargo doc --no-deps i386_test_script: - . $HOME/.cargo/env - cargo test --target i686-unknown-freebsd + - cargo doc --no-deps --target i686-unknown-freebsd before_cache_script: rm -rf $CARGO_HOME/registry/index # Test OSX and iOS in a full VM @@ -48,7 +53,7 @@ task: RUST_TEST_THREADS: 1 # QEMU works best with 1 thread HOME: /tmp/home PATH: $HOME/.cargo/bin:$PATH - RUSTFLAGS: --cfg qemu + RUSTFLAGS: --cfg qemu -D warnings matrix: - name: Linux arm gnueabi env: @@ -93,6 +98,7 @@ task: - . $HOME/.cargo/env || true - cross build --target $TARGET - cross test --target $TARGET + - cross doc --no-deps --target $TARGET before_cache_script: rm -rf $CARGO_HOME/registry/index # Tasks for Linux native builds @@ -107,7 +113,7 @@ task: arm_container: image: rust:1.46 env: - RUSTFLAGS: --cfg graviton + RUSTFLAGS: --cfg graviton -D warnings TARGET: aarch64-unknown-linux-gnu - name: Linux x86_64 container: @@ -125,6 +131,7 @@ task: script: - cargo build --target $TARGET --all-targets - cargo test --target $TARGET + - cargo doc --no-deps --target $TARGET before_cache_script: rm -rf $CARGO_HOME/registry/index # Tasks for cross-compiling, but no testing @@ -210,6 +217,7 @@ task: script: - cargo +$TOOLCHAIN check --target $TARGET - cargo +$TOOLCHAIN check --all-targets --target $TARGET + - cargo +$TOOLCHAIN doc --no-deps --target $TARGET before_cache_script: rm -rf $CARGO_HOME/registry/index # Test that we can build with the lowest version of all dependencies. diff --git a/CHANGELOG.md b/CHANGELOG.md index ee47ab83ce..0dfa5946b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[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)) ### Changed @@ -76,6 +78,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 +90,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)) diff --git a/Cargo.toml b/Cargo.toml index 9e48fc0ccd..fe0d3b521a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/lib.rs b/src/lib.rs index 1ae6381065..7a64b97ab5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ #![deny(unstable_features)] #![deny(missing_copy_implementations)] #![deny(missing_debug_implementations)] -#![deny(missing_docs)] +#![warn(missing_docs)] // Re-exported external crates pub use libc; diff --git a/src/sys/aio.rs b/src/sys/aio.rs index ae08a1fcd7..fcee28c52e 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -62,9 +62,9 @@ libc_enum! { pub enum LioOpcode { /// No operation LIO_NOP, - /// Write data as if by a call to [`aio_write`] + /// Write data as if by a call to [`AioCb::write`] LIO_WRITE, - /// Write data as if by a call to [`aio_read`] + /// Write data as if by a call to [`AioCb::read`] LIO_READ, } } diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 2f35680179..5d9821a762 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -49,7 +49,6 @@ pub mod mman; #[allow(missing_docs)] pub mod personality; -#[allow(missing_docs)] pub mod pthread; #[cfg(any(target_os = "android", @@ -70,11 +69,9 @@ pub mod quota; pub mod reboot; #[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))] -#[allow(missing_docs)] pub mod resource; #[cfg(not(target_os = "redox"))] -#[allow(missing_docs)] pub mod select; #[cfg(any(target_os = "android", @@ -82,10 +79,8 @@ pub mod select; target_os = "ios", target_os = "linux", target_os = "macos"))] -#[allow(missing_docs)] pub mod sendfile; -#[allow(missing_docs)] pub mod signal; #[cfg(any(target_os = "android", target_os = "linux"))] @@ -107,7 +102,6 @@ pub mod stat; target_os = "macos", target_os = "openbsd" ))] -#[allow(missing_docs)] pub mod statfs; pub mod statvfs; @@ -122,13 +116,10 @@ pub mod termios; #[allow(missing_docs)] pub mod time; -#[allow(missing_docs)] pub mod uio; -#[allow(missing_docs)] pub mod utsname; -#[allow(missing_docs)] pub mod wait; #[cfg(any(target_os = "android", target_os = "linux"))] diff --git a/src/sys/pthread.rs b/src/sys/pthread.rs index 9163c8d1cc..d42e45d13d 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 8f71375b25..c3bf29e86d 100644 --- a/src/sys/resource.rs +++ b/src/sys/resource.rs @@ -50,54 +50,88 @@ libc_enum! { #[non_exhaustive] pub enum Resource { #[cfg(not(any(target_os = "netbsd", target_os = "freebsd")))] + /// 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 a8035f79db..0a0e830dc0 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 a12c04117f..7a210c6fc3 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 89bcc1a280..1011930f8e 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -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 @@ -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>>(pid: Pid, signal: T) -> Result<()> { let res = unsafe { libc::kill(pid.into(), match signal.into() { @@ -797,12 +883,16 @@ pub fn kill>>(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>>(pgrp: Pid, signal: T) -> Result<()> { let res = unsafe { libc::killpg(pgrp.into(), @@ -814,6 +904,9 @@ pub fn killpg>>(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 f701a7312a..33585bb902 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), - /// 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/stat.rs b/src/sys/stat.rs index ed62b12d7e..c8f10419c3 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 27b72592b9..829be57f63 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(path: &P) -> Result { unsafe { let mut stat = mem::MaybeUninit::::uninit(); @@ -459,6 +505,14 @@ pub fn statfs(path: &P) -> Result { } } +/// 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(fd: &T) -> Result { unsafe { let mut stat = mem::MaybeUninit::::uninit(); diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 48a0efd8da..3abcde24fe 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 { 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 { 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 { /// 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 { 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 { 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 { 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 { 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{ 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(pub(crate) libc::iovec, PhantomData); impl IoVec { + /// 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 bf1a814d6d..98edee0428 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 6c5c0f0ed5..ee49e37dec 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>>(pid: P, options: Option) -> Result { use self::WaitStatus::*; @@ -237,6 +254,9 @@ pub fn waitpid>>(pid: P, options: Option) -> 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 { waitpid(None, None) }