From 54587ec651a53dd096754c1623ae8c4624d3740f Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 16 Oct 2021 18:19:56 -0600 Subject: [PATCH 001/358] Remove broken newlib support Nix has never supported a newlib target, but there were a few cfg checks for it in our codebase. Some of them were misspelled (newlibc vs newlib), and some of the checks were wrong. Removing them makes the code much more readable. --- src/time.rs | 91 +++++++++++++++++++++-------------------------------- 1 file changed, 35 insertions(+), 56 deletions(-) diff --git a/src/time.rs b/src/time.rs index 6275b59c74..91ed7c6d63 100644 --- a/src/time.rs +++ b/src/time.rs @@ -51,10 +51,8 @@ impl ClockId { #[cfg(not(any( target_os = "macos", target_os = "ios", - all( - not(any(target_env = "uclibc", target_env = "newlibc")), - any(target_os = "redox", target_os = "hermit",), - ), + target_os = "redox", + target_os = "hermit", )))] pub fn set_time(self, timespec: TimeSpec) -> Result<()> { clock_settime(self, timespec) @@ -66,28 +64,25 @@ impl ClockId { } #[cfg(any( + target_os = "android", + target_os = "emscripten", target_os = "fuchsia", - all( - not(any(target_env = "uclibc", target_env = "newlib")), - any(target_os = "linux", target_os = "android", target_os = "emscripten"), - ) + target_os = "linux" ))] pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME); #[cfg(any( + target_os = "android", + target_os = "emscripten", target_os = "fuchsia", - all( - not(any(target_env = "uclibc", target_env = "newlib")), - any(target_os = "linux", target_os = "android", target_os = "emscripten") - ) + target_os = "linux" ))] pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM); pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC); #[cfg(any( + target_os = "android", + target_os = "emscripten", target_os = "fuchsia", - all( - not(any(target_env = "uclibc", target_env = "newlib")), - any(target_os = "linux", target_os = "android", target_os = "emscripten") - ) + target_os = "linux" ))] pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] @@ -95,43 +90,39 @@ impl ClockId { #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE); #[cfg(any( + target_os = "android", + target_os = "emscripten", target_os = "fuchsia", - all( - not(any(target_env = "uclibc", target_env = "newlib")), - any(target_os = "linux", target_os = "android", target_os = "emscripten") - ) + target_os = "linux" ))] pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW); #[cfg(any( + target_os = "android", + target_os = "emscripten", target_os = "fuchsia", - target_env = "uclibc", target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "dragonfly", - all( - not(target_env = "newlib"), - any(target_os = "linux", target_os = "android", target_os = "emscripten") - ) + target_os = "redox", + target_os = "linux" ))] pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF); pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME); #[cfg(any( + target_os = "android", + target_os = "emscripten", target_os = "fuchsia", - all( - not(any(target_env = "uclibc", target_env = "newlib")), - any(target_os = "linux", target_os = "android", target_os = "emscripten") - ) + target_os = "linux" ))] pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM); #[cfg(any( + target_os = "android", + target_os = "emscripten", target_os = "fuchsia", - all( - not(any(target_env = "uclibc", target_env = "newlib")), - any(target_os = "linux", target_os = "android", target_os = "emscripten") - ) + target_os = "linux" ))] pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] @@ -141,38 +132,27 @@ impl ClockId { #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND); #[cfg(any( + target_os = "emscripten", target_os = "fuchsia", - all( - not(any(target_env = "uclibc", target_env = "newlib")), - any( - target_os = "emscripten", - all(target_os = "linux", target_env = "musl") - ) - ) + all(target_os = "linux", target_env = "musl") ))] pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE); #[cfg(any( + target_os = "android", + target_os = "emscripten", target_os = "fuchsia", - all( - not(any(target_env = "uclibc", target_env = "newlib")), - any( - target_os = "emscripten", - all(target_os = "linux", target_env = "musl") - ) - ) + target_os = "linux" ))] pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI); #[cfg(any( - target_env = "uclibc", + target_os = "android", + target_os = "emscripten", target_os = "fuchsia", target_os = "ios", target_os = "macos", target_os = "freebsd", target_os = "dragonfly", - all( - not(target_env = "newlib"), - any(target_os = "linux", target_os = "android", target_os = "emscripten",), - ), + target_os = "linux" ))] pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] @@ -229,10 +209,9 @@ pub fn clock_gettime(clock_id: ClockId) -> Result { #[cfg(not(any( target_os = "macos", target_os = "ios", - all( - not(any(target_env = "uclibc", target_env = "newlibc")), - any(target_os = "redox", target_os = "hermit",), - ), + target_env = "uclibc", + target_os = "redox", + target_os = "hermit", )))] pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) }; From 644d36cf1fa5515dade300e42de6f9877c892204 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Fri, 22 Oct 2021 22:50:29 -0500 Subject: [PATCH 002/358] Remove unsafe in with_nix_path() for [u8] --- src/lib.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3a2b63ab0b..9f09c9fdf3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,9 +78,9 @@ pub mod unistd; * */ -use libc::{c_char, PATH_MAX}; +use libc::PATH_MAX; -use std::{ptr, result}; +use std::result; use std::ffi::{CStr, OsStr}; use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; @@ -184,16 +184,10 @@ impl NixPath for [u8] { return Err(Errno::ENAMETOOLONG) } - match self.iter().position(|b| *b == 0) { - Some(_) => Err(Errno::EINVAL), - None => { - unsafe { - // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028 - ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len()); - Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char))) - } - - } + buf[..self.len()].copy_from_slice(self); + match CStr::from_bytes_with_nul(&buf[..=self.len()]) { + Ok(s) => Ok(f(s)), + Err(_) => Err(Errno::EINVAL), } } } From 131bae7a780216907e8aabc236116eb9967c9aa5 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Fri, 17 Dec 2021 09:38:44 -0600 Subject: [PATCH 003/358] Remove no-dev-version flag --- release.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/release.toml b/release.toml index df2c9da45d..23488fbfa5 100644 --- a/release.toml +++ b/release.toml @@ -1,4 +1,3 @@ -no-dev-version = true pre-release-replacements = [ { file="CHANGELOG.md", search="Unreleased", replace="{{version}}" }, { file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}" } From 5f5b7d4d7a76575673b57e685c13ba2c52c4183e Mon Sep 17 00:00:00 2001 From: Vincent Dagonneau Date: Thu, 19 Mar 2020 11:40:53 +0100 Subject: [PATCH 004/358] feature-gate most Nix functions Using features reduces build time and size for consumer crates. By default all features are enabled. --- .cirrus.yml | 23 +++- CHANGELOG.md | 9 ++ Cargo.toml | 43 +++++++ src/dir.rs | 43 +++---- src/fcntl.rs | 81 ++++++++++++- src/lib.rs | 139 ++++++++++++++++----- src/macros.rs | 14 +++ src/mount/bsd.rs | 15 +++ src/mount/mod.rs | 2 + src/mqueue.rs | 2 + src/net/if_.rs | 57 +++++++++ src/poll.rs | 18 ++- src/pty.rs | 12 +- src/sched.rs | 1 + src/sys/aio.rs | 5 + src/sys/epoll.rs | 1 + src/sys/inotify.rs | 18 +-- src/sys/mman.rs | 78 +++++++++++- src/sys/mod.rs | 175 +++++++++++++++++++-------- src/sys/pthread.rs | 10 +- src/sys/ptrace/bsd.rs | 5 + src/sys/ptrace/linux.rs | 5 +- src/sys/resource.rs | 15 +++ src/sys/select.rs | 8 +- src/sys/sendfile.rs | 2 + src/sys/signal.rs | 46 ++++++- src/sys/socket/addr.rs | 119 +++++++++++++++++- src/sys/socket/mod.rs | 134 ++++++++++++++++++--- src/sys/socket/sockopt.rs | 55 +++++++++ src/sys/stat.rs | 9 ++ src/sys/statfs.rs | 45 +++++++ src/sys/statvfs.rs | 11 ++ src/sys/termios.rs | 83 +++++++++++++ src/sys/uio.rs | 9 +- src/sys/wait.rs | 8 ++ src/time.rs | 31 +++++ src/unistd.rs | 246 ++++++++++++++++++++++++++++++++++++-- 37 files changed, 1399 insertions(+), 178 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 8d6e121020..7d2f41168f 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -19,6 +19,8 @@ build: &BUILD - $TOOL +$TOOLCHAIN $BUILD $ZFLAGS --target $TARGET --all-targets - $TOOL +$TOOLCHAIN doc $ZFLAGS --no-deps --target $TARGET - $TOOL +$TOOLCHAIN clippy $ZFLAGS --target $TARGET -- -D warnings + - if [ -z "$NOHACK" ]; then $TOOL install cargo-hack; fi + - if [ -z "$NOHACK" ]; then $TOOL hack $ZFLAGS check --target $TARGET --each-feature; fi # Tests that do require executing the binaries test: &TEST @@ -50,6 +52,9 @@ task: - cargo build --target i686-unknown-freebsd - cargo doc --no-deps --target i686-unknown-freebsd - cargo test --target i686-unknown-freebsd + i386_feature_script: + - . $HOME/.cargo/env + - cargo hack check --each-feature --target i686-unknown-freebsd before_cache_script: rm -rf $CARGO_HOME/registry/index # Test OSX in a full VM @@ -201,6 +206,8 @@ task: # https://github.com/rust-embedded/cross/issues/535 - name: iOS aarch64 env: + # cargo hack tries to invoke the iphonesimulator SDK for iOS + NOHACK: 1 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 @@ -208,6 +215,8 @@ task: TOOLCHAIN: 1.49.0 - name: iOS x86_64 env: + # cargo hack tries to invoke the iphonesimulator SDK for iOS + NOHACK: 1 TARGET: x86_64-apple-ios TOOLCHAIN: 1.49.0 # Cross testing on powerpc fails with "undefined reference to renameat2". @@ -244,11 +253,13 @@ task: BUILD: check name: Redox x86_64 env: - TARGET: x86_64-unknown-redox - # Redox requires a nightly compiler. - # If stuff breaks, change nightly to the date at - # https://gitlab.redox-os.org/redox-os/redox/-/blob/master/rust-toolchain - TOOLCHAIN: nightly-2021-06-15 + TARGET: x86_64-unknown-redox + # cargo-hack needs a newer compiler. # TODO: try enabling NOHACK. + NOHACK: 1 + # Redox requires a nightly compiler. + # If stuff breaks, change nightly to the date at + # https://gitlab.redox-os.org/redox-os/redox/-/blob/master/rust-toolchain + TOOLCHAIN: nightly-2021-06-15 setup_script: - rustup target add $TARGET - rustup toolchain install $TOOLCHAIN --profile minimal --target $TARGET @@ -310,6 +321,6 @@ task: image: rustlang/rust:nightly setup_script: - cargo update -Zminimal-versions - script: + check_script: - cargo check before_cache_script: rm -rf $CARGO_HOME/registry/index diff --git a/CHANGELOG.md b/CHANGELOG.md index 77d5b2a326..46a3eff4b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,15 @@ This project adheres to [Semantic Versioning](https://semver.org/). `0..FD_SETSIZE`. (#[1575](https://github.com/nix-rust/nix/pull/1575)) +## [Unreleased] - ReleaseDate +### Added + +- Added fine-grained features flags. Most Nix functionality can now be + conditionally enabled. By default, all features are enabled. + (#[1498](https://github.com/nix-rust/nix/pull/1498)) + +### Changed +### Fixed ### Removed ## [0.23.0] - 2021-09-28 diff --git a/Cargo.toml b/Cargo.toml index d2ca8ee804..e515e4eb69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ categories = ["os::unix-apis"] include = ["src/**/*", "test/**/*", "LICENSE", "README.md", "CHANGELOG.md"] [package.metadata.docs.rs] +rustdoc-args = ["--cfg", "docsrs"] targets = [ "x86_64-unknown-linux-gnu", "aarch64-linux-android", @@ -33,6 +34,48 @@ cfg-if = "1.0" [target.'cfg(not(target_os = "redox"))'.dependencies] memoffset = "0.6.3" +[features] +default = [ + "acct", "aio", "dir", "env", "event", "features", "fs", + "hostname", "inotify", "ioctl", "kmod", "mman", "mount", "mqueue", + "net", "personality", "poll", "process", "pthread", "ptrace", "quota", + "reboot", "resource", "sched", "signal", "socket", "term", "time", + "ucontext", "uio", "users", "zerocopy", +] + +acct = [] +aio = [] +dir = ["fs"] +env = [] +event = [] +features = [] +fs = [] +hostname = [] +inotify = [] +ioctl = [] +kmod = [] +mman = [] +mount = ["uio"] +mqueue = ["fs"] +net = ["socket"] +personality = [] +poll = [] +pthread = [] +ptrace = ["process"] +quota = [] +process = [] +reboot = [] +resource = [] +sched = ["process"] +signal = ["process"] +socket = [] +term = [] +time = [] +ucontext = ["signal"] +uio = [] +users = ["features"] +zerocopy = ["fs", "uio"] + [target.'cfg(target_os = "dragonfly")'.build-dependencies] cc = "1" diff --git a/src/dir.rs b/src/dir.rs index ed70a458ac..62e7b4d5b6 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -5,6 +5,7 @@ use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; use std::ptr; use std::ffi; use crate::sys; +use cfg_if::cfg_if; #[cfg(target_os = "linux")] use libc::{dirent64 as dirent, readdir64_r as readdir_r}; @@ -186,34 +187,24 @@ pub enum Type { impl Entry { /// Returns the inode number (`d_ino`) of the underlying `dirent`. - #[cfg(any(target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", - target_os = "l4re", - target_os = "linux", - target_os = "macos", - target_os = "solaris"))] - pub fn ino(&self) -> u64 { - self.0.d_ino as u64 - } - - /// Returns the inode number (`d_fileno`) of the underlying `dirent`. - #[cfg(not(any(target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", - target_os = "l4re", - target_os = "linux", - target_os = "macos", - target_os = "solaris")))] #[allow(clippy::useless_conversion)] // Not useless on all OSes pub fn ino(&self) -> u64 { - u64::from(self.0.d_fileno) + cfg_if! { + if #[cfg(any(target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "l4re", + target_os = "linux", + target_os = "macos", + target_os = "solaris"))] { + self.0.d_ino as u64 + } else { + u64::from(self.0.d_fileno) + } + } } /// Returns the bare file name of this directory entry without any other leading path component. diff --git a/src/fcntl.rs b/src/fcntl.rs index dd8e59a6ec..74d9eb9c38 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -5,13 +5,15 @@ use std::ffi::OsString; use std::os::raw; use std::os::unix::ffi::OsStringExt; use std::os::unix::io::RawFd; -use crate::sys::stat::Mode; -use crate::{NixPath, Result}; #[cfg(any(target_os = "android", target_os = "linux"))] use std::ptr; // For splice and copy_file_range -#[cfg(any(target_os = "android", target_os = "linux"))] -use crate::sys::uio::IoVec; // For vmsplice +#[cfg(feature = "fs")] +use crate::{ + NixPath, + Result, + sys::stat::Mode +}; #[cfg(any( target_os = "linux", @@ -22,10 +24,13 @@ use crate::sys::uio::IoVec; // For vmsplice target_env = "uclibc", target_os = "freebsd" ))] -pub use self::posix_fadvise::*; +#[cfg(feature = "fs")] +pub use self::posix_fadvise::{PosixFadviseAdvice, posix_fadvise}; #[cfg(not(target_os = "redox"))] +#[cfg(any(feature = "fs", feature = "process"))] libc_bitflags! { + #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "process"))))] pub struct AtFlags: c_int { AT_REMOVEDIR; AT_SYMLINK_FOLLOW; @@ -39,18 +44,22 @@ libc_bitflags! { } } +#[cfg(any(feature = "fs", feature = "term"))] libc_bitflags!( /// Configuration options for opened files. + #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "term"))))] pub struct OFlag: c_int { /// Mask for the access mode of the file. O_ACCMODE; /// Use alternate I/O semantics. #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] O_ALT_IO; /// Open the file in append-only mode. O_APPEND; /// Generate a signal when input or output becomes possible. #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_ASYNC; /// Closes the file descriptor once an `execve` call is made. /// @@ -64,9 +73,11 @@ libc_bitflags!( target_os = "freebsd", target_os = "linux", target_os = "netbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_DIRECT; /// If the specified path isn't a directory, fail. #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_DIRECTORY; /// Implicitly follow each `write()` with an `fdatasync()`. #[cfg(any(target_os = "android", @@ -75,11 +86,13 @@ libc_bitflags!( target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_DSYNC; /// Error out if a file was not created. O_EXCL; /// Open for execute only. #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] O_EXEC; /// Open with an exclusive file lock. #[cfg(any(target_os = "dragonfly", @@ -89,6 +102,7 @@ libc_bitflags!( target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_EXLOCK; /// Same as `O_SYNC`. #[cfg(any(target_os = "dragonfly", @@ -99,18 +113,23 @@ libc_bitflags!( target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_FSYNC; /// Allow files whose sizes can't be represented in an `off_t` to be opened. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_LARGEFILE; /// Do not update the file last access time during `read(2)`s. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_NOATIME; /// Don't attach the device as the process' controlling terminal. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_NOCTTY; /// Same as `O_NONBLOCK`. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_NDELAY; /// `open()` will fail if the given path is a symbolic link. O_NOFOLLOW; @@ -118,11 +137,13 @@ libc_bitflags!( O_NONBLOCK; /// Don't deliver `SIGPIPE`. #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] O_NOSIGPIPE; /// Obtain a file descriptor for low-level access. /// /// The file itself is not opened and other file operations will fail. #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_PATH; /// Only allow reading. /// @@ -134,9 +155,11 @@ libc_bitflags!( O_RDWR; /// Similar to `O_DSYNC` but applies to `read`s instead. #[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_RSYNC; /// Skip search permission checks. #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] O_SEARCH; /// Open with a shared file lock. #[cfg(any(target_os = "dragonfly", @@ -146,17 +169,21 @@ libc_bitflags!( target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_SHLOCK; /// Implicitly follow each `write()` with an `fsync()`. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_SYNC; /// Create an unnamed temporary file. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] O_TMPFILE; /// Truncate an existing regular file to 0 length if it allows writing. O_TRUNC; /// Restore default TTY attributes. #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] O_TTY_INIT; /// Only allow writing. /// @@ -165,6 +192,9 @@ libc_bitflags!( } ); +feature! { +#![feature = "fs"] + // The conversion is not identical on all operating systems. #[allow(clippy::useless_conversion)] pub fn open(path: &P, oflag: OFlag, mode: Mode) -> Result { @@ -209,12 +239,15 @@ pub fn renameat( })??; Errno::result(res).map(drop) } +} #[cfg(all( target_os = "linux", target_env = "gnu", ))] +#[cfg(feature = "fs")] libc_bitflags! { + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] pub struct RenameFlags: u32 { RENAME_EXCHANGE; RENAME_NOREPLACE; @@ -222,6 +255,8 @@ libc_bitflags! { } } +feature! { +#![feature = "fs"] #[cfg(all( target_os = "linux", target_env = "gnu", @@ -348,10 +383,13 @@ pub(crate) fn at_rawfd(fd: Option) -> raw::c_int { Some(fd) => fd, } } +} #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(feature = "fs")] libc_bitflags!( /// Additional flags for file sealing, which allows for limiting operations on a file. + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] pub struct SealFlag: c_int { /// Prevents further calls to `fcntl()` with `F_ADD_SEALS`. F_SEAL_SEAL; @@ -364,14 +402,19 @@ libc_bitflags!( } ); +#[cfg(feature = "fs")] libc_bitflags!( /// Additional configuration flags for `fcntl`'s `F_SETFD`. + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] pub struct FdFlag: c_int { /// The file descriptor will automatically be closed during a successful `execve(2)`. FD_CLOEXEC; } ); +feature! { +#![feature = "fs"] + #[cfg(not(target_os = "redox"))] #[derive(Debug, Eq, Hash, PartialEq)] #[non_exhaustive] @@ -455,6 +498,7 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result { Errno::result(res) } +// TODO: convert to libc_enum #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[non_exhaustive] pub enum FlockArg { @@ -483,10 +527,13 @@ pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> { Errno::result(res).map(drop) } +} #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(feature = "zerocopy")] libc_bitflags! { /// Additional flags to `splice` and friends. + #[cfg_attr(docsrs, doc(cfg(feature = "zerocopy")))] pub struct SpliceFFlags: c_uint { /// Request that pages be moved instead of copied. /// @@ -505,6 +552,9 @@ libc_bitflags! { } } +feature! { +#![feature = "zerocopy"] + /// Copy a range of data from one file to another /// /// The `copy_file_range` system call performs an in-kernel copy between @@ -577,7 +627,12 @@ pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Resu } #[cfg(any(target_os = "linux", target_os = "android"))] -pub fn vmsplice(fd: RawFd, iov: &[IoVec<&[u8]>], flags: SpliceFFlags) -> Result { +pub fn vmsplice( + fd: RawFd, + iov: &[crate::sys::uio::IoVec<&[u8]>], + flags: SpliceFFlags + ) -> Result +{ let ret = unsafe { libc::vmsplice( fd, @@ -588,10 +643,13 @@ pub fn vmsplice(fd: RawFd, iov: &[IoVec<&[u8]>], flags: SpliceFFlags) -> Result< }; Errno::result(ret).map(|r| r as usize) } +} #[cfg(any(target_os = "linux"))] +#[cfg(feature = "fs")] libc_bitflags!( /// Mode argument flags for fallocate determining operation performed on a given range. + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] pub struct FallocateFlags: c_int { /// File size is not changed. /// @@ -620,11 +678,15 @@ libc_bitflags!( } ); +feature! { +#![feature = "fs"] + /// Manipulates file space. /// /// Allows the caller to directly manipulate the allocated disk space for the /// file referred to by fd. #[cfg(any(target_os = "linux"))] +#[cfg(feature = "fs")] pub fn fallocate( fd: RawFd, mode: FallocateFlags, @@ -635,6 +697,7 @@ pub fn fallocate( Errno::result(res).map(drop) } + #[cfg(any( target_os = "linux", target_os = "android", @@ -649,9 +712,11 @@ mod posix_fadvise { use std::os::unix::io::RawFd; use crate::Result; + #[cfg(feature = "fs")] libc_enum! { #[repr(i32)] #[non_exhaustive] + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] pub enum PosixFadviseAdvice { POSIX_FADV_NORMAL, POSIX_FADV_SEQUENTIAL, @@ -662,6 +727,8 @@ mod posix_fadvise { } } + feature! { + #![feature = "fs"] pub fn posix_fadvise( fd: RawFd, offset: libc::off_t, @@ -676,6 +743,7 @@ mod posix_fadvise { Err(Errno::from_i32(res)) } } + } } #[cfg(any( @@ -694,3 +762,4 @@ pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Resu Ok(errno) => Err(Errno::from_i32(errno)), } } +} diff --git a/src/lib.rs b/src/lib.rs index 3a2b63ab0b..96f56f6bcf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,17 +2,58 @@ //! //! Modules are structured according to the C header file that they would be //! defined in. +//! +//! # Features +//! +//! Nix uses the following Cargo features to enable optional functionality. +//! They may be enabled in any combination. +//! * `acct` - Process accounting +//! * `aio` - POSIX AIO +//! * `dir` - Stuff relating to directory iteration +//! * `env` - Manipulate environment variables +//! * `event` - Event-driven APIs, like `kqueue` and `epoll` +//! * `features` - Query characteristics of the OS at runtime +//! * `fs` - File system functionality +//! * `hostname` - Get and set the system's hostname +//! * `inotify` - Linux's `inotify` file system notification API +//! * `ioctl` - The `ioctl` syscall, and wrappers for my specific instances +//! * `kmod` - Load and unload kernel modules +//! * `mman` - Stuff relating to memory management +//! * `mount` - Mount and unmount file systems +//! * `mqueue` - POSIX message queues +//! * `net` - Networking-related functionality +//! * `personality` - Set the process execution domain +//! * `poll` - APIs like `poll` and `select` +//! * `process` - Stuff relating to running processes +//! * `pthread` - POSIX threads +//! * `ptrace` - Process tracing and debugging +//! * `quota` - File system quotas +//! * `reboot` - Reboot the system +//! * `resource` - Process resource limits +//! * `sched` - Manipulate process's scheduling +//! * `signal` - Send and receive signals to processes +//! * `term` - Terminal control APIs +//! * `time` - Query the operating system's clocks +//! * `ucontext` - User thread context +//! * `uio` - Vectored I/O +//! * `users` - Stuff relating to users and groups +//! * `zerocopy` - APIs like `sendfile` and `copy_file_range` #![crate_name = "nix"] #![cfg(unix)] +#![cfg_attr(docsrs, doc(cfg(all())))] #![allow(non_camel_case_types)] #![cfg_attr(test, deny(warnings))] #![recursion_limit = "500"] #![deny(unused)] +#![allow(unused_macros)] +#![cfg_attr(not(feature = "default"), allow(unused_imports))] #![deny(unstable_features)] #![deny(missing_copy_implementations)] #![deny(missing_debug_implementations)] #![warn(missing_docs)] +#![cfg_attr(docsrs, feature(doc_cfg))] + // Re-exported external crates pub use libc; @@ -21,54 +62,96 @@ pub use libc; // Public crates #[cfg(not(target_os = "redox"))] -#[allow(missing_docs)] -pub mod dir; -pub mod env; +feature! { + #![feature = "dir"] + #[allow(missing_docs)] + pub mod dir; +} +feature! { + #![feature = "env"] + pub mod env; +} #[allow(missing_docs)] pub mod errno; -pub mod features; +feature! { + #![feature = "features"] + + #[deny(missing_docs)] + pub mod features; +} #[allow(missing_docs)] pub mod fcntl; -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] -pub mod ifaddrs; +feature! { + #![feature = "net"] + + #[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd"))] + #[deny(missing_docs)] + pub mod ifaddrs; + #[cfg(not(target_os = "redox"))] + #[deny(missing_docs)] + pub mod net; +} #[cfg(any(target_os = "android", target_os = "linux"))] -#[allow(missing_docs)] -pub mod kmod; +feature! { + #![feature = "kmod"] + #[allow(missing_docs)] + pub mod kmod; +} #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] -pub mod mount; +feature! { + #![feature = "mount"] + pub mod mount; +} #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "fushsia", target_os = "linux", target_os = "netbsd"))] -#[allow(missing_docs)] -pub mod mqueue; -#[cfg(not(target_os = "redox"))] -pub mod net; -pub mod poll; +feature! { + #![feature = "mqueue"] + #[allow(missing_docs)] + pub mod mqueue; +} +feature! { + #![feature = "poll"] + pub mod poll; +} #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] -pub mod pty; -pub mod sched; +feature! { + #![feature = "term"] + #[deny(missing_docs)] + pub mod pty; +} +feature! { + #![feature = "sched"] + pub mod sched; +} pub mod sys; -#[allow(missing_docs)] -pub mod time; +feature! { + #![feature = "time"] + #[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; +feature! { + #![feature = "ucontext"] + #[allow(missing_docs)] + pub mod ucontext; +} #[allow(missing_docs)] pub mod unistd; diff --git a/src/macros.rs b/src/macros.rs index 3ccbfdd43b..c357a0636c 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,3 +1,17 @@ +// Thanks to Tokio for this macro +macro_rules! feature { + ( + #![$meta:meta] + $($item:item)* + ) => { + $( + #[cfg($meta)] + #[cfg_attr(docsrs, doc(cfg($meta)))] + $item + )* + } +} + /// The `libc_bitflags!` macro helps with a common use case of defining a public bitflags type /// with values from the libc crate. It is used the same way as the `bitflags!` macro, except /// that only the name of the flag value has to be given. diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs index 627bfa5ec1..ba0c1a2883 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd.rs @@ -20,29 +20,36 @@ libc_bitflags!( pub struct MntFlags: c_int { /// ACL support enabled. #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_ACLS; /// All I/O to the file system should be done asynchronously. MNT_ASYNC; /// dir should instead be a file system ID encoded as “FSID:val0:val1”. #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_BYFSID; /// Force a read-write mount even if the file system appears to be /// unclean. MNT_FORCE; /// GEOM journal support enabled. #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_GJOURNAL; /// MAC support for objects. #[cfg(any(target_os = "macos", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_MULTILABEL; /// Disable read clustering. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_NOCLUSTERR; /// Disable write clustering. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_NOCLUSTERW; /// Enable NFS version 4 ACLs. #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_NFS4ACLS; /// Do not update access times. MNT_NOATIME; @@ -52,6 +59,7 @@ libc_bitflags!( MNT_NOSUID; /// Do not follow symlinks. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_NOSYMFOLLOW; /// Mount read-only. MNT_RDONLY; @@ -62,6 +70,7 @@ libc_bitflags!( /// /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs) #[cfg(any(target_os = "macos", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_SNAPSHOT; /// Using soft updates. #[cfg(any( @@ -70,10 +79,12 @@ libc_bitflags!( target_os = "netbsd", target_os = "openbsd" ))] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_SOFTDEP; /// Directories with the SUID bit set chown new files to their own /// owner. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_SUIDDIR; /// All I/O to the file system should be done synchronously. MNT_SYNCHRONOUS; @@ -83,12 +94,14 @@ libc_bitflags!( target_os = "freebsd", target_os = "netbsd" ))] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_UNION; /// Indicates that the mount command is being applied to an already /// mounted file system. MNT_UPDATE; /// Check vnode use counts. #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] MNT_NONBUSY; } ); @@ -182,6 +195,7 @@ pub type NmountResult = std::result::Result<(), NmountError>; /// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount) /// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs) #[cfg(target_os = "freebsd")] +#[cfg_attr(docsrs, doc(cfg(all())))] #[derive(Debug, Default)] pub struct Nmount<'a>{ iov: Vec>, @@ -189,6 +203,7 @@ pub struct Nmount<'a>{ } #[cfg(target_os = "freebsd")] +#[cfg_attr(docsrs, doc(cfg(all())))] impl<'a> Nmount<'a> { /// Add an opaque mount option. /// diff --git a/src/mount/mod.rs b/src/mount/mod.rs index 14bf2a9636..e89c1a07c3 100644 --- a/src/mount/mod.rs +++ b/src/mount/mod.rs @@ -1,5 +1,6 @@ //! Mount file systems #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] mod linux; #[cfg(any(target_os = "android", target_os = "linux"))] @@ -10,6 +11,7 @@ pub use self::linux::*; target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] +#[cfg_attr(docsrs, doc(cfg(all())))] mod bsd; #[cfg(any(target_os = "dragonfly", diff --git a/src/mqueue.rs b/src/mqueue.rs index 34fd802785..564df4e40d 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -37,8 +37,10 @@ pub struct MqAttr { // x32 compatibility // See https://sourceware.org/bugzilla/show_bug.cgi?id=21279 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub type mq_attr_member_t = i64; #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub type mq_attr_member_t = libc::c_long; impl MqAttr { diff --git a/src/net/if_.rs b/src/net/if_.rs index bc00a4328b..ebe8bcceeb 100644 --- a/src/net/if_.rs +++ b/src/net/if_.rs @@ -45,9 +45,11 @@ libc_bitflags!( target_os = "netbsd", target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_NOTRAILERS; /// Interface manages own routes. #[cfg(any(target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_SMART; /// Resources allocated. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) @@ -62,6 +64,7 @@ libc_bitflags!( target_os = "netbsd", target_os = "openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_RUNNING; /// No arp protocol, L2 destination address not set. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) @@ -75,6 +78,7 @@ libc_bitflags!( /// Master of a load balancing bundle. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_MASTER; /// transmission in progress, tx hardware queue is full #[cfg(any(target_os = "freebsd", @@ -82,13 +86,16 @@ libc_bitflags!( target_os = "netbsd", target_os = "openbsd", target_os = "ios"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_OACTIVE; /// Protocol code on board. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_INTELLIGENT; /// Slave of a load balancing bundle. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_SLAVE; /// Can't hear own transmissions. #[cfg(any(target_os = "dragonfly", @@ -97,6 +104,7 @@ libc_bitflags!( target_os = "netbsd", target_os = "openbsd", target_os = "osx"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_SIMPLEX; /// Supports multicast. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) @@ -108,13 +116,16 @@ libc_bitflags!( target_os = "netbsd", target_os = "openbsd", target_os = "ios"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_LINK0; /// Multicast using broadcast. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_MULTI_BCAST; /// Is able to select media type via ifmap. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_PORTSEL; /// Per link layer defined bit. #[cfg(any(target_os = "dragonfly", @@ -123,13 +134,16 @@ libc_bitflags!( target_os = "netbsd", target_os = "openbsd", target_os = "ios"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_LINK1; /// Non-unique address. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_UNNUMBERED; /// Auto media selection active. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_AUTOMEDIA; /// Per link layer defined bit. #[cfg(any(target_os = "dragonfly", @@ -138,132 +152,174 @@ libc_bitflags!( target_os = "netbsd", target_os = "openbsd", target_os = "ios"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_LINK2; /// Use alternate physical connection. #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos", target_os = "ios"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_ALTPHYS; /// DHCP controls interface. #[cfg(any(target_os = "solaris", target_os = "illumos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_DHCPRUNNING; /// The addresses are lost when the interface goes down. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_DYNAMIC; /// Do not advertise. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_PRIVATE; /// Driver signals L1 up. Volatile. #[cfg(any(target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_LOWER_UP; /// Interface is in polling mode. #[cfg(any(target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_POLLING_COMPAT; /// Unconfigurable using ioctl(2). #[cfg(any(target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_CANTCONFIG; /// Do not transmit packets. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_NOXMIT; /// Driver signals dormant. Volatile. #[cfg(any(target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_DORMANT; /// User-requested promisc mode. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_PPROMISC; /// Just on-link subnet. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_NOLOCAL; /// Echo sent packets. Volatile. #[cfg(any(target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_ECHO; /// User-requested monitor mode. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_MONITOR; /// Address is deprecated. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_DEPRECATED; /// Static ARP. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_STATICARP; /// Address from stateless addrconf. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_ADDRCONF; /// Interface is in polling mode. #[cfg(any(target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_NPOLLING; /// Router on interface. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_ROUTER; /// Interface is in polling mode. #[cfg(any(target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_IDIRECT; /// Interface is winding down #[cfg(any(target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_DYING; /// No NUD on interface. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_NONUD; /// Interface is being renamed #[cfg(any(target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_RENAMING; /// Anycast address. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_ANYCAST; /// Don't exchange routing info. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_NORTEXCH; /// Do not provide packet information #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_NO_PI as libc::c_int; /// TUN device (no Ethernet headers) #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_TUN as libc::c_int; /// TAP device #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_TAP as libc::c_int; /// IPv4 interface. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_IPV4; /// IPv6 interface. #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_IPV6; /// in.mpathd test address #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_NOFAILOVER; /// Interface has failed #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_FAILED; /// Interface is a hot-spare #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_STANDBY; /// Functioning but not used #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_INACTIVE; /// Interface is offline #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_OFFLINE; #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_COS_ENABLED; /// Prefer as source addr. #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_PREFERRED; /// RFC3041 #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_TEMPORARY; /// MTU set with SIOCSLIFMTU #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_FIXEDMTU; /// Cannot send / receive packets #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_VIRTUAL; /// Local address in use #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_DUPLICATE; /// IPMP IP interface #[cfg(target_os = "solaris")] + #[cfg_attr(docsrs, doc(cfg(all())))] IFF_IPMP; } ); @@ -278,6 +334,7 @@ libc_bitflags!( target_os = "netbsd", target_os = "openbsd", ))] +#[cfg_attr(docsrs, doc(cfg(all())))] mod if_nameindex { use super::*; diff --git a/src/poll.rs b/src/poll.rs index 8556c1bb74..5b1815264d 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -1,8 +1,4 @@ //! Wait for events to trigger on specific file descriptors -#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] -use crate::sys::time::TimeSpec; -#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] -use crate::sys::signal::SigSet; use std::os::unix::io::{AsRawFd, RawFd}; use crate::Result; @@ -81,15 +77,19 @@ libc_bitflags! { POLLOUT; /// Equivalent to [`POLLIN`](constant.POLLIN.html) #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] POLLRDNORM; #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Equivalent to [`POLLOUT`](constant.POLLOUT.html) POLLWRNORM; /// Priority band data can be read (generally unused on Linux). #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] POLLRDBAND; /// Priority data may be written. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] POLLWRBAND; /// Error condition (only returned in /// [`PollFd::revents`](struct.PollFd.html#method.revents); @@ -142,6 +142,8 @@ pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result { Errno::result(res) } +feature! { +#![feature = "signal"] /// `ppoll()` allows an application to safely wait until either a file /// descriptor becomes ready or until a signal is caught. /// ([`poll(2)`](https://man7.org/linux/man-pages/man2/poll.2.html)) @@ -151,7 +153,12 @@ pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result { /// specify `None` as `timeout` (it is like `timeout = -1` for `poll`). /// #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] -pub fn ppoll(fds: &mut [PollFd], timeout: Option, sigmask: SigSet) -> Result { +pub fn ppoll( + fds: &mut [PollFd], + timeout: Option, + sigmask: crate::sys::signal::SigSet + ) -> Result +{ let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); let res = unsafe { libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd, @@ -161,3 +168,4 @@ pub fn ppoll(fds: &mut [PollFd], timeout: Option, sigmask: SigSet) -> }; Errno::result(res) } +} diff --git a/src/pty.rs b/src/pty.rs index facc9aaf40..a104a69c90 100644 --- a/src/pty.rs +++ b/src/pty.rs @@ -9,8 +9,9 @@ use std::mem; use std::os::unix::prelude::*; use crate::sys::termios::Termios; -use crate::unistd::{self, ForkResult, Pid}; -use crate::{Result, fcntl}; +#[cfg(feature = "process")] +use crate::unistd::{ForkResult, Pid}; +use crate::{Result, fcntl, unistd}; use crate::errno::Errno; /// Representation of a master/slave pty pair @@ -25,6 +26,8 @@ pub struct OpenptyResult { pub slave: RawFd, } +feature! { +#![feature = "process"] /// Representation of a master with a forked pty /// /// This is returned by `forkpty`. Note that this type does *not* implement `Drop`, so the user @@ -36,6 +39,7 @@ pub struct ForkptyResult { /// Metadata about forked process pub fork_result: ForkResult, } +} /// Representation of the Master device in a master/slave pty pair @@ -188,6 +192,7 @@ pub unsafe fn ptsname(fd: &PtyMaster) -> Result { /// This value is useful for opening the slave ptty once the master has already been opened with /// `posix_openpt()`. #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] #[inline] pub fn ptsname_r(fd: &PtyMaster) -> Result { let mut name_buf = Vec::::with_capacity(64); @@ -294,6 +299,8 @@ pub fn openpty<'a, 'b, T: Into>, U: Into } } +feature! { +#![feature = "process"] /// Create a new pseudoterminal, returning the master file descriptor and forked pid. /// in `ForkptyResult` /// (see [`forkpty`](https://man7.org/linux/man-pages/man3/forkpty.3.html)). @@ -346,3 +353,4 @@ pub unsafe fn forkpty<'a, 'b, T: Into>, U: Into Drop for AioCb<'a> { /// /// The basic structure used to issue multiple AIO operations simultaneously. #[cfg(not(any(target_os = "ios", target_os = "macos")))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub struct LioCb<'a> { /// A collection of [`AioCb`]s. All of these will be issued simultaneously /// by the [`listio`] method. @@ -828,6 +830,7 @@ unsafe impl<'a> Send for LioCb<'a> {} unsafe impl<'a> Sync for LioCb<'a> {} #[cfg(not(any(target_os = "ios", target_os = "macos")))] +#[cfg_attr(docsrs, doc(cfg(all())))] impl<'a> LioCb<'a> { /// Are no [`AioCb`]s contained? pub fn is_empty(&self) -> bool { @@ -1036,6 +1039,7 @@ impl<'a> Debug for LioCb<'a> { // LioCbBuilder must use a Vec to make construction possible when the final size // is unknown. #[cfg(not(any(target_os = "ios", target_os = "macos")))] +#[cfg_attr(docsrs, doc(cfg(all())))] #[derive(Debug)] pub struct LioCbBuilder<'a> { /// A collection of [`AioCb`]s. @@ -1045,6 +1049,7 @@ pub struct LioCbBuilder<'a> { } #[cfg(not(any(target_os = "ios", target_os = "macos")))] +#[cfg_attr(docsrs, doc(cfg(all())))] impl<'a> LioCbBuilder<'a> { /// Initialize an empty `LioCb` pub fn with_capacity(capacity: usize) -> LioCbBuilder<'a> { diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 6bc2a2539e..678c27f956 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -19,6 +19,7 @@ libc_bitflags!( EPOLLHUP; EPOLLRDHUP; #[cfg(target_os = "linux")] // Added in 4.5; not in Android. + #[cfg_attr(docsrs, doc(cfg(all())))] EPOLLEXCLUSIVE; #[cfg(not(target_arch = "mips"))] EPOLLWAKEUP; diff --git a/src/sys/inotify.rs b/src/sys/inotify.rs index 3f5ae22abc..d6697a4a21 100644 --- a/src/sys/inotify.rs +++ b/src/sys/inotify.rs @@ -36,6 +36,7 @@ use crate::unistd::read; use crate::Result; use crate::NixPath; use crate::errno::Errno; +use cfg_if::cfg_if; libc_bitflags! { /// Configuration options for [`inotify_add_watch`](fn.inotify_add_watch.html). @@ -151,16 +152,15 @@ impl Inotify { /// Returns an EINVAL error if the watch descriptor is invalid. /// /// For more information see, [inotify_rm_watch(2)](https://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html). - #[cfg(target_os = "linux")] pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> { - let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd) }; - - Errno::result(res).map(drop) - } - - #[cfg(target_os = "android")] - pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> { - let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd as u32) }; + cfg_if! { + if #[cfg(target_os = "linux")] { + let arg = wd.wd; + } else if #[cfg(target_os = "android")] { + let arg = wd.wd as u32; + } + } + let res = unsafe { libc::inotify_rm_watch(self.fd, arg) }; Errno::result(res).map(drop) } diff --git a/src/sys/mman.rs b/src/sys/mman.rs index 0ef1ca8a4f..017c3f6e17 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -5,10 +5,9 @@ use crate::Result; use crate::NixPath; use crate::errno::Errno; #[cfg(not(target_os = "android"))] -use crate::fcntl::OFlag; +#[cfg(feature = "fs")] +use crate::{fcntl::OFlag, sys::stat::Mode}; use libc::{self, c_int, c_void, size_t, off_t}; -#[cfg(not(target_os = "android"))] -use crate::sys::stat::Mode; use std::os::unix::io::RawFd; libc_bitflags!{ @@ -24,9 +23,11 @@ libc_bitflags!{ PROT_EXEC; /// Apply protection up to the end of a mapping that grows upwards. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] PROT_GROWSDOWN; /// Apply protection down to the beginning of a mapping that grows downwards. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] PROT_GROWSUP; } } @@ -45,6 +46,7 @@ libc_bitflags!{ /// To be used with `MAP_FIXED`, to forbid the system /// to select a different address than the one specified. #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_EXCL; /// Synonym for `MAP_ANONYMOUS`. MAP_ANON; @@ -55,98 +57,128 @@ libc_bitflags!{ any(target_arch = "x86", target_arch = "x86_64")), all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")), all(target_os = "freebsd", target_pointer_width = "64")))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_32BIT; /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_GROWSDOWN; /// Compatibility flag. Ignored. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_DENYWRITE; /// Compatibility flag. Ignored. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_EXECUTABLE; /// Mark the mmaped region to be locked in the same way as `mlock(2)`. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_LOCKED; /// Do not reserve swap space for this mapping. /// /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_NORESERVE; /// Populate page tables for a mapping. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_POPULATE; /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_NONBLOCK; /// Allocate the mapping using "huge pages." #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGETLB; /// Make use of 64KB huge page (must be supported by the system) #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_64KB; /// Make use of 512KB huge page (must be supported by the system) #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_512KB; /// Make use of 1MB huge page (must be supported by the system) #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_1MB; /// Make use of 2MB huge page (must be supported by the system) #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_2MB; /// Make use of 8MB huge page (must be supported by the system) #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_8MB; /// Make use of 16MB huge page (must be supported by the system) #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_16MB; /// Make use of 32MB huge page (must be supported by the system) #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_32MB; /// Make use of 256MB huge page (must be supported by the system) #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_256MB; /// Make use of 512MB huge page (must be supported by the system) #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_512MB; /// Make use of 1GB huge page (must be supported by the system) #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_1GB; /// Make use of 2GB huge page (must be supported by the system) #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_2GB; /// Make use of 16GB huge page (must be supported by the system) #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HUGE_16GB; /// Lock the mapped region into memory as with `mlock(2)`. #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_WIRED; /// Causes dirtied data in the specified range to be flushed to disk only when necessary. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_NOSYNC; /// Rename private pages to a file. /// /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_RENAME; /// Region may contain semaphores. #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_HASSEMAPHORE; /// Region grows down, like a stack. #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_STACK; /// Pages in this mapping are not retained in the kernel's memory cache. #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_NOCACHE; /// Allows the W/X bit on the page, it's necessary on aarch64 architecture. #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_JIT; /// Allows to use large pages, underlying alignment based on size. #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_ALIGNED_SUPER; /// Pages will be discarded in the core dumps. #[cfg(target_os = "openbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_CONCEAL; } } @@ -157,15 +189,19 @@ libc_bitflags!{ pub struct MRemapFlags: c_int { /// Permit the kernel to relocate the mapping to a new virtual address, if necessary. #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MREMAP_MAYMOVE; /// Place the mapping at exactly the address specified in `new_address`. #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] MREMAP_FIXED; /// Permits to use the old and new address as hints to relocate the mapping. #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_FIXED; /// Allows to duplicate the mapping to be able to apply different flags on the copy. #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] MAP_REMAPDUP; } } @@ -189,23 +225,29 @@ libc_enum!{ MADV_DONTNEED, /// Free up a given range of pages and its associated backing store. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_REMOVE, /// Do not make pages in this range available to the child after a `fork(2)`. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_DONTFORK, /// Undo the effect of `MADV_DONTFORK`. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_DOFORK, /// Poison the given pages. /// /// Subsequent references to those pages are treated like hardware memory corruption. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_HWPOISON, /// Enable Kernel Samepage Merging (KSM) for the given pages. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_MERGEABLE, /// Undo the effect of `MADV_MERGEABLE` #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_UNMERGEABLE, /// Preserve the memory of each page but offline the original page. #[cfg(any(target_os = "android", @@ -221,46 +263,61 @@ libc_enum!{ MADV_SOFT_OFFLINE, /// Enable Transparent Huge Pages (THP) for pages in the given range. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_HUGEPAGE, /// Undo the effect of `MADV_HUGEPAGE`. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_NOHUGEPAGE, /// Exclude the given range from a core dump. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_DONTDUMP, /// Undo the effect of an earlier `MADV_DONTDUMP`. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_DODUMP, /// Specify that the application no longer needs the pages in the given range. MADV_FREE, /// Request that the system not flush the current range to disk unless it needs to. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_NOSYNC, /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_AUTOSYNC, /// Region is not included in a core file. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_NOCORE, /// Include region in a core file #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_CORE, #[cfg(any(target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_PROTECT, /// Invalidate the hardware page table for the given region. #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_INVAL, /// Set the offset of the page directory page to `value` for the virtual page table. #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_SETMAP, /// Indicates that the application will not need the data in the given range. #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_ZERO_WIRED_PAGES, #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_FREE_REUSABLE, #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_FREE_REUSE, #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_CAN_REUSE, } } @@ -274,9 +331,11 @@ libc_bitflags!{ MS_INVALIDATE; /// Invalidate pages, but leave them mapped. #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MS_KILLPAGES; /// Deactivate pages, but leave them mapped. #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MS_DEACTIVATE; /// Perform an update and wait for it to complete. MS_SYNC; @@ -453,13 +512,21 @@ pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result Errno::result(libc::msync(addr, length, flags.bits())).map(drop) } +#[cfg(not(target_os = "android"))] +feature! { +#![feature = "fs"] /// Creates and opens a new, or opens an existing, POSIX shared memory object. /// /// For more information, see [`shm_open(3)`]. /// /// [`shm_open(3)`]: https://man7.org/linux/man-pages/man3/shm_open.3.html -#[cfg(not(target_os = "android"))] -pub fn shm_open(name: &P, flag: OFlag, mode: Mode) -> Result { +pub fn shm_open

( + name: &P, + flag: OFlag, + mode: Mode + ) -> Result + where P: ?Sized + NixPath +{ let ret = name.with_nix_path(|cstr| { #[cfg(any(target_os = "macos", target_os = "ios"))] unsafe { @@ -473,6 +540,7 @@ pub fn shm_open(name: &P, flag: OFlag, mode: Mode) -> Resul Errno::result(ret) } +} /// Performs the converse of [`shm_open`], removing an object previously created. /// diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 156b0d9d1c..16ba9e0ab8 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -5,24 +5,31 @@ target_os = "linux", target_os = "macos", target_os = "netbsd"))] -pub mod aio; - -#[cfg(any(target_os = "android", target_os = "linux"))] -#[allow(missing_docs)] -pub mod epoll; - -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - 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; +feature! { + #![feature = "aio"] + pub mod aio; +} + +feature! { + #![feature = "event"] + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[allow(missing_docs)] + pub mod epoll; + + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + 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", target_os = "dragonfly", @@ -34,21 +41,35 @@ pub mod eventfd; target_os = "netbsd", target_os = "illumos", target_os = "openbsd"))] +#[cfg(feature = "ioctl")] +#[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] #[macro_use] pub mod ioctl; #[cfg(target_os = "linux")] -pub mod memfd; +feature! { + #![feature = "fs"] + pub mod memfd; +} #[cfg(not(target_os = "redox"))] -#[allow(missing_docs)] -pub mod mman; +feature! { + #![feature = "mman"] + #[allow(missing_docs)] + pub mod mman; +} #[cfg(target_os = "linux")] -#[allow(missing_docs)] -pub mod personality; +feature! { + #![feature = "personality"] + #[allow(missing_docs)] + pub mod personality; +} -pub mod pthread; +feature! { + #![feature = "pthread"] + pub mod pthread; +} #[cfg(any(target_os = "android", target_os = "dragonfly", @@ -57,41 +78,68 @@ pub mod pthread; target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] -#[allow(missing_docs)] -pub mod ptrace; +feature! { + #![feature = "ptrace"] + #[allow(missing_docs)] + pub mod ptrace; +} #[cfg(target_os = "linux")] -pub mod quota; +feature! { + #![feature = "quota"] + pub mod quota; +} -#[cfg(any(target_os = "linux"))] -#[allow(missing_docs)] -pub mod reboot; +#[cfg(target_os = "linux")] +feature! { + #![feature = "reboot"] + #[allow(missing_docs)] + pub mod reboot; +} #[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))] -pub mod resource; +feature! { + #![feature = "resource"] + pub mod resource; +} #[cfg(not(target_os = "redox"))] -pub mod select; +feature! { + #![feature = "poll"] + pub mod select; +} #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "ios", target_os = "linux", target_os = "macos"))] -pub mod sendfile; +feature! { + #![feature = "zerocopy"] + pub mod sendfile; +} pub mod signal; #[cfg(any(target_os = "android", target_os = "linux"))] -#[allow(missing_docs)] -pub mod signalfd; +feature! { + #![feature = "signal"] + #[allow(missing_docs)] + pub mod signalfd; +} #[cfg(not(target_os = "redox"))] -#[allow(missing_docs)] -pub mod socket; - -#[allow(missing_docs)] -pub mod stat; +feature! { + #![feature = "socket"] + #[allow(missing_docs)] + pub mod socket; +} + +feature! { + #![feature = "fs"] + #[allow(missing_docs)] + pub mod stat; +} #[cfg(any(target_os = "android", target_os = "dragonfly", @@ -101,30 +149,55 @@ pub mod stat; target_os = "macos", target_os = "openbsd" ))] -pub mod statfs; +feature! { + #![feature = "fs"] + pub mod statfs; +} -pub mod statvfs; +feature! { + #![feature = "fs"] + pub mod statvfs; +} #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] #[allow(missing_docs)] pub mod sysinfo; -#[allow(missing_docs)] -pub mod termios; +feature! { + #![feature = "term"] + #[allow(missing_docs)] + pub mod termios; +} #[allow(missing_docs)] pub mod time; -pub mod uio; +feature! { + #![feature = "uio"] + pub mod uio; +} -pub mod utsname; +feature! { + #![feature = "features"] + pub mod utsname; +} -pub mod wait; +feature! { + #![feature = "process"] + pub mod wait; +} #[cfg(any(target_os = "android", target_os = "linux"))] -#[allow(missing_docs)] -pub mod inotify; +feature! { + #![feature = "inotify"] + #[allow(missing_docs)] + pub mod inotify; +} #[cfg(any(target_os = "android", target_os = "linux"))] -#[allow(missing_docs)] -pub mod timerfd; +feature! { + #![feature = "time"] + #[allow(missing_docs)] + pub mod timerfd; +} diff --git a/src/sys/pthread.rs b/src/sys/pthread.rs index d42e45d13d..fd81f3ed38 100644 --- a/src/sys/pthread.rs +++ b/src/sys/pthread.rs @@ -4,8 +4,6 @@ use crate::errno::Errno; #[cfg(not(target_os = "redox"))] use crate::Result; -#[cfg(not(target_os = "redox"))] -use crate::sys::signal::Signal; use libc::{self, pthread_t}; /// Identifies an individual thread. @@ -21,6 +19,9 @@ pub fn pthread_self() -> Pthread { unsafe { libc::pthread_self() } } +feature! { +#![feature = "signal"] + /// Send a signal to a thread (see [`pthread_kill(3)`]). /// /// If `signal` is `None`, `pthread_kill` will only preform error checking and @@ -28,7 +29,9 @@ pub fn pthread_self() -> Pthread { /// /// [`pthread_kill(3)`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_kill.html #[cfg(not(target_os = "redox"))] -pub fn pthread_kill>>(thread: Pthread, signal: T) -> Result<()> { +pub fn pthread_kill(thread: Pthread, signal: T) -> Result<()> + where T: Into> +{ let sig = match signal.into() { Some(s) => s as libc::c_int, None => 0, @@ -36,3 +39,4 @@ pub fn pthread_kill>>(thread: Pthread, signal: T) -> Resu let res = unsafe { libc::pthread_kill(thread, sig) }; Errno::result(res).map(drop) } +} diff --git a/src/sys/ptrace/bsd.rs b/src/sys/ptrace/bsd.rs index a62881ef34..ac7d83126c 100644 --- a/src/sys/ptrace/bsd.rs +++ b/src/sys/ptrace/bsd.rs @@ -30,10 +30,12 @@ libc_enum! { PT_READ_I, PT_READ_D, #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(all())))] PT_READ_U, PT_WRITE_I, PT_WRITE_D, #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(all())))] PT_WRITE_U, PT_CONTINUE, PT_KILL, @@ -47,10 +49,13 @@ libc_enum! { PT_ATTACH, PT_DETACH, #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(all())))] PT_SIGEXC, #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(all())))] PT_THUPDATE, #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(all())))] PT_ATTACHEXC } } diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs index 37236790b4..fb6ff1996d 100644 --- a/src/sys/ptrace/linux.rs +++ b/src/sys/ptrace/linux.rs @@ -99,8 +99,10 @@ libc_enum!{ target_arch = "mips64"))))] PTRACE_SETREGSET, #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] PTRACE_SEIZE, #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] PTRACE_INTERRUPT, #[cfg(all(target_os = "linux", not(any(target_arch = "mips", target_arch = "mips64"))))] @@ -171,7 +173,6 @@ libc_bitflags! { PTRACE_O_TRACESECCOMP; /// Send a SIGKILL to the tracee if the tracer exits. This is useful /// for ptrace jailers to prevent tracees from escaping their control. - #[cfg(any(target_os = "android", target_os = "linux"))] PTRACE_O_EXITKILL; } } @@ -340,6 +341,7 @@ pub fn attach(pid: Pid) -> Result<()> { /// /// Attaches to the process specified in pid, making it a tracee of the calling process. #[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn seize(pid: Pid, options: Options) -> Result<()> { unsafe { ptrace_other( @@ -388,6 +390,7 @@ pub fn cont>>(pid: Pid, sig: T) -> Result<()> { /// /// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)` #[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn interrupt(pid: Pid) -> Result<()> { unsafe { ptrace_other(Request::PTRACE_INTERRUPT, pid, ptr::null_mut(), ptr::null_mut()).map(drop) diff --git a/src/sys/resource.rs b/src/sys/resource.rs index f3bfb67194..80473e583c 100644 --- a/src/sys/resource.rs +++ b/src/sys/resource.rs @@ -54,6 +54,7 @@ libc_enum! { target_os = "netbsd", target_os = "openbsd" )))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum amount (in bytes) of virtual memory the process is /// allowed to map. RLIMIT_AS, @@ -72,69 +73,83 @@ libc_enum! { RLIMIT_STACK, #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum number of kqueues this user id is allowed to create. RLIMIT_KQUEUES, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// 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"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// 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"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// 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"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// 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"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum number of simultaneous processes for this user id. RLIMIT_NPROC, #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] /// 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"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// 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"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// 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"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// 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"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// 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"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum size (in bytes) of socket buffer usage for this user. RLIMIT_SBSIZE, #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] /// 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")] + #[cfg_attr(docsrs, doc(cfg(all())))] /// An alias for RLIMIT_AS. RLIMIT_VMEM, } diff --git a/src/sys/select.rs b/src/sys/select.rs index 4d7576a58a..ab4f68f537 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -8,7 +8,6 @@ use std::ptr::{null, null_mut}; use libc::{self, c_int}; use crate::Result; use crate::errno::Errno; -use crate::sys::signal::SigSet; use crate::sys::time::{TimeSpec, TimeVal}; pub use libc::FD_SETSIZE; @@ -213,6 +212,11 @@ where Errno::result(res) } +feature! { +#![feature = "signal"] + +use crate::sys::signal::SigSet; + /// Monitors file descriptors for readiness with an altered signal mask. /// /// Returns the total number of ready file descriptors in all sets. The sets are changed so that all @@ -283,7 +287,7 @@ where Errno::result(res) } - +} #[cfg(test)] mod tests { diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs index 7a210c6fc3..1a87a6800a 100644 --- a/src/sys/sendfile.rs +++ b/src/sys/sendfile.rs @@ -22,6 +22,7 @@ use crate::errno::Errno; /// /// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn sendfile( out_fd: RawFd, in_fd: RawFd, @@ -48,6 +49,7 @@ pub fn sendfile( /// /// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) #[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn sendfile64( out_fd: RawFd, in_fd: RawFd, diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 61bdc74aef..f85bf26611 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -5,7 +5,6 @@ use crate::{Error, Result}; use crate::errno::Errno; -use crate::unistd::Pid; use std::mem; use std::fmt; use std::str::FromStr; @@ -14,8 +13,10 @@ use std::os::unix::io::RawFd; use std::ptr; #[cfg(not(any(target_os = "openbsd", target_os = "redox")))] +#[cfg(any(feature = "aio", feature = "signal"))] pub use self::sigevent::*; +#[cfg(any(feature = "aio", feature = "process", feature = "signal"))] libc_enum!{ /// Types of operating system signals // Currently there is only one definition of c_int in libc, as well as only one @@ -24,6 +25,7 @@ libc_enum!{ // this is not (yet) possible. #[repr(i32)] #[non_exhaustive] + #[cfg_attr(docsrs, doc(cfg(any(feature = "aio", feature = "signal"))))] pub enum Signal { /// Hangup SIGHUP, @@ -89,6 +91,7 @@ libc_enum!{ SIGIO, #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Power failure imminent. SIGPWR, /// Bad system call @@ -96,17 +99,20 @@ libc_enum!{ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", target_os = "redox")))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Emulator trap SIGEMT, #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", target_os = "redox")))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Information request SIGINFO, } impl TryFrom } +#[cfg(feature = "signal")] impl FromStr for Signal { type Err = Error; fn from_str(s: &str) -> Result { @@ -161,6 +167,7 @@ impl FromStr for Signal { } } +#[cfg(feature = "signal")] impl Signal { /// Returns name of signal. /// @@ -217,21 +224,25 @@ impl Signal { } } +#[cfg(feature = "signal")] impl AsRef for Signal { fn as_ref(&self) -> &str { self.as_str() } } +#[cfg(feature = "signal")] impl fmt::Display for Signal { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_ref()) } } +#[cfg(feature = "signal")] pub use self::Signal::*; #[cfg(target_os = "redox")] +#[cfg(feature = "signal")] const SIGNALS: [Signal; 29] = [ SIGHUP, SIGINT, @@ -266,6 +277,7 @@ const SIGNALS: [Signal; 29] = [ target_os = "emscripten", target_os = "fuchsia"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))] +#[cfg(feature = "signal")] const SIGNALS: [Signal; 31] = [ SIGHUP, SIGINT, @@ -302,6 +314,7 @@ const SIGNALS: [Signal; 31] = [ target_os = "emscripten", target_os = "fuchsia"), any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")))] +#[cfg(feature = "signal")] const SIGNALS: [Signal; 30] = [ SIGHUP, SIGINT, @@ -336,6 +349,7 @@ const SIGNALS: [Signal; 30] = [ #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "fuchsia", target_os = "emscripten", target_os = "redox")))] +#[cfg(feature = "signal")] const SIGNALS: [Signal; 31] = [ SIGHUP, SIGINT, @@ -369,6 +383,9 @@ const SIGNALS: [Signal; 31] = [ SIGEMT, SIGINFO]; +feature! { +#![feature = "signal"] + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] /// Iterate through all signals defined by this operating system pub struct SignalIterator { @@ -407,9 +424,12 @@ pub const SIGUNUSED : Signal = SIGSYS; type SaFlags_t = libc::c_int; #[cfg(target_os = "redox")] type SaFlags_t = libc::c_ulong; +} +#[cfg(feature = "signal")] libc_bitflags!{ /// Controls the behavior of a [`SigAction`] + #[cfg_attr(docsrs, doc(cfg(feature = "signal")))] 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 @@ -435,10 +455,12 @@ libc_bitflags!{ } } +#[cfg(feature = "signal")] libc_enum! { /// Specifies how certain functions should manipulate a signal mask #[repr(i32)] #[non_exhaustive] + #[cfg_attr(docsrs, doc(cfg(feature = "signal")))] pub enum SigmaskHow { /// The new mask is the union of the current mask and the specified set. SIG_BLOCK, @@ -450,13 +472,17 @@ libc_enum! { } } +feature! { +#![feature = "signal"] + +use crate::unistd::Pid; + /// 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 } - impl SigSet { /// Initialize to include all signals. pub fn all() -> SigSet { @@ -542,6 +568,7 @@ impl SigSet { /// Suspends execution of the calling thread until one of the signals in the /// signal mask becomes pending, and returns the accepted signal. #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn wait(&self) -> Result { use std::convert::TryFrom; @@ -573,6 +600,7 @@ pub enum SigHandler { /// Use the given signal-catching function, which takes in the signal, information about how /// the signal was generated, and a pointer to the threads `ucontext_t`. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)) } @@ -636,6 +664,7 @@ impl SigAction { /// Returns the action's handler. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn handler(&self) -> SigHandler { match self.sigaction.sa_sigaction { libc::SIG_DFL => SigHandler::SigDfl, @@ -670,6 +699,7 @@ impl SigAction { /// Returns the action's handler. #[cfg(target_os = "redox")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn handler(&self) -> SigHandler { match self.sigaction.sa_handler { libc::SIG_DFL => SigHandler::SigDfl, @@ -912,7 +942,11 @@ pub fn raise(signal: Signal) -> Result<()> { Errno::result(res).map(drop) } +} + +feature! { +#![any(feature = "aio", feature = "signal")] /// Identifies a thread for [`SigevNotify::SigevThreadId`] #[cfg(target_os = "freebsd")] @@ -942,6 +976,7 @@ pub enum SigevNotify { // expose a way to set the union members needed by SIGEV_THREAD. /// Notify by delivering an event to a kqueue. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] SigevKevent { /// File descriptor of the kqueue to notify. kq: RawFd, @@ -950,6 +985,7 @@ pub enum SigevNotify { }, /// Notify by delivering a signal to a thread. #[cfg(any(target_os = "freebsd", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] SigevThreadId { /// Signal to send signal: Signal, @@ -960,9 +996,14 @@ pub enum SigevNotify { si_value: libc::intptr_t }, } +} #[cfg(not(any(target_os = "openbsd", target_os = "redox")))] +#[cfg_attr(docsrs, doc(cfg(all())))] mod sigevent { + feature! { + #![any(feature = "aio", feature = "signal")] + use std::mem; use std::ptr; use super::SigevNotify; @@ -1051,6 +1092,7 @@ mod sigevent { SigEvent{ sigevent: *sigevent } } } + } } #[cfg(test)] diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index b119642b3f..fa62706ebb 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -13,7 +13,7 @@ use crate::sys::socket::addr::netlink::NetlinkAddr; use crate::sys::socket::addr::alg::AlgAddr; #[cfg(any(target_os = "ios", target_os = "macos"))] use std::os::unix::io::RawFd; -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] use crate::sys::socket::addr::sys_control::SysControlAddr; #[cfg(any(target_os = "android", target_os = "dragonfly", @@ -25,6 +25,7 @@ use crate::sys::socket::addr::sys_control::SysControlAddr; target_os = "netbsd", target_os = "openbsd", target_os = "fuchsia"))] +#[cfg(feature = "net")] pub use self::datalink::LinkAddr; #[cfg(any(target_os = "android", target_os = "linux"))] pub use self::vsock::VsockAddr; @@ -43,6 +44,7 @@ pub enum AddressFamily { Inet6 = libc::AF_INET6, /// Kernel user interface device (see [`netlink(7)`](https://man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Netlink = libc::AF_NETLINK, /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html)) #[cfg(any(target_os = "android", @@ -50,84 +52,117 @@ pub enum AddressFamily { target_os = "illumos", target_os = "fuchsia", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Packet = libc::AF_PACKET, /// KEXT Controls and Notifications #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] System = libc::AF_SYSTEM, /// Amateur radio AX.25 protocol #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Ax25 = libc::AF_AX25, /// IPX - Novell protocols Ipx = libc::AF_IPX, /// AppleTalk AppleTalk = libc::AF_APPLETALK, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetRom = libc::AF_NETROM, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Bridge = libc::AF_BRIDGE, /// Access to raw ATM PVCs #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] AtmPvc = libc::AF_ATMPVC, /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](https://man7.org/linux/man-pages/man7/x25.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] X25 = libc::AF_X25, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Rose = libc::AF_ROSE, Decnet = libc::AF_DECnet, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetBeui = libc::AF_NETBEUI, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Security = libc::AF_SECURITY, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Key = libc::AF_KEY, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Ash = libc::AF_ASH, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Econet = libc::AF_ECONET, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] AtmSvc = libc::AF_ATMSVC, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Rds = libc::AF_RDS, Sna = libc::AF_SNA, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Irda = libc::AF_IRDA, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Pppox = libc::AF_PPPOX, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Wanpipe = libc::AF_WANPIPE, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Llc = libc::AF_LLC, #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] Ib = libc::AF_IB, #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] Mpls = libc::AF_MPLS, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Can = libc::AF_CAN, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Tipc = libc::AF_TIPC, #[cfg(not(any(target_os = "illumos", target_os = "ios", target_os = "macos", target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] Bluetooth = libc::AF_BLUETOOTH, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Iucv = libc::AF_IUCV, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] RxRpc = libc::AF_RXRPC, #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] Isdn = libc::AF_ISDN, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Phonet = libc::AF_PHONET, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Ieee802154 = libc::AF_IEEE802154, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Caif = libc::AF_CAIF, /// Interface to kernel crypto API #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Alg = libc::AF_ALG, #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] Nfc = libc::AF_NFC, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Vsock = libc::AF_VSOCK, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -135,6 +170,7 @@ pub enum AddressFamily { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ImpLink = libc::AF_IMPLINK, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -142,6 +178,7 @@ pub enum AddressFamily { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Pup = libc::AF_PUP, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -149,11 +186,13 @@ pub enum AddressFamily { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Chaos = libc::AF_CHAOS, #[cfg(any(target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Ns = libc::AF_NS, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -161,6 +200,7 @@ pub enum AddressFamily { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Iso = libc::AF_ISO, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -168,6 +208,7 @@ pub enum AddressFamily { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Datakit = libc::AF_DATAKIT, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -175,6 +216,7 @@ pub enum AddressFamily { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Ccitt = libc::AF_CCITT, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -182,6 +224,7 @@ pub enum AddressFamily { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Dli = libc::AF_DLI, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -189,6 +232,7 @@ pub enum AddressFamily { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Lat = libc::AF_LAT, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -196,6 +240,7 @@ pub enum AddressFamily { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Hylink = libc::AF_HYLINK, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -204,6 +249,7 @@ pub enum AddressFamily { target_os = "illumos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Link = libc::AF_LINK, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -211,6 +257,7 @@ pub enum AddressFamily { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Coip = libc::AF_COIP, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -218,6 +265,7 @@ pub enum AddressFamily { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Cnt = libc::AF_CNT, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -225,9 +273,11 @@ pub enum AddressFamily { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Natm = libc::AF_NATM, /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Unspec = libc::AF_UNSPEC, } @@ -263,6 +313,9 @@ impl AddressFamily { } } +feature! { +#![feature = "net"] + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum InetAddr { V4(libc::sockaddr_in), @@ -515,6 +568,7 @@ impl fmt::Display for Ipv6Addr { self.to_std().fmt(fmt) } } +} /// A wrapper around `sockaddr_un`. #[derive(Clone, Copy, Debug)] @@ -586,6 +640,7 @@ impl UnixAddr { /// This is a Linux-specific extension, primarily used to allow chrooted /// processes to communicate with processes having a different filesystem view. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn new_abstract(path: &[u8]) -> Result { unsafe { let mut ret = libc::sockaddr_un { @@ -644,6 +699,7 @@ impl UnixAddr { /// For abstract sockets only the bare name is returned, without the /// leading null byte. `None` is returned for unnamed or path-backed sockets. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn as_abstract(&self) -> Option<&[u8]> { match self.kind() { UnixAddrKind::Abstract(name) => Some(name), @@ -709,13 +765,18 @@ impl Hash for UnixAddr { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[non_exhaustive] pub enum SockAddr { + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Inet(InetAddr), Unix(UnixAddr), #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Netlink(NetlinkAddr), #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Alg(AlgAddr), - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] + #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] SysControl(SysControlAddr), /// Datalink address (MAC) #[cfg(any(target_os = "android", @@ -727,52 +788,68 @@ pub enum SockAddr { target_os = "illumos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Link(LinkAddr), #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] Vsock(VsockAddr), } impl SockAddr { + feature! { + #![feature = "net"] pub fn new_inet(addr: InetAddr) -> SockAddr { SockAddr::Inet(addr) } + } pub fn new_unix(path: &P) -> Result { Ok(SockAddr::Unix(UnixAddr::new(path)?)) } #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn new_netlink(pid: u32, groups: u32) -> SockAddr { SockAddr::Netlink(NetlinkAddr::new(pid, groups)) } #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr { SockAddr::Alg(AlgAddr::new(alg_type, alg_name)) } + feature! { + #![feature = "ioctl"] #[cfg(any(target_os = "ios", target_os = "macos"))] pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result { SysControlAddr::from_name(sockfd, name, unit).map(SockAddr::SysControl) } + } #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn new_vsock(cid: u32, port: u32) -> SockAddr { SockAddr::Vsock(VsockAddr::new(cid, port)) } pub fn family(&self) -> AddressFamily { match *self { + #[cfg(feature = "net")] SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet, + #[cfg(feature = "net")] SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6, SockAddr::Unix(..) => AddressFamily::Unix, #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Netlink(..) => AddressFamily::Netlink, #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Alg(..) => AddressFamily::Alg, - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(all(feature = "ioctl", + any(target_os = "ios", target_os = "macos")))] SockAddr::SysControl(..) => AddressFamily::System, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] SockAddr::Link(..) => AddressFamily::Packet, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -781,6 +858,7 @@ impl SockAddr { target_os = "netbsd", target_os = "illumos", target_os = "openbsd"))] + #[cfg(feature = "net")] SockAddr::Link(..) => AddressFamily::Link, #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Vsock(..) => AddressFamily::Vsock, @@ -802,23 +880,28 @@ impl SockAddr { /// unsafe because it takes a raw pointer as argument. The caller must /// ensure that the pointer is valid. #[cfg(not(target_os = "fuchsia"))] + #[cfg(feature = "net")] pub(crate) unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option { if addr.is_null() { None } else { match AddressFamily::from_i32(i32::from((*addr).sa_family)) { Some(AddressFamily::Unix) => None, + #[cfg(feature = "net")] Some(AddressFamily::Inet) => Some(SockAddr::Inet( InetAddr::V4(*(addr as *const libc::sockaddr_in)))), + #[cfg(feature = "net")] Some(AddressFamily::Inet6) => Some(SockAddr::Inet( InetAddr::V6(*(addr as *const libc::sockaddr_in6)))), #[cfg(any(target_os = "android", target_os = "linux"))] Some(AddressFamily::Netlink) => Some(SockAddr::Netlink( NetlinkAddr(*(addr as *const libc::sockaddr_nl)))), - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(all(feature = "ioctl", + any(target_os = "ios", target_os = "macos")))] Some(AddressFamily::System) => Some(SockAddr::SysControl( SysControlAddr(*(addr as *const libc::sockaddr_ctl)))), #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] Some(AddressFamily::Packet) => Some(SockAddr::Link( LinkAddr(*(addr as *const libc::sockaddr_ll)))), #[cfg(any(target_os = "dragonfly", @@ -828,6 +911,7 @@ impl SockAddr { target_os = "netbsd", target_os = "illumos", target_os = "openbsd"))] + #[cfg(feature = "net")] Some(AddressFamily::Link) => { let ether_addr = LinkAddr(*(addr as *const libc::sockaddr_dl)); if ether_addr.is_empty() { @@ -855,6 +939,7 @@ impl SockAddr { /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back. pub fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) { match *self { + #[cfg(feature = "net")] SockAddr::Inet(InetAddr::V4(ref addr)) => ( // This cast is always allowed in C unsafe { @@ -862,6 +947,7 @@ impl SockAddr { }, mem::size_of_val(addr) as libc::socklen_t ), + #[cfg(feature = "net")] SockAddr::Inet(InetAddr::V6(ref addr)) => ( // This cast is always allowed in C unsafe { @@ -892,7 +978,8 @@ impl SockAddr { }, mem::size_of_val(sa) as libc::socklen_t ), - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(all(feature = "ioctl", + any(target_os = "ios", target_os = "macos")))] SockAddr::SysControl(SysControlAddr(ref sa)) => ( // This cast is always allowed in C unsafe { @@ -902,6 +989,7 @@ impl SockAddr { ), #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] SockAddr::Link(LinkAddr(ref addr)) => ( // This cast is always allowed in C unsafe { @@ -916,6 +1004,7 @@ impl SockAddr { target_os = "illumos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg(feature = "net")] SockAddr::Link(LinkAddr(ref addr)) => ( // This cast is always allowed in C unsafe { @@ -938,13 +1027,15 @@ impl SockAddr { impl fmt::Display for SockAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { + #[cfg(feature = "net")] SockAddr::Inet(ref inet) => inet.fmt(f), SockAddr::Unix(ref unix) => unix.fmt(f), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Netlink(ref nl) => nl.fmt(f), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Alg(ref nl) => nl.fmt(f), - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(all(feature = "ioctl", + any(target_os = "ios", target_os = "macos")))] SockAddr::SysControl(ref sc) => sc.fmt(f), #[cfg(any(target_os = "android", target_os = "dragonfly", @@ -955,6 +1046,7 @@ impl fmt::Display for SockAddr { target_os = "netbsd", target_os = "illumos", target_os = "openbsd"))] + #[cfg(feature = "net")] SockAddr::Link(ref ether_addr) => ether_addr.fmt(f), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Vsock(ref svm) => svm.fmt(f), @@ -963,6 +1055,7 @@ impl fmt::Display for SockAddr { } #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub mod netlink { use crate::sys::socket::addr::AddressFamily; use libc::{sa_family_t, sockaddr_nl}; @@ -998,6 +1091,7 @@ pub mod netlink { } #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub mod alg { use libc::{AF_ALG, sockaddr_alg, c_char}; use std::{fmt, mem, str}; @@ -1060,6 +1154,8 @@ pub mod alg { } } +feature! { +#![feature = "ioctl"] #[cfg(any(target_os = "ios", target_os = "macos"))] pub mod sys_control { use crate::sys::socket::addr::AddressFamily; @@ -1130,10 +1226,14 @@ pub mod sys_control { } } } +} #[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))] +#[cfg_attr(docsrs, doc(cfg(all())))] mod datalink { + feature! { + #![feature = "net"] use super::{fmt, AddressFamily}; /// Hardware Address @@ -1197,6 +1297,7 @@ mod datalink { addr[5]) } } + } } #[cfg(any(target_os = "dragonfly", @@ -1206,7 +1307,10 @@ mod datalink { target_os = "illumos", target_os = "netbsd", target_os = "openbsd"))] +#[cfg_attr(docsrs, doc(cfg(all())))] mod datalink { + feature! { + #![feature = "net"] use super::{fmt, AddressFamily}; /// Hardware Address @@ -1216,6 +1320,7 @@ mod datalink { impl LinkAddr { /// Total length of sockaddr #[cfg(not(target_os = "illumos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn len(&self) -> usize { self.0.sdl_len as usize } @@ -1291,9 +1396,11 @@ mod datalink { addr[5]) } } + } } #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub mod vsock { use crate::sys::socket::addr::AddressFamily; use libc::{sa_family_t, sockaddr_vm}; diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 97eea3dcb1..dcac2818ed 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -8,10 +8,14 @@ use libc::{self, c_void, c_int, iovec, socklen_t, size_t, use memoffset::offset_of; use std::{mem, ptr, slice}; use std::os::unix::io::RawFd; -#[cfg(all(target_os = "linux"))] +#[cfg(target_os = "linux")] +#[cfg(feature = "uio")] use crate::sys::time::TimeSpec; -use crate::sys::time::TimeVal; -use crate::sys::uio::IoVec; +#[cfg(feature = "uio")] +use crate::sys::{ + time::TimeVal, + uio::IoVec +}; mod addr; #[deny(missing_docs)] @@ -27,19 +31,27 @@ pub mod sockopt; pub use self::addr::{ AddressFamily, SockAddr, - InetAddr, UnixAddr, +}; +#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] +#[cfg(feature = "net")] +pub use self::addr::{ + InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, - LinkAddr, + LinkAddr }; #[cfg(any(target_os = "illumos", target_os = "solaris"))] pub use self::addr::{ AddressFamily, SockAddr, - InetAddr, UnixAddr, +}; +#[cfg(any(target_os = "illumos", target_os = "solaris"))] +#[cfg(feature = "net")] +pub use self::addr::{ + InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, @@ -52,16 +64,16 @@ pub use crate::sys::socket::addr::alg::AlgAddr; #[cfg(any(target_os = "android", target_os = "linux"))] pub use crate::sys::socket::addr::vsock::VsockAddr; +#[cfg(feature = "uio")] +pub use libc::{cmsghdr, msghdr}; pub use libc::{ - cmsghdr, - msghdr, sa_family_t, sockaddr, - sockaddr_in, - sockaddr_in6, sockaddr_storage, sockaddr_un, }; +#[cfg(feature = "net")] +pub use libc::{sockaddr_in, sockaddr_in6}; // Needed by the cmsg_space macro #[doc(hidden)] @@ -105,68 +117,84 @@ pub enum SockProtocol { /// Allows applications and other KEXTs to be notified when certain kernel events occur /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] KextEvent = libc::SYSPROTO_EVENT, /// Allows applications to configure and control a KEXT /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] KextControl = libc::SYSPROTO_CONTROL, /// Receives routing and link updates and may be used to modify the routing tables (both IPv4 and IPv6), IP addresses, link // parameters, neighbor setups, queueing disciplines, traffic classes and packet classifiers /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkRoute = libc::NETLINK_ROUTE, /// Reserved for user-mode socket protocols /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkUserSock = libc::NETLINK_USERSOCK, /// Query information about sockets of various protocol families from the kernel /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkSockDiag = libc::NETLINK_SOCK_DIAG, /// SELinux event notifications. /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkSELinux = libc::NETLINK_SELINUX, /// Open-iSCSI /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkISCSI = libc::NETLINK_ISCSI, /// Auditing /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkAudit = libc::NETLINK_AUDIT, /// Access to FIB lookup from user space /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP, /// Netfilter subsystem /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkNetFilter = libc::NETLINK_NETFILTER, /// SCSI Transports /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT, /// Infiniband RDMA /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkRDMA = libc::NETLINK_RDMA, /// Transport IPv6 packets from netfilter to user space. Used by ip6_queue kernel module. /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkIPv6Firewall = libc::NETLINK_IP6_FW, /// DECnet routing messages /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG, /// Kernel messages to user space /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT, /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow /// configuration of the kernel crypto API. /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkCrypto = libc::NETLINK_CRYPTO, } @@ -181,6 +209,7 @@ libc_bitflags!{ target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] SOCK_NONBLOCK; /// Set close-on-exec on the new descriptor #[cfg(any(target_os = "android", @@ -190,13 +219,16 @@ libc_bitflags!{ target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] SOCK_CLOEXEC; /// Return `EPIPE` instead of raising `SIGPIPE` #[cfg(target_os = "netbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] SOCK_NOSIGPIPE; /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)` /// to the DNS port (typically 53) #[cfg(target_os = "openbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] SOCK_DNS; } } @@ -245,6 +277,7 @@ libc_bitflags!{ /// the socket error queue. (For more details, see /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom)) #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MSG_ERRQUEUE; /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain /// file descriptor using the `SCM_RIGHTS` operation (described in @@ -259,6 +292,7 @@ libc_bitflags!{ target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MSG_CMSG_CLOEXEC; } } @@ -276,11 +310,14 @@ cfg_if! { impl UnixCredentials { /// Creates a new instance with the credentials of the current process pub fn new() -> Self { - UnixCredentials(libc::ucred { - pid: crate::unistd::getpid().as_raw(), - uid: crate::unistd::getuid().as_raw(), - gid: crate::unistd::getgid().as_raw(), - }) + // Safe because these FFI functions are inherently safe + unsafe { + UnixCredentials(libc::ucred { + pid: libc::getpid(), + uid: libc::getuid(), + gid: libc::getgid() + }) + } } /// Returns the process identifier @@ -347,7 +384,12 @@ cfg_if! { /// Returns a list group identifiers (the first one being the effective GID) pub fn groups(&self) -> &[libc::gid_t] { - unsafe { slice::from_raw_parts(self.0.cmcred_groups.as_ptr() as *const libc::gid_t, self.0.cmcred_ngroups as _) } + unsafe { + slice::from_raw_parts( + self.0.cmcred_groups.as_ptr() as *const libc::gid_t, + self.0.cmcred_ngroups as _ + ) + } } } @@ -391,6 +433,8 @@ cfg_if!{ } } +feature! { +#![feature = "net"] /// Request for multicast socket operations /// /// This is a wrapper type around `ip_mreq`. @@ -426,6 +470,10 @@ impl Ipv6MembershipRequest { }) } } +} + +feature! { +#![feature = "uio"] /// Create a buffer large enough for storing some control messages as returned /// by [`recvmsg`](fn.recvmsg.html). @@ -531,9 +579,11 @@ pub enum ControlMessageOwned { ScmRights(Vec), /// Received version of [`ControlMessage::ScmCredentials`] #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ScmCredentials(UnixCredentials), /// Received version of [`ControlMessage::ScmCreds`] #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ScmCreds(UnixCredentials), /// A message of type `SCM_TIMESTAMP`, containing the time the /// packet was received by the kernel. @@ -595,6 +645,7 @@ pub enum ControlMessageOwned { /// /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) #[cfg(all(target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ScmTimestampns(TimeSpec), #[cfg(any( target_os = "android", @@ -603,6 +654,8 @@ pub enum ControlMessageOwned { target_os = "macos", target_os = "netbsd", ))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4PacketInfo(libc::in_pktinfo), #[cfg(any( target_os = "android", @@ -614,6 +667,8 @@ pub enum ControlMessageOwned { target_os = "openbsd", target_os = "netbsd", ))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv6PacketInfo(libc::in6_pktinfo), #[cfg(any( target_os = "freebsd", @@ -622,6 +677,8 @@ pub enum ControlMessageOwned { target_os = "netbsd", target_os = "openbsd", ))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4RecvIf(libc::sockaddr_dl), #[cfg(any( target_os = "freebsd", @@ -630,6 +687,8 @@ pub enum ControlMessageOwned { target_os = "netbsd", target_os = "openbsd", ))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4RecvDstAddr(libc::in_addr), /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP @@ -641,6 +700,8 @@ pub enum ControlMessageOwned { /// `UdpGroSegment` socket option should be enabled on a socket /// to allow receiving GRO packets. #[cfg(target_os = "linux")] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] UdpGroSegments(u16), /// SO_RXQ_OVFL indicates that an unsigned 32 bit value @@ -652,13 +713,18 @@ pub enum ControlMessageOwned { /// `RxqOvfl` socket option should be enabled on a socket /// to allow receiving the drop counter. #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] RxqOvfl(u32), /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4RecvErr(libc::sock_extended_err, Option), /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv6RecvErr(libc::sock_extended_err, Option), /// Catch-all variant for unimplemented cmsg types. @@ -717,6 +783,7 @@ impl ControlMessageOwned { target_os = "linux", target_os = "macos" ))] + #[cfg(feature = "net")] (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => { let info = ptr::read_unaligned(p as *const libc::in6_pktinfo); ControlMessageOwned::Ipv6PacketInfo(info) @@ -728,6 +795,7 @@ impl ControlMessageOwned { target_os = "macos", target_os = "netbsd", ))] + #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_PKTINFO) => { let info = ptr::read_unaligned(p as *const libc::in_pktinfo); ControlMessageOwned::Ipv4PacketInfo(info) @@ -739,6 +807,7 @@ impl ControlMessageOwned { target_os = "netbsd", target_os = "openbsd", ))] + #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_RECVIF) => { let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl); ControlMessageOwned::Ipv4RecvIf(dl) @@ -750,11 +819,13 @@ impl ControlMessageOwned { target_os = "netbsd", target_os = "openbsd", ))] + #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => { let dl = ptr::read_unaligned(p as *const libc::in_addr); ControlMessageOwned::Ipv4RecvDstAddr(dl) }, #[cfg(target_os = "linux")] + #[cfg(feature = "net")] (libc::SOL_UDP, libc::UDP_GRO) => { let gso_size: u16 = ptr::read_unaligned(p as *const _); ControlMessageOwned::UdpGroSegments(gso_size) @@ -765,11 +836,13 @@ impl ControlMessageOwned { ControlMessageOwned::RxqOvfl(drop_counter) }, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] (libc::IPPROTO_IP, libc::IP_RECVERR) => { let (err, addr) = Self::recv_err_helper::(p, len); ControlMessageOwned::Ipv4RecvErr(err, addr) }, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => { let (err, addr) = Self::recv_err_helper::(p, len); ControlMessageOwned::Ipv6RecvErr(err, addr) @@ -783,6 +856,7 @@ impl ControlMessageOwned { } #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] unsafe fn recv_err_helper(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option) { let ee = p as *const libc::sock_extended_err; let err = ptr::read_unaligned(ee); @@ -832,6 +906,7 @@ pub enum ControlMessage<'a> { /// For further information, please refer to the /// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page. #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ScmCredentials(&'a UnixCredentials), /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of /// a process connected to the socket. @@ -846,6 +921,7 @@ pub enum ControlMessage<'a> { /// For further information, please refer to the /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page. #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ScmCreds, /// Set IV for `AF_ALG` crypto API. @@ -856,6 +932,7 @@ pub enum ControlMessage<'a> { target_os = "android", target_os = "linux", ))] + #[cfg_attr(docsrs, doc(cfg(all())))] AlgSetIv(&'a [u8]), /// Set crypto operation for `AF_ALG` crypto API. It may be one of /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT` @@ -866,6 +943,7 @@ pub enum ControlMessage<'a> { target_os = "android", target_os = "linux", ))] + #[cfg_attr(docsrs, doc(cfg(all())))] AlgSetOp(&'a libc::c_int), /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms) /// for `AF_ALG` crypto API. @@ -876,6 +954,7 @@ pub enum ControlMessage<'a> { target_os = "android", target_os = "linux", ))] + #[cfg_attr(docsrs, doc(cfg(all())))] AlgSetAeadAssoclen(&'a u32), /// UDP GSO makes it possible for applications to generate network packets @@ -887,6 +966,8 @@ pub enum ControlMessage<'a> { /// Send buffer should consist of multiple fixed-size wire payloads /// following one by one, and the last, possibly smaller one. #[cfg(target_os = "linux")] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] UdpGsoSegments(&'a u16), /// Configure the sending addressing and interface for v4 @@ -898,6 +979,8 @@ pub enum ControlMessage<'a> { target_os = "netbsd", target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4PacketInfo(&'a libc::in_pktinfo), /// Configure the sending addressing and interface for v6 @@ -910,6 +993,8 @@ pub enum ControlMessage<'a> { target_os = "freebsd", target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv6PacketInfo(&'a libc::in6_pktinfo), /// SO_RXQ_OVFL indicates that an unsigned 32 bit value @@ -918,6 +1003,7 @@ pub enum ControlMessage<'a> { /// socket between the last recieved packet and this /// received packet. #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] RxqOvfl(&'a u32), } @@ -998,16 +1084,19 @@ impl<'a> ControlMessage<'a> { len as *const _ as *const u8 }, #[cfg(target_os = "linux")] + #[cfg(feature = "net")] ControlMessage::UdpGsoSegments(gso_size) => { gso_size as *const _ as *const u8 }, #[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd", target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8, #[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd", target_os = "freebsd", target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8, #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] ControlMessage::RxqOvfl(drop_count) => { @@ -1050,16 +1139,19 @@ impl<'a> ControlMessage<'a> { mem::size_of_val(len) }, #[cfg(target_os = "linux")] + #[cfg(feature = "net")] ControlMessage::UdpGsoSegments(gso_size) => { mem::size_of_val(gso_size) }, #[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd", target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info), #[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd", target_os = "freebsd", target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info), #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] ControlMessage::RxqOvfl(drop_count) => { @@ -1080,14 +1172,17 @@ impl<'a> ControlMessage<'a> { ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) | ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG, #[cfg(target_os = "linux")] + #[cfg(feature = "net")] ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP, #[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd", target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP, #[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd", target_os = "freebsd", target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6, #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET, @@ -1115,16 +1210,19 @@ impl<'a> ControlMessage<'a> { libc::ALG_SET_AEAD_ASSOCLEN }, #[cfg(target_os = "linux")] + #[cfg(feature = "net")] ControlMessage::UdpGsoSegments(_) => { libc::UDP_SEGMENT }, #[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd", target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO, #[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd", target_os = "freebsd", target_os = "android", target_os = "ios",))] + #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO, #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] ControlMessage::RxqOvfl(_) => { @@ -1528,6 +1626,7 @@ pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>], Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init(), &mut cmsg_buffer) }) } +} /// Create an endpoint for communication @@ -1818,6 +1917,7 @@ pub fn sockaddr_storage_to_addr( } match c_int::from(addr.ss_family) { + #[cfg(feature = "net")] libc::AF_INET => { assert!(len as usize >= mem::size_of::()); let sin = unsafe { @@ -1825,6 +1925,7 @@ pub fn sockaddr_storage_to_addr( }; Ok(SockAddr::Inet(InetAddr::V4(sin))) } + #[cfg(feature = "net")] libc::AF_INET6 => { assert!(len as usize >= mem::size_of::()); let sin6 = unsafe { @@ -1840,6 +1941,7 @@ pub fn sockaddr_storage_to_addr( } } #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(feature = "net")] libc::AF_PACKET => { use libc::sockaddr_ll; // Don't assert anything about the size. diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index fcb4be81be..3ad139ad22 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -17,6 +17,7 @@ use std::os::unix::ffi::OsStrExt; // Constants // TCP_CA_NAME_MAX isn't defined in user space include files #[cfg(any(target_os = "freebsd", target_os = "linux"))] +#[cfg(feature = "net")] const TCP_CA_NAME_MAX: usize = 16; /// Helper for implementing `SetSockOpt` for a given socket option. See @@ -251,7 +252,9 @@ sockopt_impl!( /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an /// identical socket address. ReusePort, Both, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool); +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Under most circumstances, TCP sends data when it is presented; when /// outstanding data has not yet been acknowledged, it gathers small amounts /// of output to be sent in a single packet once an acknowledgement is @@ -265,20 +268,28 @@ sockopt_impl!( /// queued messages for the socket have been successfully sent or the /// linger timeout has been reached. Linger, Both, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger); +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Join a multicast group IpAddMembership, SetOnly, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, super::IpMembershipRequest); +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Leave a multicast group. IpDropMembership, SetOnly, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, super::IpMembershipRequest); cfg_if! { if #[cfg(any(target_os = "android", target_os = "linux"))] { + #[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Join an IPv6 multicast group. Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest); + #[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Leave an IPv6 multicast group. Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest); } else if #[cfg(any(target_os = "dragonfly", @@ -289,26 +300,36 @@ cfg_if! { target_os = "netbsd", target_os = "openbsd", target_os = "solaris"))] { + #[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Join an IPv6 multicast group. Ipv6AddMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest); + #[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Leave an IPv6 multicast group. Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest); } } +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Set or read the time-to-live value of outgoing multicast packets for /// this socket. IpMulticastTtl, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8); +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Set or read a boolean integer argument that determines whether sent /// multicast packets should be looped back to the local sockets. IpMulticastLoop, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool); #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// If enabled, this boolean option allows binding to an IP address that /// is nonlocal or does not (yet) exist. IpFreebind, Both, libc::IPPROTO_IP, libc::IP_FREEBIND, bool); @@ -347,7 +368,9 @@ sockopt_impl!( PeerCredentials, GetOnly, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials); #[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Specify the amount of time, in seconds, that the connection must be idle /// before keepalive probes (if enabled) are sent. TcpKeepAlive, Both, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32); @@ -356,7 +379,9 @@ sockopt_impl!( target_os = "freebsd", target_os = "linux", target_os = "nacl"))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The time (in seconds) the connection needs to remain idle before TCP /// starts sending keepalive probes TcpKeepIdle, Both, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32); @@ -372,7 +397,9 @@ cfg_if! { } } #[cfg(not(target_os = "openbsd"))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The maximum number of keepalive probes TCP should send before /// dropping the connection. TcpKeepCount, Both, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32); @@ -384,11 +411,15 @@ sockopt_impl!( // Not documented by Linux! TcpRepair, Both, libc::IPPROTO_TCP, libc::TCP_REPAIR, u32); #[cfg(not(target_os = "openbsd"))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The time (in seconds) between individual keepalive probes. TcpKeepInterval, Both, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32); #[cfg(any(target_os = "fuchsia", target_os = "linux"))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Specifies the maximum amount of time in milliseconds that transmitted /// data may remain unacknowledged before TCP will forcibly close the /// corresponding connection @@ -423,7 +454,9 @@ sockopt_impl!( /// Bind this socket to a particular device like “eth0”. BindToDevice, Both, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>); #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] #[allow(missing_docs)] // Not documented by Linux! OriginalDst, GetOnly, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in); @@ -440,16 +473,22 @@ sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message. ReceiveTimestampns, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPNS, bool); #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Setting this boolean option enables transparent proxying on this socket. IpTransparent, Both, libc::SOL_IP, libc::IP_TRANSPARENT, bool); #[cfg(target_os = "openbsd")] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Allows the socket to be bound to addresses which are not local to the /// machine, so it can be used to make a transparent proxy. BindAny, Both, libc::SOL_SOCKET, libc::SO_BINDANY, bool); #[cfg(target_os = "freebsd")] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Can `bind(2)` to any address, even one not bound to any available /// network interface in the system. BindAny, Both, libc::IPPROTO_IP, libc::IP_BINDANY, bool); @@ -464,7 +503,9 @@ sockopt_impl!( /// message. PassCred, Both, libc::SOL_SOCKET, libc::SO_PASSCRED, bool); #[cfg(any(target_os = "freebsd", target_os = "linux"))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// This option allows the caller to set the TCP congestion control /// algorithm to be used, on a per-socket basis. TcpCongestion, Both, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>); @@ -475,7 +516,9 @@ sockopt_impl!( target_os = "macos", target_os = "netbsd", ))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Pass an `IP_PKTINFO` ancillary message that contains a pktinfo /// structure that supplies some information about the incoming packet. Ipv4PacketInfo, Both, libc::IPPROTO_IP, libc::IP_PKTINFO, bool); @@ -488,7 +531,9 @@ sockopt_impl!( target_os = "netbsd", target_os = "openbsd", ))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Set delivery of the `IPV6_PKTINFO` control message on incoming /// datagrams. Ipv6RecvPacketInfo, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool); @@ -499,7 +544,9 @@ sockopt_impl!( target_os = "netbsd", target_os = "openbsd", ))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The `recvmsg(2)` call returns a `struct sockaddr_dl` corresponding to /// the interface on which the packet was received. Ipv4RecvIf, Both, libc::IPPROTO_IP, libc::IP_RECVIF, bool); @@ -510,17 +557,23 @@ sockopt_impl!( target_os = "netbsd", target_os = "openbsd", ))] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The `recvmsg(2)` call will return the destination IP address for a UDP /// datagram. Ipv4RecvDstAddr, Both, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool); #[cfg(target_os = "linux")] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] #[allow(missing_docs)] // Not documented by Linux! UdpGsoSegment, Both, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int); #[cfg(target_os = "linux")] +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] #[allow(missing_docs)] // Not documented by Linux! UdpGroSegment, Both, libc::IPPROTO_UDP, libc::UDP_GRO, bool); @@ -530,7 +583,9 @@ sockopt_impl!( /// be attached to received skbs indicating the number of packets dropped by /// the socket since its creation. RxqOvfl, Both, libc::SOL_SOCKET, libc::SO_RXQ_OVFL, libc::c_int); +#[cfg(feature = "net")] sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The socket is restricted to sending and receiving IPv6 packets only. Ipv6V6Only, Both, libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, bool); #[cfg(any(target_os = "android", target_os = "linux"))] diff --git a/src/sys/stat.rs b/src/sys/stat.rs index c8f10419c3..67a1b7f769 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -54,6 +54,7 @@ pub fn mknod(path: &P, kind: SFlag, perm: Mode, dev: dev_t) /// Create a special or ordinary file, relative to a given directory. #[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn mknodat( dirfd: RawFd, path: &P, @@ -69,18 +70,21 @@ pub fn mknodat( } #[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] pub const fn major(dev: dev_t) -> u64 { ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff) } #[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] pub const fn minor(dev: dev_t) -> u64 { ((dev >> 12) & 0xffff_ff00) | ((dev ) & 0x0000_00ff) } #[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] pub const fn makedev(major: u64, minor: u64) -> dev_t { ((major & 0xffff_f000) << 32) | ((major & 0x0000_0fff) << 8) | @@ -129,6 +133,7 @@ pub fn fstat(fd: RawFd) -> Result { } #[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn fstatat(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result { let mut dst = mem::MaybeUninit::uninit(); let res = pathname.with_nix_path(|cstr| { @@ -175,6 +180,7 @@ pub enum FchmodatFlags { /// /// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). #[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn fchmodat( dirfd: Option, path: &P, @@ -233,6 +239,7 @@ pub fn utimes(path: &P, atime: &TimeVal, mtime: &TimeVal) - target_os = "macos", target_os = "freebsd", target_os = "netbsd"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn lutimes(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> { let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; let res = path.with_nix_path(|cstr| unsafe { @@ -280,6 +287,7 @@ pub enum UtimensatFlags { /// /// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html). #[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn utimensat( dirfd: Option, path: &P, @@ -306,6 +314,7 @@ pub fn utimensat( } #[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn mkdirat(fd: RawFd, path: &P, mode: Mode) -> Result<()> { let res = path.with_nix_path(|cstr| { unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) } diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 829be57f63..bfb94f4866 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -11,9 +11,11 @@ use crate::{NixPath, Result, errno::Errno}; /// Identifies a mounted file system #[cfg(target_os = "android")] +#[cfg_attr(docsrs, doc(cfg(all())))] pub type fsid_t = libc::__fsid_t; /// Identifies a mounted file system #[cfg(not(target_os = "android"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub type fsid_t = libc::fsid_t; /// Describes a mounted file system @@ -142,12 +144,14 @@ impl Statfs { target_os = "ios", target_os = "macos" )))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn filesystem_type(&self) -> FsType { FsType(self.0.f_type) } /// Magic code defining system type #[cfg(not(any(target_os = "linux", target_os = "android")))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn filesystem_type_name(&self) -> &str { let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) }; c_str.to_str().unwrap() @@ -155,18 +159,21 @@ impl Statfs { /// Optimal transfer block size #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> i32 { self.0.f_iosize } /// Optimal transfer block size #[cfg(target_os = "openbsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> u32 { self.0.f_iosize } /// Optimal transfer block size #[cfg(all(target_os = "linux", target_arch = "s390x"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> u32 { self.0.f_bsize } @@ -176,30 +183,35 @@ impl Statfs { target_os = "android", all(target_os = "linux", target_env = "musl") ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> libc::c_ulong { self.0.f_bsize } /// Optimal transfer block size #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> libc::__fsword_t { self.0.f_bsize } /// Optimal transfer block size #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> libc::c_long { self.0.f_iosize } /// Optimal transfer block size #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> u64 { self.0.f_iosize } /// Size of a block #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> u32 { self.0.f_bsize } @@ -207,6 +219,7 @@ impl Statfs { /// Size of a block // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 #[cfg(all(target_os = "linux", target_arch = "s390x"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> u32 { self.0.f_bsize } @@ -214,6 +227,7 @@ impl Statfs { /// Size of a block // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 #[cfg(all(target_os = "linux", target_env = "musl"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> libc::c_ulong { self.0.f_bsize } @@ -221,54 +235,63 @@ impl Statfs { /// Size of a block // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> libc::__fsword_t { self.0.f_bsize } /// Size of a block #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> u64 { self.0.f_bsize } /// Size of a block #[cfg(target_os = "android")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> libc::c_ulong { self.0.f_bsize } /// Size of a block #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> libc::c_long { self.0.f_bsize } /// Maximum length of filenames #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn maximum_name_length(&self) -> u32 { self.0.f_namemax } /// Maximum length of filenames #[cfg(all(target_os = "linux", target_arch = "s390x"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn maximum_name_length(&self) -> u32 { self.0.f_namelen } /// Maximum length of filenames #[cfg(all(target_os = "linux", target_env = "musl"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn maximum_name_length(&self) -> libc::c_ulong { self.0.f_namelen } /// Maximum length of filenames #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn maximum_name_length(&self) -> libc::__fsword_t { self.0.f_namelen } /// Maximum length of filenames #[cfg(target_os = "android")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn maximum_name_length(&self) -> libc::c_ulong { self.0.f_namelen } @@ -281,18 +304,21 @@ impl Statfs { target_os = "freebsd", target_os = "openbsd", ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks(&self) -> u64 { self.0.f_blocks } /// Total data blocks in filesystem #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks(&self) -> libc::c_long { self.0.f_blocks } /// Total data blocks in filesystem #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks(&self) -> u64 { self.0.f_blocks } @@ -307,6 +333,7 @@ impl Statfs { target_os = "dragonfly", all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))) )))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks(&self) -> libc::c_ulong { self.0.f_blocks } @@ -319,18 +346,21 @@ impl Statfs { target_os = "freebsd", target_os = "openbsd", ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_free(&self) -> u64 { self.0.f_bfree } /// Free blocks in filesystem #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_free(&self) -> libc::c_long { self.0.f_bfree } /// Free blocks in filesystem #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_free(&self) -> u64 { self.0.f_bfree } @@ -345,30 +375,35 @@ impl Statfs { target_os = "dragonfly", all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))) )))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_free(&self) -> libc::c_ulong { self.0.f_bfree } /// Free blocks available to unprivileged user #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_available(&self) -> u64 { self.0.f_bavail } /// Free blocks available to unprivileged user #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_available(&self) -> libc::c_long { self.0.f_bavail } /// Free blocks available to unprivileged user #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_available(&self) -> i64 { self.0.f_bavail } /// Free blocks available to unprivileged user #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_available(&self) -> u64 { self.0.f_bavail } @@ -383,6 +418,7 @@ impl Statfs { target_os = "dragonfly", all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))) )))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_available(&self) -> libc::c_ulong { self.0.f_bavail } @@ -395,18 +431,21 @@ impl Statfs { target_os = "freebsd", target_os = "openbsd", ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files(&self) -> u64 { self.0.f_files } /// Total file nodes in filesystem #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files(&self) -> libc::c_long { self.0.f_files } /// Total file nodes in filesystem #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files(&self) -> libc::fsfilcnt_t { self.0.f_files } @@ -421,6 +460,7 @@ impl Statfs { target_os = "dragonfly", all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))) )))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files(&self) -> libc::c_ulong { self.0.f_files } @@ -432,24 +472,28 @@ impl Statfs { target_os = "macos", target_os = "openbsd" ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> u64 { self.0.f_ffree } /// Free file nodes in filesystem #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> libc::c_long { self.0.f_ffree } /// Free file nodes in filesystem #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> i64 { self.0.f_ffree } /// Free file nodes in filesystem #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> libc::fsfilcnt_t { self.0.f_ffree } @@ -464,6 +508,7 @@ impl Statfs { target_os = "dragonfly", all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))) )))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> libc::c_ulong { self.0.f_ffree } diff --git a/src/sys/statvfs.rs b/src/sys/statvfs.rs index 15e7a7d4ab..ab54b4b50b 100644 --- a/src/sys/statvfs.rs +++ b/src/sys/statvfs.rs @@ -21,33 +21,43 @@ libc_bitflags!( ST_NOSUID; /// Do not interpret character or block-special devices #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ST_NODEV; /// Do not allow execution of binaries on the filesystem #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ST_NOEXEC; /// All IO should be done synchronously #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ST_SYNCHRONOUS; /// Allow mandatory locks on the filesystem #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ST_MANDLOCK; /// Write on file/directory/symlink #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] ST_WRITE; /// Append-only file #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] ST_APPEND; /// Immutable file #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] ST_IMMUTABLE; /// Do not update access times on files #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ST_NOATIME; /// Do not update access times on files #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ST_NODIRATIME; /// Update access time relative to modify/change time #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] ST_RELATIME; } ); @@ -109,6 +119,7 @@ impl Statvfs { /// Get the mount flags #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn flags(&self) -> FsFlags { FsFlags::from_bits_truncate(self.0.f_flag) } diff --git a/src/sys/termios.rs b/src/sys/termios.rs index 01d4608039..92204a051d 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -160,6 +160,7 @@ use std::convert::From; use std::mem; use std::os::unix::io::RawFd; +#[cfg(feature = "process")] use crate::unistd::Pid; /// Stores settings for the termios API @@ -276,6 +277,7 @@ libc_enum!{ target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B7200, B9600, #[cfg(any(target_os = "dragonfly", @@ -283,6 +285,7 @@ libc_enum!{ target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B14400, B19200, #[cfg(any(target_os = "dragonfly", @@ -290,6 +293,7 @@ libc_enum!{ target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B28800, B38400, B57600, @@ -298,12 +302,15 @@ libc_enum!{ target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B76800, B115200, #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B153600, B230400, #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B307200, #[cfg(any(target_os = "android", target_os = "freebsd", @@ -311,10 +318,13 @@ libc_enum!{ target_os = "linux", target_os = "netbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B460800, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B500000, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B576000, #[cfg(any(target_os = "android", target_os = "freebsd", @@ -322,22 +332,31 @@ libc_enum!{ target_os = "linux", target_os = "netbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B921600, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B1000000, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B1152000, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B1500000, #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B2000000, #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] B2500000, #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] B3000000, #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] B3500000, #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] B4000000, } impl TryFrom @@ -420,6 +439,7 @@ libc_enum! { target_os = "netbsd", target_os = "openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] VDSUSP, VEOF, VEOL, @@ -429,12 +449,14 @@ libc_enum! { target_os = "freebsd", target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] VERASE2, VINTR, VKILL, VLNEXT, #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), target_os = "illumos", target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] VMIN, VQUIT, VREPRINT, @@ -446,18 +468,23 @@ libc_enum! { target_os = "netbsd", target_os = "openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] VSTATUS, VSTOP, VSUSP, #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] VSWTC, #[cfg(any(target_os = "haiku", target_os = "illumos", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] VSWTCH, #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), target_os = "illumos", target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] VTIME, VWERASE, #[cfg(target_os = "dragonfly")] + #[cfg_attr(docsrs, doc(cfg(all())))] VCHECKPT, } } @@ -476,6 +503,7 @@ pub use libc::NCCS; target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub use libc::_POSIX_VDISABLE; libc_bitflags! { @@ -493,10 +521,13 @@ libc_bitflags! { IXON; IXOFF; #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IXANY; #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IMAXBEL; #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] IUTF8; } } @@ -509,6 +540,7 @@ libc_bitflags! { target_os = "haiku", target_os = "linux", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] OLCUC; ONLCR; OCRNL as tcflag_t; @@ -519,48 +551,56 @@ libc_bitflags! { target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] OFILL as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] OFDEL as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NL0 as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NL1 as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CR0 as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CR1 as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CR2 as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CR3 as tcflag_t; #[cfg(any(target_os = "android", target_os = "freebsd", @@ -568,18 +608,21 @@ libc_bitflags! { target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] TAB0 as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] TAB1 as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] TAB2 as tcflag_t; #[cfg(any(target_os = "android", target_os = "freebsd", @@ -587,44 +630,52 @@ libc_bitflags! { target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] TAB3 as tcflag_t; #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] XTABS; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] BS0 as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] BS1 as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] VT0 as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] VT1 as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] FF0 as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] FF1 as tcflag_t; #[cfg(any(target_os = "freebsd", target_os = "dragonfly", @@ -632,12 +683,14 @@ libc_bitflags! { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] OXTABS; #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ONOEOT as tcflag_t; // Bitmasks for use with OutputFlags to select specific settings @@ -649,12 +702,14 @@ libc_bitflags! { target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CRDLY as tcflag_t; #[cfg(any(target_os = "android", target_os = "freebsd", @@ -662,24 +717,28 @@ libc_bitflags! { target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] TABDLY as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] BSDLY as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] VTDLY as tcflag_t; #[cfg(any(target_os = "android", target_os = "haiku", target_os = "ios", target_os = "linux", target_os = "macos"))] + #[cfg_attr(docsrs, doc(cfg(all())))] FFDLY as tcflag_t; } } @@ -693,6 +752,7 @@ libc_bitflags! { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CIGNORE; CS5; CS6; @@ -705,43 +765,54 @@ libc_bitflags! { HUPCL; CLOCAL; #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CRTSCTS; #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CBAUD; #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))] + #[cfg_attr(docsrs, doc(cfg(all())))] CMSPAR; #[cfg(any(target_os = "android", all(target_os = "linux", not(any(target_arch = "powerpc", target_arch = "powerpc64")))))] CIBAUD; #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CBAUDEX; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MDMBUF; #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CHWFLOW; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CCTS_OFLOW; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CRTS_IFLOW; #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CDTR_IFLOW; #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CDSR_OFLOW; #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] CCAR_OFLOW; // Bitmasks for use with ControlFlags to select specific settings @@ -756,14 +827,17 @@ libc_bitflags! { /// Flags for setting any local modes pub struct LocalFlags: tcflag_t { #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ECHOKE; ECHOE; ECHOK; ECHO; ECHONL; #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ECHOPRT; #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ECHOCTL; ISIG; ICANON; @@ -773,12 +847,15 @@ libc_bitflags! { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] ALTWERASE; IEXTEN; #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] EXTPROC; TOSTOP; #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] FLUSHO; #[cfg(any(target_os = "freebsd", target_os = "dragonfly", @@ -786,8 +863,10 @@ libc_bitflags! { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] NOKERNINFO; #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] PENDIN; NOFLSH; } @@ -927,6 +1006,7 @@ pub fn cfmakeraw(termios: &mut Termios) { /// /// Note that this is a non-standard function, available on FreeBSD. #[cfg(target_os = "freebsd")] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn cfmakesane(termios: &mut Termios) { let inner_termios = unsafe { termios.get_libc_termios_mut() }; unsafe { @@ -995,6 +1075,8 @@ pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> { Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop) } +feature! { +#![feature = "process"] /// Get the session controlled by the given terminal (see /// [tcgetsid(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)). pub fn tcgetsid(fd: RawFd) -> Result { @@ -1002,6 +1084,7 @@ pub fn tcgetsid(fd: RawFd) -> Result { Errno::result(res).map(Pid::from_raw) } +} #[cfg(test)] mod test { diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 3abcde24fe..523240200f 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -31,6 +31,7 @@ pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result { /// /// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) #[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], offset: off_t) -> Result { let res = unsafe { @@ -48,6 +49,7 @@ pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], /// /// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) #[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>], offset: off_t) -> Result { let res = unsafe { @@ -92,6 +94,7 @@ pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result{ /// is used with [`process_vm_readv`](fn.process_vm_readv.html) /// and [`process_vm_writev`](fn.process_vm_writev.html). #[cfg(target_os = "linux")] +#[cfg_attr(docsrs, doc(cfg(all())))] #[repr(C)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct RemoteIoVec { @@ -101,6 +104,9 @@ pub struct RemoteIoVec { pub len: usize, } +feature! { +#![feature = "process"] + /// Write data directly to another process's virtual memory /// (see [`process_vm_writev`(2)]). /// @@ -170,6 +176,7 @@ pub fn process_vm_readv( Errno::result(res).map(|r| r as usize) } +} /// A vector of buffers. /// @@ -195,7 +202,7 @@ impl IoVec { } impl<'a> IoVec<&'a [u8]> { - #[cfg(target_os = "freebsd")] + #[cfg(all(feature = "mount", target_os = "freebsd"))] pub(crate) fn from_raw_parts(base: *mut c_void, len: usize) -> Self { IoVec(libc::iovec { iov_base: base, diff --git a/src/sys/wait.rs b/src/sys/wait.rs index ee49e37dec..20ca1c1907 100644 --- a/src/sys/wait.rs +++ b/src/sys/wait.rs @@ -27,6 +27,7 @@ libc_bitflags!( target_os = "redox", target_os = "macos", target_os = "netbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] WEXITED; /// Report the status of selected processes that have continued from a /// job control stop by receiving a @@ -41,6 +42,7 @@ libc_bitflags!( target_os = "redox", target_os = "macos", target_os = "netbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] WSTOPPED; /// Don't reap, just poll status. #[cfg(any(target_os = "android", @@ -51,15 +53,19 @@ libc_bitflags!( target_os = "redox", target_os = "macos", target_os = "netbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] WNOWAIT; /// Don't wait on children of other threads in this group #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] __WNOTHREAD; /// Wait on all children, regardless of type #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] __WALL; /// Wait for "clone" children only. #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] __WCLONE; } ); @@ -97,6 +103,7 @@ pub enum WaitStatus { /// [`nix::sys::ptrace`]: ../ptrace/index.html /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg_attr(docsrs, doc(cfg(all())))] PtraceEvent(Pid, Signal, c_int), /// The traced process was stopped by execution of a system call, /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for @@ -104,6 +111,7 @@ pub enum WaitStatus { /// /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg_attr(docsrs, doc(cfg(all())))] PtraceSyscall(Pid), /// The process was previously stopped but has resumed execution /// after receiving a `SIGCONT` signal. This is only reported if diff --git a/src/time.rs b/src/time.rs index 6275b59c74..6fd06ec811 100644 --- a/src/time.rs +++ b/src/time.rs @@ -6,6 +6,7 @@ use crate::sys::time::TimeSpec; target_os = "android", target_os = "emscripten", ))] +#[cfg(feature = "process")] use crate::unistd::Pid; use crate::{Errno, Result}; use libc::{self, clockid_t}; @@ -24,6 +25,8 @@ impl ClockId { ClockId(clk_id) } + feature! { + #![feature = "process"] /// Returns `ClockId` of a `pid` CPU-time clock #[cfg(any( target_os = "freebsd", @@ -32,12 +35,15 @@ impl ClockId { target_os = "android", target_os = "emscripten", ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn pid_cpu_clock_id(pid: Pid) -> Result { clock_getcpuclockid(pid) } + } /// Returns resolution of the clock id #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn res(self) -> Result { clock_getres(self) } @@ -56,6 +62,7 @@ impl ClockId { any(target_os = "redox", target_os = "hermit",), ), )))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn set_time(self, timespec: TimeSpec) -> Result<()> { clock_settime(self, timespec) } @@ -72,6 +79,7 @@ impl ClockId { any(target_os = "linux", target_os = "android", target_os = "emscripten"), ) ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME); #[cfg(any( target_os = "fuchsia", @@ -80,6 +88,7 @@ impl ClockId { any(target_os = "linux", target_os = "android", target_os = "emscripten") ) ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM); pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC); #[cfg(any( @@ -89,10 +98,13 @@ impl ClockId { any(target_os = "linux", target_os = "android", target_os = "emscripten") ) ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_MONOTONIC_FAST: ClockId = ClockId(libc::CLOCK_MONOTONIC_FAST); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE); #[cfg(any( target_os = "fuchsia", @@ -101,6 +113,7 @@ impl ClockId { any(target_os = "linux", target_os = "android", target_os = "emscripten") ) ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW); #[cfg(any( target_os = "fuchsia", @@ -114,8 +127,10 @@ impl ClockId { any(target_os = "linux", target_os = "android", target_os = "emscripten") ) ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF); pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME); #[cfg(any( @@ -125,6 +140,7 @@ impl ClockId { any(target_os = "linux", target_os = "android", target_os = "emscripten") ) ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM); #[cfg(any( target_os = "fuchsia", @@ -133,12 +149,16 @@ impl ClockId { any(target_os = "linux", target_os = "android", target_os = "emscripten") ) ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_REALTIME_PRECISE: ClockId = ClockId(libc::CLOCK_REALTIME_PRECISE); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND); #[cfg(any( target_os = "fuchsia", @@ -150,6 +170,7 @@ impl ClockId { ) ) ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE); #[cfg(any( target_os = "fuchsia", @@ -161,6 +182,7 @@ impl ClockId { ) ) ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI); #[cfg(any( target_env = "uclibc", @@ -174,14 +196,19 @@ impl ClockId { any(target_os = "linux", target_os = "android", target_os = "emscripten",), ), ))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_UPTIME_PRECISE: ClockId = ClockId(libc::CLOCK_UPTIME_PRECISE); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL); } @@ -206,6 +233,7 @@ impl std::fmt::Display for ClockId { /// Get the resolution of the specified clock, (see /// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)). #[cfg(not(target_os = "redox"))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn clock_getres(clock_id: ClockId) -> Result { let mut c_time: MaybeUninit = MaybeUninit::uninit(); let ret = unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) }; @@ -234,6 +262,7 @@ pub fn clock_gettime(clock_id: ClockId) -> Result { any(target_os = "redox", target_os = "hermit",), ), )))] +#[cfg_attr(docsrs, doc(cfg(all())))] pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) }; Errno::result(ret).map(drop) @@ -248,6 +277,8 @@ pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { target_os = "android", target_os = "emscripten", ))] +#[cfg(feature = "process")] +#[cfg_attr(docsrs, doc(cfg(feature = "process")))] pub fn clock_getcpuclockid(pid: Pid) -> Result { let mut clk_id: MaybeUninit = MaybeUninit::uninit(); let ret = unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) }; diff --git a/src/unistd.rs b/src/unistd.rs index 2c89d77240..d48541f678 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -5,11 +5,12 @@ use cfg_if::cfg_if; use crate::errno::{self, Errno}; use crate::{Error, Result, NixPath}; #[cfg(not(target_os = "redox"))] +#[cfg(feature = "fs")] use crate::fcntl::{AtFlags, at_rawfd}; -use crate::fcntl::{FdFlag, OFlag, fcntl}; -use crate::fcntl::FcntlArg::F_SETFD; use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t, PATH_MAX}; +#[cfg(feature = "fs")] +use crate::fcntl::{FdFlag, OFlag, fcntl, FcntlArg::F_SETFD}; use std::{fmt, mem, ptr}; use std::convert::Infallible; use std::ffi::{CStr, OsString}; @@ -20,10 +21,14 @@ use std::os::unix::ffi::OsStringExt; use std::os::unix::ffi::OsStrExt; use std::os::unix::io::RawFd; use std::path::PathBuf; +#[cfg(feature = "fs")] use crate::sys::stat::Mode; -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use self::pivot_root::*; +feature! { + #![feature = "fs"] + #[cfg(any(target_os = "android", target_os = "linux"))] + pub use self::pivot_root::*; +} #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))] @@ -32,6 +37,9 @@ pub use self::setres::*; #[cfg(any(target_os = "android", target_os = "linux"))] pub use self::getres::*; +feature! { +#![feature = "users"] + /// User identifier /// /// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally @@ -121,7 +129,10 @@ impl fmt::Display for Gid { fmt::Display::fmt(&self.0, f) } } +} +feature! { +#![feature = "process"] /// Process identifier /// /// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally @@ -303,8 +314,10 @@ pub fn getsid(pid: Option) -> Result { let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) }; Errno::result(res).map(Pid) } +} - +feature! { +#![all(feature = "process", feature = "term")] /// Get the terminal foreground process group (see /// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)). /// @@ -325,8 +338,10 @@ pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> { let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) }; Errno::result(res).map(drop) } +} - +feature! { +#![feature = "process"] /// Get the group id of the calling process (see ///[getpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)). /// @@ -352,7 +367,10 @@ pub fn getpgrp() -> Pid { pub fn gettid() -> Pid { Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t }) } +} +feature! { +#![feature = "fs"] /// Create a copy of the specified file descriptor (see /// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). /// @@ -562,9 +580,11 @@ pub fn symlinkat( })??; Errno::result(res).map(drop) } +} // Double the buffer capacity up to limit. In case it already has // reached the limit, return Errno::ERANGE. +#[cfg(any(feature = "fs", feature = "users"))] fn reserve_double_buffer_size(buf: &mut Vec, limit: usize) -> Result<()> { use std::cmp::min; @@ -578,6 +598,9 @@ fn reserve_double_buffer_size(buf: &mut Vec, limit: usize) -> Result<()> { Ok(()) } +feature! { +#![feature = "fs"] + /// Returns the current directory as a `PathBuf` /// /// Err is returned if the current user doesn't have the permission to read or search a component @@ -621,6 +644,10 @@ pub fn getcwd() -> Result { } } } +} + +feature! { +#![all(feature = "users", feature = "fs")] /// Computes the raw UID and GID values to pass to a `*chown` call. // The cast is not unnecessary on all platforms. @@ -716,10 +743,16 @@ pub fn fchownat( Errno::result(res).map(drop) } +} +feature! { +#![feature = "process"] fn to_exec_array>(args: &[S]) -> Vec<*const c_char> { use std::iter::once; - args.iter().map(|s| s.as_ref().as_ptr()).chain(once(ptr::null())).collect() + args.iter() + .map(|s| s.as_ref().as_ptr()) + .chain(once(ptr::null())) + .collect() } /// Replace the current process image with a new one (see @@ -895,6 +928,10 @@ pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; Errno::result(res).map(drop) } +} + +feature! { +#![feature = "hostname"] /// Set the system host name (see /// [sethostname(2)](https://man7.org/linux/man-pages/man2/gethostname.2.html)). @@ -955,6 +992,7 @@ pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> { unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) } }) } +} /// Close a raw file descriptor /// @@ -1004,6 +1042,9 @@ pub fn write(fd: RawFd, buf: &[u8]) -> Result { Errno::result(res).map(|r| r as usize) } +feature! { +#![feature = "fs"] + /// Directive that tells [`lseek`] and [`lseek64`] what the offset is relative to. /// /// [`lseek`]: ./fn.lseek.html @@ -1054,6 +1095,7 @@ pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result std::result::Result<(RawFd, RawFd), Error> { } } +feature! { +#![feature = "fs"] /// Like `pipe`, but allows setting certain file descriptor flags. /// /// The following flags are supported, and will be set atomically as the pipe is @@ -1294,6 +1338,10 @@ pub fn fdatasync(fd: RawFd) -> Result<()> { Errno::result(res).map(drop) } +} + +feature! { +#![feature = "users"] /// Get a real user ID /// @@ -1374,7 +1422,10 @@ pub fn setgid(gid: Gid) -> Result<()> { Errno::result(res).map(drop) } +} +feature! { +#![all(feature = "fs", feature = "users")] /// Set the user identity used for filesystem checks per-thread. /// On both success and failure, this call returns the previous filesystem user /// ID of the caller. @@ -1396,6 +1447,10 @@ pub fn setfsgid(gid: Gid) -> Gid { let prev_fsgid = unsafe { libc::setfsgid(gid.into()) }; Gid::from_raw(prev_fsgid as gid_t) } +} + +feature! { +#![feature = "users"] /// Get the list of supplementary group IDs of the calling process. /// @@ -1625,6 +1680,10 @@ pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { Errno::result(res).map(drop) } +} + +feature! { +#![feature = "signal"] /// Suspend the thread until a signal is received. /// @@ -1722,6 +1781,7 @@ pub mod alarm { } } } +} /// Suspend execution for an interval of time /// @@ -1732,6 +1792,9 @@ pub fn sleep(seconds: c_uint) -> c_uint { unsafe { libc::sleep(seconds) } } +feature! { +#![feature = "acct"] + #[cfg(not(target_os = "redox"))] pub mod acct { use crate::{Result, NixPath}; @@ -1756,7 +1819,10 @@ pub mod acct { Errno::result(res).map(drop) } } +} +feature! { +#![feature = "fs"] /// Creates a regular file which persists even after process termination /// /// * `template`: a path whose 6 rightmost characters must be X, e.g. `/tmp/tmpfile_XXXXXX` @@ -1792,6 +1858,10 @@ pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { Errno::result(fd)?; Ok((fd, PathBuf::from(pathname))) } +} + +feature! { +#![all(feature = "fs", feature = "features")] /// Variable names for `pathconf` /// @@ -1817,6 +1887,7 @@ pub enum PathconfVar { target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] /// Minimum number of bits needed to represent, as a signed integer value, /// the maximum size of a regular file allowed in the specified directory. + #[cfg_attr(docsrs, doc(cfg(all())))] FILESIZEBITS = libc::_PC_FILESIZEBITS, /// Maximum number of links to a single file. LINK_MAX = libc::_PC_LINK_MAX, @@ -1840,33 +1911,40 @@ pub enum PathconfVar { #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "illumos", target_os = "linux", target_os = "netbsd", target_os = "openbsd", target_os = "redox", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Symbolic links can be created. POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Minimum number of bytes of storage actually allocated for any portion of /// a file. POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Recommended increment for file transfer sizes between the /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values. POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Maximum recommended file transfer size. POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Minimum recommended file transfer size. POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd", target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Recommended file transfer buffer alignment. POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "illumos", target_os = "linux", target_os = "netbsd", target_os = "openbsd", target_os = "redox", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Maximum number of bytes in a symbolic link. SYMLINK_MAX = libc::_PC_SYMLINK_MAX, /// The use of `chown` and `fchown` is restricted to a process with @@ -1882,22 +1960,26 @@ pub enum PathconfVar { #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "illumos", target_os = "linux", target_os = "openbsd", target_os = "redox", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Asynchronous input or output operations may be performed for the /// associated file. _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "illumos", target_os = "linux", target_os = "openbsd", target_os = "redox", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Prioritized input or output operations may be performed for the /// associated file. _POSIX_PRIO_IO = libc::_PC_PRIO_IO, #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "illumos", target_os = "linux", target_os = "netbsd", target_os = "openbsd", target_os = "redox", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Synchronized input or output operations may be performed for the /// associated file. _POSIX_SYNC_IO = libc::_PC_SYNC_IO, #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The resolution in nanoseconds for all file timestamps. _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION } @@ -1972,6 +2054,10 @@ pub fn pathconf(path: &P, var: PathconfVar) -> Result. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] LINE_MAX = libc::_SC_LINE_MAX, /// Maximum length of a login name. LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX, @@ -2061,211 +2161,267 @@ pub enum SysconfVar { NGROUPS_MAX = libc::_SC_NGROUPS_MAX, /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX, /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX, /// The maximum number of open message queue descriptors a process may hold. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX, /// The maximum number of message priorities supported by the implementation. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX, /// A value one greater than the maximum value that the system may assign to /// a newly-created file descriptor. OPEN_MAX = libc::_SC_OPEN_MAX, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Advisory Information option. _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports barriers. _POSIX_BARRIERS = libc::_SC_BARRIERS, /// The implementation supports asynchronous input and output. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports clock selection. _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Process CPU-Time Clocks option. _POSIX_CPUTIME = libc::_SC_CPUTIME, /// The implementation supports the File Synchronization option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_FSYNC = libc::_SC_FSYNC, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the IPv6 option. _POSIX_IPV6 = libc::_SC_IPV6, /// The implementation supports job control. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL, /// The implementation supports memory mapped Files. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES, /// The implementation supports the Process Memory Locking option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MEMLOCK = libc::_SC_MEMLOCK, /// The implementation supports the Range Memory Locking option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE, /// The implementation supports memory protection. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION, /// The implementation supports the Message Passing option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING, /// The implementation supports the Monotonic Clock option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", target_os = "illumos", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Prioritized Input and Output option. _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO, /// The implementation supports the Process Scheduling option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Raw Sockets option. _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports read-write locks. _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS, #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports realtime signals. _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Regular Expression Handling option. _POSIX_REGEXP = libc::_SC_REGEXP, /// Each process has a saved set-user-ID and a saved set-group-ID. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS, /// The implementation supports semaphores. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES, /// The implementation supports the Shared Memory Objects option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the POSIX shell. _POSIX_SHELL = libc::_SC_SHELL, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Spawn option. _POSIX_SPAWN = libc::_SC_SPAWN, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports spin locks. _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Process Sporadic Server option. _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER, #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX, /// The implementation supports the Synchronized Input and Output option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO, /// The implementation supports the Thread Stack Address Attribute option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR, /// The implementation supports the Thread Stack Size Attribute option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE, #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Thread CPU-Time Clocks option. _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME, /// The implementation supports the Non-Robust Mutex Priority Inheritance /// option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT, /// The implementation supports the Non-Robust Mutex Priority Protection option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT, /// The implementation supports the Thread Execution Scheduling option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Thread Process-Shared Synchronization /// option. _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED, #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Robust Mutex Priority Inheritance option. _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT, #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Robust Mutex Priority Protection option. _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT, /// The implementation supports thread-safe functions. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Thread Sporadic Server option. _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER, /// The implementation supports threads. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREADS = libc::_SC_THREADS, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports timeouts. _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS, /// The implementation supports timers. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TIMERS = libc::_SC_TIMERS, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace option. _POSIX_TRACE = libc::_SC_TRACE, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace Event Filter option. _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER, #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace Inherit option. _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace Log option. _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG, #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX, #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX, #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Typed Memory Objects option. _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS, /// Integer value indicating version of this standard (C-language binding) @@ -2275,12 +2431,14 @@ pub enum SysconfVar { #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation provides a C-language compilation environment with /// 32-bit `int`, `long`, `pointer`, and `off_t` types. _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation provides a C-language compilation environment with /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at /// least 64 bits. @@ -2288,75 +2446,92 @@ pub enum SysconfVar { #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation provides a C-language compilation environment with /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types. _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation provides a C-language compilation environment with an /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types /// using at least 64 bits. _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG, /// The implementation supports the C-Language Binding option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_C_BIND = libc::_SC_2_C_BIND, /// The implementation supports the C-Language Development Utilities option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_C_DEV = libc::_SC_2_C_DEV, /// The implementation supports the Terminal Characteristics option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM, /// The implementation supports the FORTRAN Development Utilities option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV, /// The implementation supports the FORTRAN Runtime Utilities option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN, /// The implementation supports the creation of locales by the localedef /// utility. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Batch Environment Services and Utilities /// option. _POSIX2_PBS = libc::_SC_2_PBS, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Batch Accounting option. _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Batch Checkpoint/Restart option. _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Locate Batch Job Request option. _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Batch Job Message Request option. _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Track Batch Job Request option. _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK, /// The implementation supports the Software Development Utilities option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_SW_DEV = libc::_SC_2_SW_DEV, /// The implementation supports the User Portability Utilities option. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_UPE = libc::_SC_2_UPE, /// Integer value indicating version of the Shell and Utilities volume of /// POSIX.1 to which the implementation conforms. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_VERSION = libc::_SC_2_VERSION, /// The size of a system page in bytes. /// @@ -2364,78 +2539,97 @@ pub enum SysconfVar { /// enum constants to have the same value, so nix omits `PAGESIZE`. PAGE_SIZE = libc::_SC_PAGE_SIZE, #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS, #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX, #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN, #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX, RE_DUP_MAX = libc::_SC_RE_DUP_MAX, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] RTSIG_MAX = libc::_SC_RTSIG_MAX, #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX, #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX, STREAM_MAX = libc::_SC_STREAM_MAX, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="netbsd", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX, #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] TIMER_MAX = libc::_SC_TIMER_MAX, TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX, TZNAME_MAX = libc::_SC_TZNAME_MAX, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the X/Open Encryption Option Group. _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Issue 4, Version 2 Enhanced /// Internationalization Option Group. _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the X/Open Realtime Option Group. _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the X/Open Realtime Threads Option Group. _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS, /// The implementation supports the Issue 4, Version 2 Shared Memory Option /// Group. #[cfg(not(target_os = "redox"))] + #[cfg_attr(docsrs, doc(cfg(all())))] _XOPEN_SHM = libc::_SC_XOPEN_SHM, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the XSI STREAMS Option Group. _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the XSI option _XOPEN_UNIX = libc::_SC_XOPEN_UNIX, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// Integer value indicating version of the X/Open Portability Guide to /// which the implementation conforms. _XOPEN_VERSION = libc::_SC_XOPEN_VERSION, @@ -2472,6 +2666,10 @@ pub fn sysconf(var: SysconfVar) -> Result> { Ok(Some(raw)) } } +} + +feature! { +#![feature = "fs"] #[cfg(any(target_os = "android", target_os = "linux"))] mod pivot_root { @@ -2491,10 +2689,14 @@ mod pivot_root { Errno::result(res).map(drop) } } +} #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))] mod setres { + feature! { + #![feature = "users"] + use crate::Result; use crate::errno::Errno; use super::{Uid, Gid}; @@ -2530,10 +2732,14 @@ mod setres { Errno::result(res).map(drop) } + } } #[cfg(any(target_os = "android", target_os = "linux"))] mod getres { + feature! { + #![feature = "users"] + use crate::Result; use crate::errno::Errno; use super::{Uid, Gid}; @@ -2591,10 +2797,13 @@ mod getres { Errno::result(res).map(|_| ResGid { real: Gid(rgid), effective: Gid(egid), saved: Gid(sgid) } ) } + } } +#[cfg(feature = "fs")] libc_bitflags!{ /// Options for access() + #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] pub struct AccessFlags : c_int { /// Test for existence of file. F_OK; @@ -2607,6 +2816,9 @@ libc_bitflags!{ } } +feature! { +#![feature = "fs"] + /// Checks the file named by `path` for accessibility according to the flags given by `amode` /// See [access(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html) pub fn access(path: &P, amode: AccessFlags) -> Result<()> { @@ -2617,6 +2829,10 @@ pub fn access(path: &P, amode: AccessFlags) -> Result<()> { })?; Errno::result(res).map(drop) } +} + +feature! { +#![feature = "users"] /// Representation of a User, based on `libc::passwd` /// @@ -2648,6 +2864,7 @@ pub struct User { target_os = "illumos", target_os = "linux", target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub class: CString, /// Last password change #[cfg(not(any(target_os = "android", @@ -2655,6 +2872,7 @@ pub struct User { target_os = "illumos", target_os = "linux", target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub change: libc::time_t, /// Expiration time of account #[cfg(not(any(target_os = "android", @@ -2662,6 +2880,7 @@ pub struct User { target_os = "illumos", target_os = "linux", target_os = "solaris")))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub expire: libc::time_t } @@ -2758,7 +2977,7 @@ impl User { fn from_anything(f: F) -> Result> where F: Fn(*mut libc::passwd, - *mut libc::c_char, + *mut c_char, libc::size_t, *mut *mut libc::passwd) -> libc::c_int { @@ -2879,7 +3098,7 @@ impl Group { fn from_anything(f: F) -> Result> where F: Fn(*mut libc::group, - *mut libc::c_char, + *mut c_char, libc::size_t, *mut *mut libc::group) -> libc::c_int { @@ -2954,6 +3173,10 @@ impl Group { }) } } +} + +feature! { +#![feature = "term"] /// Get the name of the terminal device that is open on file descriptor fd /// (see [`ttyname(3)`](https://man7.org/linux/man-pages/man3/ttyname.3.html)). @@ -2972,6 +3195,10 @@ pub fn ttyname(fd: RawFd) -> Result { buf.truncate(nul); Ok(OsString::from_vec(buf).into()) } +} + +feature! { +#![all(feature = "socket", feature = "users")] /// Get the effective user ID and group ID associated with a Unix domain socket. /// @@ -2992,3 +3219,4 @@ pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> { Errno::result(ret).map(|_| (Uid(uid), Gid(gid))) } +} From a91424f614e43ad78e7d41fe694afb9f303ff464 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 20 Dec 2021 22:39:36 -0700 Subject: [PATCH 005/358] Use the correct toolchain for cargo-hack --- .cirrus.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 7d2f41168f..086cca5709 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -19,8 +19,8 @@ build: &BUILD - $TOOL +$TOOLCHAIN $BUILD $ZFLAGS --target $TARGET --all-targets - $TOOL +$TOOLCHAIN doc $ZFLAGS --no-deps --target $TARGET - $TOOL +$TOOLCHAIN clippy $ZFLAGS --target $TARGET -- -D warnings - - if [ -z "$NOHACK" ]; then $TOOL install cargo-hack; fi - - if [ -z "$NOHACK" ]; then $TOOL hack $ZFLAGS check --target $TARGET --each-feature; fi + - if [ -z "$NOHACK" ]; then $TOOL +$TOOLCHAIN install cargo-hack; fi + - if [ -z "$NOHACK" ]; then $TOOL +$TOOLCHAIN hack $ZFLAGS check --target $TARGET --each-feature; fi # Tests that do require executing the binaries test: &TEST From 0b4717d3a4bf6cedf3406d58ccc369c31fc28d0e Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 20 Dec 2021 22:41:36 -0700 Subject: [PATCH 006/358] try cargo-hack on Redox. It might work. --- .cirrus.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 086cca5709..4e1da038ef 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -254,8 +254,6 @@ task: name: Redox x86_64 env: TARGET: x86_64-unknown-redox - # cargo-hack needs a newer compiler. # TODO: try enabling NOHACK. - NOHACK: 1 # Redox requires a nightly compiler. # If stuff breaks, change nightly to the date at # https://gitlab.redox-os.org/redox-os/redox/-/blob/master/rust-toolchain From 771c710e903c7176eb362fe632fb9fbf0e6f6910 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 20 Dec 2021 22:42:39 -0700 Subject: [PATCH 007/358] Fix merge error in CHANGELOG --- CHANGELOG.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46a3eff4b2..d935e28c5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +## [Unreleased] - ReleaseDate +### Added + +- Added fine-grained features flags. Most Nix functionality can now be + conditionally enabled. By default, all features are enabled. + (#[1611](https://github.com/nix-rust/nix/pull/1611)) + +### Changed +### Fixed +### Removed + ## [0.23.1] - 2021-12-16 ### Added @@ -20,17 +31,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). `0..FD_SETSIZE`. (#[1575](https://github.com/nix-rust/nix/pull/1575)) -## [Unreleased] - ReleaseDate -### Added - -- Added fine-grained features flags. Most Nix functionality can now be - conditionally enabled. By default, all features are enabled. - (#[1498](https://github.com/nix-rust/nix/pull/1498)) - -### Changed -### Fixed -### Removed - ## [0.23.0] - 2021-09-28 ### Added From 2d45fab9f36110de95a4e91e78c546c44e82a306 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 22 Oct 2021 20:00:02 -0600 Subject: [PATCH 008/358] impl Send and Sync for IoVec --- CHANGELOG.md | 2 ++ src/sys/uio.rs | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1f06dd648..63bb744098 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added `fexecve` on DragonFly. (#[1577](https://github.com/nix-rust/nix/pull/1577)) +- `sys::uio::IoVec` is now `Send` and `Sync` + (#[1582](https://github.com/nix-rust/nix/pull/1582)) - Added fine-grained features flags. Most Nix functionality can now be conditionally enabled. By default, all features are enabled. (#[1611](https://github.com/nix-rust/nix/pull/1611)) diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 523240200f..125c2e6c30 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -228,3 +228,8 @@ impl<'a> IoVec<&'a mut [u8]> { }, PhantomData) } } + +// The only reason IoVec isn't automatically Send+Sync is because libc::iovec +// contains raw pointers. +unsafe impl Send for IoVec where T: Send {} +unsafe impl Sync for IoVec where T: Sync {} From 867ac514b03801b14839ea3815918f7c32be282c Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 21 Dec 2021 08:50:57 -0700 Subject: [PATCH 009/358] Improve the sockaddr interface: * All sockaddr newtypes should be repr(transparent) * All sockaddr newtypes should be opaque, so the user can't do something like change the sa_family field in a way that violates invariants. This is a prerequisite for #1544. --- CHANGELOG.md | 4 ++++ src/sys/socket/addr.rs | 21 ++++++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63bb744098..d431166832 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Fixed ### Removed +- Removed public access to the inner fields of `NetlinkAddr`, `AlgAddr`, + `SysControlAddr`, `LinkAddr`, and `VsockAddr`. + (#[1614](https://github.com/nix-rust/nix/pull/1614)) + ## [0.23.1] - 2021-12-16 ### Added diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index fa62706ebb..f06a80d3fb 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -473,6 +473,7 @@ impl fmt::Display for IpAddr { */ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(transparent)] pub struct Ipv4Addr(pub libc::in_addr); impl Ipv4Addr { @@ -522,6 +523,7 @@ impl fmt::Display for Ipv4Addr { */ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[repr(transparent)] pub struct Ipv6Addr(pub libc::in6_addr); // Note that IPv6 addresses are stored in big endian order on all architectures. @@ -1062,7 +1064,8 @@ pub mod netlink { use std::{fmt, mem}; #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] - pub struct NetlinkAddr(pub sockaddr_nl); + #[repr(transparent)] + pub struct NetlinkAddr(pub(in super::super) sockaddr_nl); impl NetlinkAddr { pub fn new(pid: u32, groups: u32) -> NetlinkAddr { @@ -1099,7 +1102,8 @@ pub mod alg { use std::ffi::CStr; #[derive(Copy, Clone)] - pub struct AlgAddr(pub sockaddr_alg); + #[repr(transparent)] + pub struct AlgAddr(pub(in super::super) sockaddr_alg); // , PartialEq, Eq, Debug, Hash impl PartialEq for AlgAddr { @@ -1179,9 +1183,9 @@ pub mod sys_control { ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info); - #[repr(C)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct SysControlAddr(pub libc::sockaddr_ctl); + #[repr(transparent)] + pub struct SysControlAddr(pub(in super::super) libc::sockaddr_ctl); impl SysControlAddr { pub const fn new(id: u32, unit: u32) -> SysControlAddr { @@ -1238,7 +1242,8 @@ mod datalink { /// Hardware Address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct LinkAddr(pub libc::sockaddr_ll); + #[repr(transparent)] + pub struct LinkAddr(pub(in super::super) libc::sockaddr_ll); impl LinkAddr { /// Always AF_PACKET @@ -1315,7 +1320,8 @@ mod datalink { /// Hardware Address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] - pub struct LinkAddr(pub libc::sockaddr_dl); + #[repr(transparent)] + pub struct LinkAddr(pub(in super::super) libc::sockaddr_dl); impl LinkAddr { /// Total length of sockaddr @@ -1408,7 +1414,8 @@ pub mod vsock { use std::hash::{Hash, Hasher}; #[derive(Copy, Clone)] - pub struct VsockAddr(pub sockaddr_vm); + #[repr(transparent)] + pub struct VsockAddr(pub(in super::super) sockaddr_vm); impl PartialEq for VsockAddr { fn eq(&self, other: &Self) -> bool { From 2eb6e88406f84e6800c4aa26e64fc3b2be8442eb Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Tue, 19 Oct 2021 23:51:55 -0500 Subject: [PATCH 010/358] DragonFly 6.0 added fexecve(2) --- CHANGELOG.md | 2 ++ Cargo.toml | 2 +- src/unistd.rs | 4 +--- test/test_unistd.rs | 12 ++++-------- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d935e28c5d..745f6a2e4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added `fexecve` on DragonFly. + (#[1577](https://github.com/nix-rust/nix/pull/1577)) - Added fine-grained features flags. Most Nix functionality can now be conditionally enabled. By default, all features are enabled. (#[1611](https://github.com/nix-rust/nix/pull/1611)) diff --git a/Cargo.toml b/Cargo.toml index e515e4eb69..03941aa5f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.102", features = [ "extra_traits" ] } +libc = { version = "0.2.112", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" diff --git a/src/unistd.rs b/src/unistd.rs index d48541f678..0e7f94e0fa 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -848,11 +848,9 @@ pub fn execvpe, SE: AsRef>(filename: &CStr, args: &[SA], e /// /// This function is similar to `execve`, except that the program to be executed /// is referenced as a file descriptor instead of a path. -// Note for NetBSD and OpenBSD: although rust-lang/libc includes it (under -// unix/bsd/netbsdlike/) fexecve is not currently implemented on NetBSD nor on -// OpenBSD. #[cfg(any(target_os = "android", target_os = "linux", + target_os = "dragonfly", target_os = "freebsd"))] #[inline] pub fn fexecve ,SE: AsRef>(fd: RawFd, args: &[SA], env: &[SE]) -> Result { diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 61062ad229..59ab24e462 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -363,25 +363,21 @@ cfg_if!{ if #[cfg(target_os = "android")] { execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap().as_c_str()); execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd()); - } else if #[cfg(any(target_os = "freebsd", + } else if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", target_os = "linux"))] { // These tests frequently fail on musl, probably due to // https://github.com/nix-rust/nix/issues/555 execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd()); - } else if #[cfg(any(target_os = "dragonfly", - target_os = "illumos", + } else if #[cfg(any(target_os = "illumos", target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd", target_os = "solaris"))] { execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str()); - // No fexecve() on DragonFly, ios, macos, NetBSD, OpenBSD. - // - // Note for NetBSD and OpenBSD: although rust-lang/libc includes it - // (under unix/bsd/netbsdlike/) fexecve is not currently implemented on - // NetBSD nor on OpenBSD. + // No fexecve() on ios, macos, NetBSD, OpenBSD. } } From 6d07477fac02d14ddd885fa298346d4403c2aacb Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 21 Dec 2021 18:14:49 -0700 Subject: [PATCH 011/358] UnixAddr: replace path_len with sun_len Within UnixAddr, replace the path_len variable (length of the sun_path field) with sun_len (length of the whole structure). This is more similar to how other sockaddr types work, and it's the same way that the BSDs use the sun_len field. Also, don't require that sun_path be nul-terminated. The OS doesn't require it. --- src/sys/socket/addr.rs | 82 ++++++++++++++++++++++++++++-------------- src/sys/socket/mod.rs | 6 ++-- 2 files changed, 59 insertions(+), 29 deletions(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index f06a80d3fb..0b7932ca13 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -3,6 +3,7 @@ use crate::{Result, NixPath}; use crate::errno::Errno; use memoffset::offset_of; use std::{fmt, mem, net, ptr, slice}; +use std::convert::TryInto; use std::ffi::OsStr; use std::hash::{Hash, Hasher}; use std::path::Path; @@ -575,9 +576,11 @@ impl fmt::Display for Ipv6Addr { /// A wrapper around `sockaddr_un`. #[derive(Clone, Copy, Debug)] pub struct UnixAddr { - // INVARIANT: sun & path_len are valid as defined by docs for from_raw_parts + // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts sun: libc::sockaddr_un, - path_len: usize, + /// The length of the valid part of `sun`, including the sun_family field + /// but excluding any trailing nul. + sun_len: u8, } // linux man page unix(7) says there are 3 kinds of unix socket: @@ -594,8 +597,10 @@ enum UnixAddrKind<'a> { Abstract(&'a [u8]), } impl<'a> UnixAddrKind<'a> { - /// Safety: sun & path_len must be valid - unsafe fn get(sun: &'a libc::sockaddr_un, path_len: usize) -> Self { + /// Safety: sun & sun_len must be valid + unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self { + assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path)); + let path_len = sun_len as usize - offset_of!(libc::sockaddr_un, sun_path); if path_len == 0 { return Self::Unnamed; } @@ -605,7 +610,7 @@ impl<'a> UnixAddrKind<'a> { slice::from_raw_parts(sun.sun_path.as_ptr().add(1) as *const u8, path_len - 1); return Self::Abstract(name); } - let pathname = slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len - 1); + let pathname = slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len); Self::Pathname(Path::new(OsStr::from_bytes(pathname))) } } @@ -626,18 +631,32 @@ impl UnixAddr { return Err(Errno::ENAMETOOLONG); } + let sun_len = (bytes.len() + + offset_of!(libc::sockaddr_un, sun_path)).try_into() + .unwrap(); + + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd"))] + { + ret.sun_len = sun_len; + } ptr::copy_nonoverlapping(bytes.as_ptr(), ret.sun_path.as_mut_ptr() as *mut u8, bytes.len()); - Ok(UnixAddr::from_raw_parts(ret, bytes.len() + 1)) + Ok(UnixAddr::from_raw_parts(ret, sun_len)) } })? } /// Create a new `sockaddr_un` representing an address in the "abstract namespace". /// - /// The leading null byte for the abstract namespace is automatically added; + /// The leading nul byte for the abstract namespace is automatically added; /// thus the input `path` is expected to be the bare name, not null-prefixed. /// This is a Linux-specific extension, primarily used to allow chrooted /// processes to communicate with processes having a different filesystem view. @@ -653,6 +672,10 @@ impl UnixAddr { if path.len() >= ret.sun_path.len() { return Err(Errno::ENAMETOOLONG); } + let sun_len = (path.len() + + 1 + + offset_of!(libc::sockaddr_un, sun_path)).try_into() + .unwrap(); // Abstract addresses are represented by sun_path[0] == // b'\0', so copy starting one byte in. @@ -660,32 +683,39 @@ impl UnixAddr { ret.sun_path.as_mut_ptr().offset(1) as *mut u8, path.len()); - Ok(UnixAddr::from_raw_parts(ret, path.len() + 1)) + Ok(UnixAddr::from_raw_parts(ret, sun_len)) } } - /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `path_len` is the "addrlen" - /// of this address, but minus `offsetof(struct sockaddr_un, sun_path)`. Basically the length - /// of the data in `sun_path`. + /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len` + /// is the size of the valid portion of the struct, excluding any trailing + /// NUL. /// /// # Safety - /// This pair of sockaddr_un & path_len must be a valid unix addr, which means: - /// - path_len <= sockaddr_un.sun_path.len() - /// - if this is a unix addr with a pathname, sun.sun_path is a nul-terminated fs path and - /// sun.sun_path[path_len - 1] == 0 || sun.sun_path[path_len] == 0 - pub(crate) unsafe fn from_raw_parts(sun: libc::sockaddr_un, mut path_len: usize) -> UnixAddr { - if let UnixAddrKind::Pathname(_) = UnixAddrKind::get(&sun, path_len) { - if sun.sun_path[path_len - 1] != 0 { - assert_eq!(sun.sun_path[path_len], 0); - path_len += 1 - } + /// This pair of sockaddr_un & sun_len must be a valid unix addr, which + /// means: + /// - sun_len >= offset_of(sockaddr_un, sun_path) + /// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path) + /// - if this is a unix addr with a pathname, sun.sun_path is a + /// fs path, not necessarily nul-terminated. + pub(crate) unsafe fn from_raw_parts(sun: libc::sockaddr_un, sun_len: u8) -> UnixAddr { + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd"))] + { + assert_eq!(sun_len, sun.sun_len); } - UnixAddr { sun, path_len } + + UnixAddr { sun, sun_len } } fn kind(&self) -> UnixAddrKind<'_> { // SAFETY: our sockaddr is always valid because of the invariant on the struct - unsafe { UnixAddrKind::get(&self.sun, self.path_len) } + unsafe { UnixAddrKind::get(&self.sun, self.sun_len) } } /// If this address represents a filesystem path, return that path. @@ -712,7 +742,7 @@ impl UnixAddr { /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)` #[inline] pub fn path_len(&self) -> usize { - self.path_len + self.sun_len as usize - offset_of!(libc::sockaddr_un, sun_path) } /// Returns a pointer to the raw `sockaddr_un` struct #[inline] @@ -957,12 +987,12 @@ impl SockAddr { }, mem::size_of_val(addr) as libc::socklen_t ), - SockAddr::Unix(UnixAddr { ref sun, path_len }) => ( + SockAddr::Unix(UnixAddr { ref sun, sun_len }) => ( // This cast is always allowed in C unsafe { &*(sun as *const libc::sockaddr_un as *const libc::sockaddr) }, - (path_len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t + sun_len as libc::socklen_t ), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Netlink(NetlinkAddr(ref sa)) => ( diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index dcac2818ed..2ed3827243 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -5,7 +5,7 @@ use cfg_if::cfg_if; use crate::{Result, errno::Errno}; use libc::{self, c_void, c_int, iovec, socklen_t, size_t, CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN}; -use memoffset::offset_of; +use std::convert::TryInto; use std::{mem, ptr, slice}; use std::os::unix::io::RawFd; #[cfg(target_os = "linux")] @@ -1934,10 +1934,10 @@ pub fn sockaddr_storage_to_addr( Ok(SockAddr::Inet(InetAddr::V6(sin6))) } libc::AF_UNIX => { - let pathlen = len - offset_of!(sockaddr_un, sun_path); unsafe { let sun = *(addr as *const _ as *const sockaddr_un); - Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, pathlen))) + let sun_len = len.try_into().unwrap(); + Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len))) } } #[cfg(any(target_os = "android", target_os = "linux"))] From e5af88425160d24a99c8a5cb40b7e6a4712bab0b Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sat, 16 Oct 2021 12:23:42 -0500 Subject: [PATCH 012/358] Recent versions of Android support EPOLLEXCLUSIVE Enable epoll tests on Android, because they are passing. --- CHANGELOG.md | 2 ++ src/sys/epoll.rs | 2 -- test/sys/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 745f6a2e4f..5c4c3eb342 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added fine-grained features flags. Most Nix functionality can now be conditionally enabled. By default, all features are enabled. (#[1611](https://github.com/nix-rust/nix/pull/1611)) +- Added `EPOLLEXCLUSIVE` on Android. + (#[1567](https://github.com/nix-rust/nix/pull/1567)) ### Changed ### Fixed diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 678c27f956..8141ff5cb3 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -18,8 +18,6 @@ libc_bitflags!( EPOLLERR; EPOLLHUP; EPOLLRDHUP; - #[cfg(target_os = "linux")] // Added in 4.5; not in Android. - #[cfg_attr(docsrs, doc(cfg(all())))] EPOLLEXCLUSIVE; #[cfg(not(target_arch = "mips"))] EPOLLWAKEUP; diff --git a/test/sys/mod.rs b/test/sys/mod.rs index e73d9b1dc6..60904bd174 100644 --- a/test/sys/mod.rs +++ b/test/sys/mod.rs @@ -30,7 +30,7 @@ mod test_ioctl; mod test_wait; mod test_uio; -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "android", target_os = "linux"))] mod test_epoll; #[cfg(target_os = "linux")] mod test_inotify; From 11494ecdadaf0a7936a14528f3b291292966b4ef Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Fri, 22 Oct 2021 18:30:56 -0500 Subject: [PATCH 013/358] Add fdatasync for missing platforms --- CHANGELOG.md | 2 ++ src/unistd.rs | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c4c3eb342..319e19adbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1611](https://github.com/nix-rust/nix/pull/1611)) - Added `EPOLLEXCLUSIVE` on Android. (#[1567](https://github.com/nix-rust/nix/pull/1567)) +- Added `fdatasync` for FreeBSD, Fuchsia, NetBSD, and OpenBSD. + (#[1581](https://github.com/nix-rust/nix/pull/1581)) ### Changed ### Fixed diff --git a/src/unistd.rs b/src/unistd.rs index 0e7f94e0fa..01f35215a4 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -1323,11 +1323,13 @@ pub fn fsync(fd: RawFd) -> Result<()> { /// /// See also /// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html) -// `fdatasync(2) is in POSIX, but in libc it is only defined in `libc::notbsd`. -// TODO: exclude only Apple systems after https://github.com/rust-lang/libc/pull/211 #[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "netbsd", + target_os = "openbsd", target_os = "illumos", target_os = "solaris"))] #[inline] From 329f661d1e4fdbcd7b0f632c32050d1c58e1eac6 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Wed, 22 Dec 2021 13:30:14 -0600 Subject: [PATCH 014/358] Fix clippy warning on latest nightly --- src/sys/aio.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sys/aio.rs b/src/sys/aio.rs index 856becb8e1..4780cdee33 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -1065,6 +1065,7 @@ impl<'a> LioCbBuilder<'a> { /// /// [`LioCb`]: struct.LioCb.html /// [`AioCb::from_slice`]: struct.AioCb.html#method.from_slice + #[must_use] pub fn emplace_slice(mut self, fd: RawFd, offs: off_t, buf: &'a [u8], prio: libc::c_int, sigev_notify: SigevNotify, opcode: LioOpcode) -> Self @@ -1081,6 +1082,7 @@ impl<'a> LioCbBuilder<'a> { /// /// [`LioCb`]: struct.LioCb.html /// [`AioCb::from_mut_slice`]: struct.AioCb.html#method.from_mut_slice + #[must_use] pub fn emplace_mut_slice(mut self, fd: RawFd, offs: off_t, buf: &'a mut [u8], prio: libc::c_int, sigev_notify: SigevNotify, opcode: LioOpcode) From 1fbdd29d45757360ad4c12663374879ac1f1a9bd Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Wed, 22 Sep 2021 14:48:12 -0500 Subject: [PATCH 015/358] Enable sched_get/setaffinity on DragonFly BSD --- CHANGELOG.md | 2 + src/sched.rs | 119 ++++++++++++++++++++++++++++----------------------- test/test.rs | 1 + 3 files changed, 68 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 319e19adbe..c1f06dd648 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1567](https://github.com/nix-rust/nix/pull/1567)) - Added `fdatasync` for FreeBSD, Fuchsia, NetBSD, and OpenBSD. (#[1581](https://github.com/nix-rust/nix/pull/1581)) +- Added `sched_setaffinity` and `sched_getaffinity` on DragonFly. + (#[1537](https://github.com/nix-rust/nix/pull/1537)) ### Changed ### Fixed diff --git a/src/sched.rs b/src/sched.rs index e888045c6e..e736f8d249 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -87,6 +87,71 @@ mod sched_linux_like { /// Type for the function executed by [`clone`]. pub type CloneCb<'a> = Box isize + 'a>; + /// `clone` create a child process + /// ([`clone(2)`](https://man7.org/linux/man-pages/man2/clone.2.html)) + /// + /// `stack` is a reference to an array which will hold the stack of the new + /// process. Unlike when calling `clone(2)` from C, the provided stack + /// address need not be the highest address of the region. Nix will take + /// care of that requirement. The user only needs to provide a reference to + /// a normally allocated buffer. + pub fn clone( + mut cb: CloneCb, + stack: &mut [u8], + flags: CloneFlags, + signal: Option, + ) -> Result { + extern "C" fn callback(data: *mut CloneCb) -> c_int { + let cb: &mut CloneCb = unsafe { &mut *data }; + (*cb)() as c_int + } + + let res = unsafe { + let combined = flags.bits() | signal.unwrap_or(0); + let ptr = stack.as_mut_ptr().add(stack.len()); + let ptr_aligned = ptr.sub(ptr as usize % 16); + libc::clone( + mem::transmute( + callback as extern "C" fn(*mut Box isize>) -> i32, + ), + ptr_aligned as *mut c_void, + combined, + &mut cb as *mut _ as *mut c_void, + ) + }; + + 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()) }; + + Errno::result(res).map(drop) + } +} + +#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "linux"))] +pub use self::sched_affinity::*; + +#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "linux"))] +mod sched_affinity { + use crate::errno::Errno; + use std::mem; + use crate::unistd::Pid; + use crate::Result; + /// CpuSet represent a bit-mask of CPUs. /// CpuSets are used by sched_setaffinity and /// sched_getaffinity for example. @@ -217,60 +282,6 @@ mod sched_linux_like { Errno::result(res).and(Ok(cpuset)) } - - /// `clone` create a child process - /// ([`clone(2)`](https://man7.org/linux/man-pages/man2/clone.2.html)) - /// - /// `stack` is a reference to an array which will hold the stack of the new - /// process. Unlike when calling `clone(2)` from C, the provided stack - /// address need not be the highest address of the region. Nix will take - /// care of that requirement. The user only needs to provide a reference to - /// a normally allocated buffer. - pub fn clone( - mut cb: CloneCb, - stack: &mut [u8], - flags: CloneFlags, - signal: Option, - ) -> Result { - extern "C" fn callback(data: *mut CloneCb) -> c_int { - let cb: &mut CloneCb = unsafe { &mut *data }; - (*cb)() as c_int - } - - let res = unsafe { - let combined = flags.bits() | signal.unwrap_or(0); - let ptr = stack.as_mut_ptr().add(stack.len()); - let ptr_aligned = ptr.sub(ptr as usize % 16); - libc::clone( - mem::transmute( - callback as extern "C" fn(*mut Box isize>) -> i32, - ), - ptr_aligned as *mut c_void, - combined, - &mut cb as *mut _ as *mut c_void, - ) - }; - - 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()) }; - - Errno::result(res).map(drop) - } } /// Explicitly yield the processor to other threads. diff --git a/test/test.rs b/test/test.rs index aade937ab9..922caa5f63 100644 --- a/test/test.rs +++ b/test/test.rs @@ -29,6 +29,7 @@ mod test_poll; #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] mod test_pty; #[cfg(any(target_os = "android", + target_os = "dragonfly", target_os = "linux"))] mod test_sched; #[cfg(any(target_os = "android", From 9aa61ef9758474b886b82999e4dfe8cc9a0b03ac Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Wed, 29 Sep 2021 11:32:03 +0800 Subject: [PATCH 016/358] feat: Add glibc::SOF_TIMESTAMPING_* support --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 51 ++++++++++++++++++++++++++++++++++ src/sys/socket/sockopt.rs | 11 ++++++-- test/sys/test_socket.rs | 58 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63bb744098..37e81a706c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1581](https://github.com/nix-rust/nix/pull/1581)) - Added `sched_setaffinity` and `sched_getaffinity` on DragonFly. (#[1537](https://github.com/nix-rust/nix/pull/1537)) +- Added the `SO_TIMESTAMPING` support + (#[1547](https://github.com/nix-rust/nix/pull/1547)) ### Changed ### Fixed diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index dcac2818ed..9df5ed4a9b 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -198,6 +198,28 @@ pub enum SockProtocol { NetlinkCrypto = libc::NETLINK_CRYPTO, } +#[cfg(any(target_os = "linux"))] +libc_bitflags! { + /// Configuration flags for `SO_TIMESTAMPING` interface + /// + /// For use with [`Timestamping`][sockopt::Timestamping]. + /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) + pub struct TimestampingFlag: c_uint { + /// Report any software timestamps when available. + SOF_TIMESTAMPING_SOFTWARE; + /// Report hardware timestamps as generated by SOF_TIMESTAMPING_TX_HARDWARE when available. + SOF_TIMESTAMPING_RAW_HARDWARE; + /// Collect transmiting timestamps as reported by hardware + SOF_TIMESTAMPING_TX_HARDWARE; + /// Collect transmiting timestamps as reported by software + SOF_TIMESTAMPING_TX_SOFTWARE; + /// Collect receiving timestamps as reported by hardware + SOF_TIMESTAMPING_RX_HARDWARE; + /// Collect receiving timestamps as reported by software + SOF_TIMESTAMPING_RX_SOFTWARE; + } +} + libc_bitflags!{ /// Additional socket options pub struct SockFlag: c_int { @@ -641,6 +663,11 @@ pub enum ControlMessageOwned { /// # } /// ``` ScmTimestamp(TimeVal), + /// A set of nanosecond resolution timestamps + /// + /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) + #[cfg(all(target_os = "linux"))] + ScmTimestampsns(Timestamps), /// Nanoseconds resolution timestamp /// /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) @@ -732,6 +759,18 @@ pub enum ControlMessageOwned { Unknown(UnknownCmsg), } +/// For representing packet timestamps via `SO_TIMESTAMPING` interface +#[cfg(all(target_os = "linux"))] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct Timestamps { + /// software based timestamp, usually one containing data + pub system: TimeSpec, + /// legacy timestamp, usually empty + pub hw_trans: TimeSpec, + /// hardware based timestamp + pub hw_raw: TimeSpec, +} + impl ControlMessageOwned { /// Decodes a `ControlMessageOwned` from raw bytes. /// @@ -776,6 +815,18 @@ impl ControlMessageOwned { let ts: libc::timespec = ptr::read_unaligned(p as *const _); ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts)) } + #[cfg(all(target_os = "linux"))] + (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => { + let tp = p as *const libc::timespec; + let ts: libc::timespec = ptr::read_unaligned(tp); + let system = TimeSpec::from(ts); + let ts: libc::timespec = ptr::read_unaligned(tp.add(1)); + let hw_trans = TimeSpec::from(ts); + let ts: libc::timespec = ptr::read_unaligned(tp.add(2)); + let hw_raw = TimeSpec::from(ts); + let timestamping = Timestamps { system, hw_trans, hw_raw }; + ControlMessageOwned::ScmTimestampsns(timestamping) + } #[cfg(any( target_os = "android", target_os = "freebsd", diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 3ad139ad22..056ded429e 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -16,7 +16,7 @@ use std::os::unix::ffi::OsStrExt; // Constants // TCP_CA_NAME_MAX isn't defined in user space include files -#[cfg(any(target_os = "freebsd", target_os = "linux"))] +#[cfg(any(target_os = "freebsd", target_os = "linux"))] #[cfg(feature = "net")] const TCP_CA_NAME_MAX: usize = 16; @@ -465,7 +465,12 @@ sockopt_impl!( #[allow(missing_docs)] // Not documented by Linux! Ip6tOriginalDst, GetOnly, libc::SOL_IPV6, libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6); -sockopt_impl!( +#[cfg(any(target_os = "linux"))] +sockopt_impl!( + /// Specifies exact type of timestamping information collected by the kernel + /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) + Timestamping, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPING, super::TimestampingFlag); +sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. ReceiveTimestamp, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool); #[cfg(all(target_os = "linux"))] @@ -502,7 +507,7 @@ sockopt_impl!( /// Enable or disable the receiving of the `SCM_CREDENTIALS` control /// message. PassCred, Both, libc::SOL_SOCKET, libc::SO_PASSCRED, bool); -#[cfg(any(target_os = "freebsd", target_os = "linux"))] +#[cfg(any(target_os = "freebsd", target_os = "linux"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 0f6fac6664..7a861abfdd 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -57,6 +57,64 @@ pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() { assert_eq!(from_storage, sockaddr); } +#[cfg(any(target_os = "linux"))] +#[cfg_attr(qemu, ignore)] +#[test] +pub fn test_timestamping() { + use nix::sys::socket::{ + recvmsg, sendmsg, setsockopt, socket, sockopt::Timestamping, ControlMessageOwned, MsgFlags, + SockFlag, SockType, TimestampingFlag, + }; + use nix::sys::uio::IoVec; + + let std_sa = SocketAddr::from_str("127.0.0.1:6790").unwrap(); + let inet_addr = InetAddr::from_std(&std_sa); + let sock_addr = SockAddr::new_inet(inet_addr); + + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + nix::sys::socket::bind(rsock, &sock_addr).unwrap(); + + setsockopt(rsock, Timestamping, &TimestampingFlag::all()).unwrap(); + + let sbuf = [0u8; 2048]; + let mut rbuf = [0u8; 2048]; + let flags = MsgFlags::empty(); + let iov1 = [IoVec::from_slice(&sbuf)]; + let iov2 = [IoVec::from_mut_slice(&mut rbuf)]; + let mut cmsg = cmsg_space!(nix::sys::socket::Timestamps); + sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); + let recv = recvmsg(rsock, &iov2, Some(&mut cmsg), flags).unwrap(); + + let mut ts = None; + for c in recv.cmsgs() { + if let ControlMessageOwned::ScmTimestampsns(timestamps) = c { + ts = Some(timestamps.system); + } + } + let ts = ts.expect("ScmTimestampns is present"); + let sys_time = ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME).unwrap(); + let diff = if ts > sys_time { + ts - sys_time + } else { + sys_time - ts + }; + assert!(std::time::Duration::from(diff).as_secs() < 60); +} + #[test] pub fn test_inetv6_addr_to_sock_addr() { let port: u16 = 3000; From a0e2f199f5c9031f28c0174e43e21276bd595808 Mon Sep 17 00:00:00 2001 From: Sachin Cherian Date: Fri, 24 Dec 2021 11:23:52 +0530 Subject: [PATCH 017/358] Add NetBSD configuration for supported process resources --- src/sys/resource.rs | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/sys/resource.rs b/src/sys/resource.rs index 80473e583c..7f2927b4a0 100644 --- a/src/sys/resource.rs +++ b/src/sys/resource.rs @@ -24,12 +24,15 @@ cfg_if! { } libc_enum! { + /// Types of process resources. + /// /// The Resource enum is platform dependent. Check different platform - /// manuals for more details. Some platform links has been provided for - /// earier reference (non-exhaustive). + /// manuals for more details. Some platform links have been provided for + /// easier reference (non-exhaustive). /// /// * [Linux](https://man7.org/linux/man-pages/man2/getrlimit.2.html) /// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=setrlimit) + /// * [NetBSD](https://man.netbsd.org/setrlimit.2) // linux-gnu uses u_int as resource enum, which is implemented in libc as // well. @@ -49,11 +52,7 @@ libc_enum! { ), repr(i32))] #[non_exhaustive] pub enum Resource { - #[cfg(not(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" - )))] + #[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum amount (in bytes) of virtual memory the process is /// allowed to map. @@ -83,7 +82,13 @@ libc_enum! { /// this process may establish. RLIMIT_LOCKS, - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))] + #[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "openbsd", + target_os = "linux", + target_os = "netbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum size (in bytes) which a process may lock into memory /// using the mlock(2) system call. @@ -101,7 +106,13 @@ libc_enum! { /// setpriority or nice. RLIMIT_NICE, - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))] + #[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", + target_os = "linux", + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum number of simultaneous processes for this user id. RLIMIT_NPROC, @@ -112,7 +123,12 @@ libc_enum! { /// create. RLIMIT_NPTS, - #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))] + #[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", + target_os = "linux", + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// When there is memory pressure and swap is available, prioritize /// eviction of a process' resident pages beyond this amount (in bytes). From 9fe943218106636c15a968f105feb0c4dbd69f06 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Fri, 24 Dec 2021 21:47:39 -0600 Subject: [PATCH 018/358] Disable mknod and mknodat tests on DragonFly --- test/test_stat.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/test_stat.rs b/test/test_stat.rs index 33cf748da3..8baa6555b6 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -308,7 +308,8 @@ fn test_mkdirat_fail() { } #[test] -#[cfg(not(any(target_os = "freebsd", +#[cfg(not(any(target_os = "dragonfly", + target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "redox")))] @@ -325,7 +326,8 @@ fn test_mknod() { } #[test] -#[cfg(not(any(target_os = "freebsd", +#[cfg(not(any(target_os = "dragonfly", + target_os = "freebsd", target_os = "illumos", target_os = "ios", target_os = "macos", From 57f41a8898e80f220d231136e26193db77388c03 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 26 Dec 2021 20:14:50 -0600 Subject: [PATCH 019/358] Fix typos --- src/poll.rs | 4 ++-- src/pty.rs | 4 ++-- src/sys/signal.rs | 2 +- src/sys/statfs.rs | 4 ++-- src/time.rs | 2 +- src/unistd.rs | 6 +++--- test/sys/test_ptrace.rs | 2 +- test/sys/test_sockopt.rs | 2 +- test/test_mount.rs | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/poll.rs b/src/poll.rs index 5b1815264d..6d332b0350 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -10,7 +10,7 @@ use crate::errno::Errno; /// [`ppoll`](fn.ppoll.html) functions to specify the events of interest /// for a specific file descriptor. /// -/// After a call to `poll` or `ppoll`, the events that occured can be +/// After a call to `poll` or `ppoll`, the events that occurred can be /// retrieved by calling [`revents()`](#method.revents) on the `PollFd`. #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -31,7 +31,7 @@ impl PollFd { } } - /// Returns the events that occured in the last call to `poll` or `ppoll`. Will only return + /// Returns the events that occurred in the last call to `poll` or `ppoll`. Will only return /// `None` if the kernel provides status flags that Nix does not know about. pub fn revents(self) -> Option { PollFlags::from_bits(self.pollfd.revents) diff --git a/src/pty.rs b/src/pty.rs index a104a69c90..ae304d83d3 100644 --- a/src/pty.rs +++ b/src/pty.rs @@ -112,7 +112,7 @@ pub fn grantpt(fd: &PtyMaster) -> Result<()> { /// Open a pseudoterminal device (see /// [`posix_openpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html)) /// -/// `posix_openpt()` returns a file descriptor to an existing unused pseuterminal master device. +/// `posix_openpt()` returns a file descriptor to an existing unused pseudoterminal master device. /// /// # Examples /// @@ -214,7 +214,7 @@ pub fn ptsname_r(fd: &PtyMaster) -> Result { /// /// `unlockpt()` unlocks the slave pseudoterminal device corresponding to the master pseudoterminal /// referred to by `fd`. This must be called before trying to open the slave side of a -/// pseuoterminal. +/// pseudoterminal. #[inline] pub fn unlockpt(fd: &PtyMaster) -> Result<()> { if unsafe { libc::unlockpt(fd.as_raw_fd()) } < 0 { diff --git a/src/sys/signal.rs b/src/sys/signal.rs index f85bf26611..b655604dd4 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -866,7 +866,7 @@ pub fn pthread_sigmask(how: SigmaskHow, /// Examine and change blocked signals. /// -/// For more informations see the [`sigprocmask` man +/// For more information see the [`sigprocmask` man /// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html). pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> { if set.is_none() && oldset.is_none() { diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index bfb94f4866..622734753a 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -536,7 +536,7 @@ impl Debug for Statfs { /// Describes a mounted file system. /// -/// The result is OS-dependent. For a portabable alternative, see +/// The result is OS-dependent. For a portable alternative, see /// [`statvfs`](crate::sys::statvfs::statvfs). /// /// # Arguments @@ -552,7 +552,7 @@ pub fn statfs(path: &P) -> Result { /// Describes a mounted file system. /// -/// The result is OS-dependent. For a portabable alternative, see +/// The result is OS-dependent. For a portable alternative, see /// [`fstatvfs`](crate::sys::statvfs::fstatvfs). /// /// # Arguments diff --git a/src/time.rs b/src/time.rs index 959769f41e..01a8fd0024 100644 --- a/src/time.rs +++ b/src/time.rs @@ -14,7 +14,7 @@ use std::mem::MaybeUninit; /// Clock identifier /// -/// Newtype pattern around `clockid_t` (which is just alias). It pervents bugs caused by +/// Newtype pattern around `clockid_t` (which is just alias). It prevents bugs caused by /// accidentally passing wrong value. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct ClockId(clockid_t); diff --git a/src/unistd.rs b/src/unistd.rs index 01f35215a4..7aa1cffe39 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -204,8 +204,8 @@ impl ForkResult { /// Create a new child process duplicating the parent process ([see /// fork(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)). /// -/// After calling the fork system call (successfully) two processes will -/// be created that are identical with the exception of their pid and the +/// After successfully calling the fork system call, a second process will +/// be created which is identical to the original except for the pid and the /// return value of this function. As an example: /// /// ``` @@ -225,7 +225,7 @@ impl ForkResult { /// } /// ``` /// -/// This will print something like the following (order indeterministic). The +/// This will print something like the following (order nondeterministic). The /// thing to note is that you end up with two processes continuing execution /// immediately after the fork call but with different match arms. /// diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs index 83fff9a5b4..89c4e2ddad 100644 --- a/test/sys/test_ptrace.rs +++ b/test/sys/test_ptrace.rs @@ -72,7 +72,7 @@ fn test_ptrace_cont() { let _m = crate::FORK_MTX.lock(); // FIXME: qemu-user doesn't implement ptrace on all architectures - // and retunrs ENOSYS in this case. + // and returns ENOSYS in this case. // We (ab)use this behavior to detect the affected platforms // and skip the test then. // On valid platforms the ptrace call should return Errno::EPERM, this diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 01920fd40a..59b97c8b7a 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -122,7 +122,7 @@ fn test_so_tcp_maxseg() { } // The CI doesn't supported getsockopt and setsockopt on emulated processors. -// It's beleived that a QEMU issue, the tests run ok on a fully emulated system. +// It's believed that a QEMU issue, the tests run ok on a fully emulated system. // Current CI just run the binary with QEMU but the Kernel remains the same as the host. // So the syscall doesn't work properly unless the kernel is also emulated. #[test] diff --git a/test/test_mount.rs b/test/test_mount.rs index 44287f975f..1ddfcfe932 100644 --- a/test/test_mount.rs +++ b/test/test_mount.rs @@ -1,6 +1,6 @@ mod common; -// Impelmentation note: to allow unprivileged users to run it, this test makes +// Implementation note: to allow unprivileged users to run it, this test makes // use of user and mount namespaces. On systems that allow unprivileged user // namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run // without root. From 1eeccb942e9cde89d96a927c2a19622b213e4bfd Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Mon, 27 Dec 2021 02:50:55 -0600 Subject: [PATCH 020/358] Add posix_fallocate on DragonFly --- CHANGELOG.md | 2 ++ src/fcntl.rs | 1 + test/test_fcntl.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd0d9e1227..6b3075073f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1581](https://github.com/nix-rust/nix/pull/1581)) - Added `sched_setaffinity` and `sched_getaffinity` on DragonFly. (#[1537](https://github.com/nix-rust/nix/pull/1537)) +- Added `posix_fallocate` on DragonFly. + (#[1621](https://github.com/nix-rust/nix/pull/1621)) - Added the `SO_TIMESTAMPING` support (#[1547](https://github.com/nix-rust/nix/pull/1547)) diff --git a/src/fcntl.rs b/src/fcntl.rs index 74d9eb9c38..c02a81a9a6 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -749,6 +749,7 @@ mod posix_fadvise { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "emscripten", target_os = "fuchsia", any(target_os = "wasi", target_env = "wasi"), diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index db2acfbf52..b24a49eef5 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -488,6 +488,7 @@ mod test_posix_fadvise { #[cfg(any(target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "emscripten", target_os = "fuchsia", any(target_os = "wasi", target_env = "wasi"), From 80f447b2ac9accf3b2c341f1ab7f84a8b03b50e0 Mon Sep 17 00:00:00 2001 From: fpagliughi Date: Sun, 26 Dec 2021 12:43:01 -0500 Subject: [PATCH 021/358] Added getters for the MqAttr struct --- CHANGELOG.md | 2 ++ src/mqueue.rs | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd0d9e1227..96a1ce0e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1537](https://github.com/nix-rust/nix/pull/1537)) - Added the `SO_TIMESTAMPING` support (#[1547](https://github.com/nix-rust/nix/pull/1547)) +- Added getter methods to `MqAttr` struct + (#[1619](https://github.com/nix-rust/nix/pull/1619)) ### Changed ### Fixed diff --git a/src/mqueue.rs b/src/mqueue.rs index 564df4e40d..20740b54f9 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -64,6 +64,21 @@ impl MqAttr { pub const fn flags(&self) -> mq_attr_member_t { self.mq_attr.mq_flags } + + /// The max number of messages that can be held by the queue + pub const fn maxmsg(&self) -> mq_attr_member_t { + self.mq_attr.mq_maxmsg + } + + /// The maximum size of each message (in bytes) + pub const fn msgsize(&self) -> mq_attr_member_t { + self.mq_attr.mq_msgsize + } + + /// The number of messages currently held in the queue + pub const fn curmsgs(&self) -> mq_attr_member_t { + self.mq_attr.mq_curmsgs + } } From a9829853df9192048be39cb9593206b8492748f6 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Wed, 25 Aug 2021 14:31:57 +0100 Subject: [PATCH 022/358] Add support for the SO_TXTIME sockopt and SCM_TXTIME control message --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 22 +++++++++++++++ src/sys/socket/sockopt.rs | 5 ++++ test/sys/test_socket.rs | 57 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23c5c0887c..4c4516ae0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1547](https://github.com/nix-rust/nix/pull/1547)) - Added getter methods to `MqAttr` struct (#[1619](https://github.com/nix-rust/nix/pull/1619)) +- Added the `TxTime` sockopt and control message. + (#[1564](https://github.com/nix-rust/nix/pull/1564)) ### Changed ### Fixed diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 9df5ed4a9b..f6d37c99e9 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1056,6 +1056,14 @@ pub enum ControlMessage<'a> { #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] RxqOvfl(&'a u32), + + /// Configure the transmission time of packets. + /// + /// For further information, please refer to the + /// [`tc-etf(8)`](https://man7.org/linux/man-pages/man8/tc-etf.8.html) man + /// page. + #[cfg(target_os = "linux")] + TxTime(&'a u64), } // An opaque structure used to prevent cmsghdr from being a public type @@ -1153,6 +1161,10 @@ impl<'a> ControlMessage<'a> { ControlMessage::RxqOvfl(drop_count) => { drop_count as *const _ as *const u8 }, + #[cfg(target_os = "linux")] + ControlMessage::TxTime(tx_time) => { + tx_time as *const _ as *const u8 + }, }; unsafe { ptr::copy_nonoverlapping( @@ -1208,6 +1220,10 @@ impl<'a> ControlMessage<'a> { ControlMessage::RxqOvfl(drop_count) => { mem::size_of_val(drop_count) }, + #[cfg(target_os = "linux")] + ControlMessage::TxTime(tx_time) => { + mem::size_of_val(tx_time) + }, } } @@ -1237,6 +1253,8 @@ impl<'a> ControlMessage<'a> { ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6, #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET, + #[cfg(target_os = "linux")] + ControlMessage::TxTime(_) => libc::SOL_SOCKET, } } @@ -1279,6 +1297,10 @@ impl<'a> ControlMessage<'a> { ControlMessage::RxqOvfl(_) => { libc::SO_RXQ_OVFL }, + #[cfg(target_os = "linux")] + ControlMessage::TxTime(_) => { + libc::SCM_TXTIME + }, } } diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 056ded429e..c600391c64 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -582,6 +582,11 @@ sockopt_impl!( #[allow(missing_docs)] // Not documented by Linux! UdpGroSegment, Both, libc::IPPROTO_UDP, libc::UDP_GRO, bool); +#[cfg(target_os = "linux")] +sockopt_impl!( + /// Configures the behavior of time-based transmission of packets, for use + /// with the `TxTime` control message. + TxTime, Both, libc::SOL_SOCKET, libc::SO_TXTIME, libc::sock_txtime); #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] sockopt_impl!( /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 7a861abfdd..5262d3b813 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1997,3 +1997,60 @@ mod linux_errqueue { assert_eq!(ext_err.ee_info, 0); } } + +// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack +// of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] +#[cfg(target_os = "linux")] +#[test] +pub fn test_txtime() { + use nix::sys::socket::{ + bind, recvmsg, sendmsg, setsockopt, socket, sockopt, ControlMessage, + MsgFlags, SockFlag, SockType, + }; + use nix::sys::time::TimeValLike; + use nix::time::{ClockId, clock_gettime}; + + require_kernel_version!(test_txtime, ">= 5.8"); + + let std_sa = SocketAddr::from_str("127.0.0.1:6790").unwrap(); + let inet_addr = InetAddr::from_std(&std_sa); + let sock_addr = SockAddr::new_inet(inet_addr); + + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + + let txtime_cfg = libc::sock_txtime { + clockid: libc::CLOCK_MONOTONIC, + flags: 0, + }; + setsockopt(ssock, sockopt::TxTime, &txtime_cfg).unwrap(); + + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + bind(rsock, &sock_addr).unwrap(); + + let sbuf = [0u8; 2048]; + let iov1 = [nix::sys::uio::IoVec::from_slice(&sbuf)]; + + let now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap(); + let delay = std::time::Duration::from_secs(1).into(); + let txtime = (now + delay).num_nanoseconds() as u64; + + let cmsg = ControlMessage::TxTime(&txtime); + sendmsg(ssock, &iov1, &[cmsg], MsgFlags::empty(), Some(&sock_addr)).unwrap(); + + let mut rbuf = [0u8; 2048]; + let iov2 = [nix::sys::uio::IoVec::from_mut_slice(&mut rbuf)]; + recvmsg(rsock, &iov2, None, MsgFlags::empty()).unwrap(); +} From d74bbe6539670bfadb35def25a43d0f34c2a32e4 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Thu, 30 Dec 2021 20:57:20 -0600 Subject: [PATCH 023/358] Remove cc dependency on DragonFly f5ee22db489f78b9c003ef60b7ad1b837503bc4a removed the need for this dependency. --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 03941aa5f1..6550db11c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,9 +76,6 @@ uio = [] users = ["features"] zerocopy = ["fs", "uio"] -[target.'cfg(target_os = "dragonfly")'.build-dependencies] -cc = "1" - [dev-dependencies] assert-impl = "0.1" lazy_static = "1.2" From f7b62f607cb336a24153c8f46d837681e49197e8 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 21 Dec 2021 18:48:28 -0700 Subject: [PATCH 024/358] Optimize UnixAddr for the BSDs On BSD-derived operating systems, struct sockaddr has a sa_len field that holds the length of the structure. UnixAddr's path_len field is redundant. Remove path_len on BSD-derived OSes, retaining it only for Illumos and Linux-based OSes. Also, ensure that two UnixAddrs compare equal if they differ only by the presence of a trailing NUL. On Linux, syscalls like getsockname add a trailing NUL to the sockaddr they return, even if no NUL was present on the sockaddr originally passed to the kernel via a syscall like bind, and even though the docs explicitly say that any NUL passed to bind is not considered to be part of the address. Work around this bug by stripping it in UnixAddrKind::get(), so that at least two UnixAddrs will compare identical even if they differ in the presence of a trailing NUL. --- src/sys/socket/addr.rs | 75 ++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 0b7932ca13..67e5d6c64f 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1,4 +1,5 @@ use super::sa_family_t; +use cfg_if::cfg_if; use crate::{Result, NixPath}; use crate::errno::Errno; use memoffset::offset_of; @@ -580,7 +581,13 @@ pub struct UnixAddr { sun: libc::sockaddr_un, /// The length of the valid part of `sun`, including the sun_family field /// but excluding any trailing nul. - sun_len: u8, + // On the BSDs, this field is built into sun + #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + sun_len: u8 } // linux man page unix(7) says there are 3 kinds of unix socket: @@ -611,7 +618,18 @@ impl<'a> UnixAddrKind<'a> { return Self::Abstract(name); } let pathname = slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len); - Self::Pathname(Path::new(OsStr::from_bytes(pathname))) + if pathname.last() == Some(&0) { + // A trailing NUL is not considered part of the path, and it does + // not need to be included in the addrlen passed to functions like + // bind(). However, Linux adds a trailing NUL, even if one was not + // originally present, when returning addrs from functions like + // getsockname() (the BSDs do not do that). So we need to filter + // out any trailing NUL here, so sockaddrs can round-trip through + // the kernel and still compare equal. + Self::Pathname(Path::new(OsStr::from_bytes(&pathname[0..pathname.len() - 1]))) + } else { + Self::Pathname(Path::new(OsStr::from_bytes(pathname))) + } } } @@ -640,7 +658,6 @@ impl UnixAddr { target_os = "ios", target_os = "macos", target_os = "netbsd", - target_os = "illumos", target_os = "openbsd"))] { ret.sun_len = sun_len; @@ -657,7 +674,7 @@ impl UnixAddr { /// Create a new `sockaddr_un` representing an address in the "abstract namespace". /// /// The leading nul byte for the abstract namespace is automatically added; - /// thus the input `path` is expected to be the bare name, not null-prefixed. + /// thus the input `path` is expected to be the bare name, not NUL-prefixed. /// This is a Linux-specific extension, primarily used to allow chrooted /// processes to communicate with processes having a different filesystem view. #[cfg(any(target_os = "android", target_os = "linux"))] @@ -699,23 +716,24 @@ impl UnixAddr { /// - if this is a unix addr with a pathname, sun.sun_path is a /// fs path, not necessarily nul-terminated. pub(crate) unsafe fn from_raw_parts(sun: libc::sockaddr_un, sun_len: u8) -> UnixAddr { - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] - { - assert_eq!(sun_len, sun.sun_len); + cfg_if!{ + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + { + UnixAddr { sun, sun_len } + } else { + assert_eq!(sun_len, sun.sun_len); + UnixAddr {sun} + } } - - UnixAddr { sun, sun_len } } fn kind(&self) -> UnixAddrKind<'_> { // SAFETY: our sockaddr is always valid because of the invariant on the struct - unsafe { UnixAddrKind::get(&self.sun, self.sun_len) } + unsafe { UnixAddrKind::get(&self.sun, self.sun_len()) } } /// If this address represents a filesystem path, return that path. @@ -729,7 +747,7 @@ impl UnixAddr { /// If this address represents an abstract socket, return its name. /// /// For abstract sockets only the bare name is returned, without the - /// leading null byte. `None` is returned for unnamed or path-backed sockets. + /// leading NUL byte. `None` is returned for unnamed or path-backed sockets. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn as_abstract(&self) -> Option<&[u8]> { @@ -742,7 +760,7 @@ impl UnixAddr { /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)` #[inline] pub fn path_len(&self) -> usize { - self.sun_len as usize - offset_of!(libc::sockaddr_un, sun_path) + self.sun_len() as usize - offset_of!(libc::sockaddr_un, sun_path) } /// Returns a pointer to the raw `sockaddr_un` struct #[inline] @@ -754,6 +772,21 @@ impl UnixAddr { pub fn as_mut_ptr(&mut self) -> *mut libc::sockaddr_un { &mut self.sun } + + fn sun_len(&self)-> u8 { + cfg_if!{ + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + { + self.sun_len + } else { + self.sun.sun_len + } + } + } } #[cfg(any(target_os = "android", target_os = "linux"))] @@ -987,12 +1020,12 @@ impl SockAddr { }, mem::size_of_val(addr) as libc::socklen_t ), - SockAddr::Unix(UnixAddr { ref sun, sun_len }) => ( + SockAddr::Unix(ref unix_addr) => ( // This cast is always allowed in C unsafe { - &*(sun as *const libc::sockaddr_un as *const libc::sockaddr) + &*(&unix_addr.sun as *const libc::sockaddr_un as *const libc::sockaddr) }, - sun_len as libc::socklen_t + unix_addr.sun_len() as libc::socklen_t ), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Netlink(NetlinkAddr(ref sa)) => ( From 77febe0e6b4e144992ea1b26ae1b9b45b746d970 Mon Sep 17 00:00:00 2001 From: "Brian L. Troutwine" Date: Mon, 27 Dec 2021 15:37:30 -0800 Subject: [PATCH 025/358] Introduce timer_* support This commit adds support for the signal timer mechanism in POSIX, the mirror to timerfd on Linux. Resolves #1424 Signed-off-by: Brian L. Troutwine --- CHANGELOG.md | 2 + src/sys/mod.rs | 15 ++++ src/sys/signal.rs | 5 ++ src/sys/time.rs | 123 +++++++++++++++++++++++++++++++ src/sys/timer.rs | 175 +++++++++++++++++++++++++++++++++++++++++++++ src/sys/timerfd.rs | 111 +++------------------------- test/test.rs | 11 +++ test/test_timer.rs | 91 +++++++++++++++++++++++ 8 files changed, 432 insertions(+), 101 deletions(-) create mode 100644 src/sys/timer.rs create mode 100644 test/test_timer.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c4516ae0a..3b097d6a11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1619](https://github.com/nix-rust/nix/pull/1619)) - Added the `TxTime` sockopt and control message. (#[1564](https://github.com/nix-rust/nix/pull/1564)) +- Added POSIX per-process timer support + (#[1622](https://github.com/nix-rust/nix/pull/1622)) ### Changed ### Fixed diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 16ba9e0ab8..654a4d87bf 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -201,3 +201,18 @@ feature! { #[allow(missing_docs)] pub mod timerfd; } + +#[cfg(all( + any( + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd" + ), + feature = "time", + feature = "signal" +))] +feature! { + #![feature = "time"] + pub mod timer; +} diff --git a/src/sys/signal.rs b/src/sys/signal.rs index b655604dd4..9750d89080 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -1085,6 +1085,11 @@ mod sigevent { pub fn sigevent(&self) -> libc::sigevent { self.sigevent } + + /// Returns a mutable pointer to the `sigevent` wrapped by `self` + pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent { + &mut self.sigevent + } } impl<'a> From<&'a libc::sigevent> for SigEvent { diff --git a/src/sys/time.rs b/src/sys/time.rs index ac4247180d..1e62b76a90 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -5,6 +5,129 @@ use libc::{timespec, timeval}; #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 pub use libc::{time_t, suseconds_t}; +#[cfg(any( + all(feature = "time", any(target_os = "android", target_os = "linux")), + all( + any( + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd" + ), + feature = "time", + feature = "signal" + ) +))] +pub(crate) mod timer { + use crate::sys::time::TimeSpec; + use bitflags::bitflags; + + #[derive(Debug, Clone, Copy)] + pub(crate) struct TimerSpec(libc::itimerspec); + + impl TimerSpec { + pub const fn none() -> Self { + Self(libc::itimerspec { + it_interval: libc::timespec { + tv_sec: 0, + tv_nsec: 0, + }, + it_value: libc::timespec { + tv_sec: 0, + tv_nsec: 0, + }, + }) + } + } + + impl AsMut for TimerSpec { + fn as_mut(&mut self) -> &mut libc::itimerspec { + &mut self.0 + } + } + + impl AsRef for TimerSpec { + fn as_ref(&self) -> &libc::itimerspec { + &self.0 + } + } + + impl From for TimerSpec { + fn from(expiration: Expiration) -> TimerSpec { + match expiration { + Expiration::OneShot(t) => TimerSpec(libc::itimerspec { + it_interval: libc::timespec { + tv_sec: 0, + tv_nsec: 0, + }, + it_value: *t.as_ref(), + }), + Expiration::IntervalDelayed(start, interval) => TimerSpec(libc::itimerspec { + it_interval: *interval.as_ref(), + it_value: *start.as_ref(), + }), + Expiration::Interval(t) => TimerSpec(libc::itimerspec { + it_interval: *t.as_ref(), + it_value: *t.as_ref(), + }), + } + } + } + + /// An enumeration allowing the definition of the expiration time of an alarm, + /// recurring or not. + #[derive(Debug, Clone, Copy, PartialEq)] + pub enum Expiration { + /// Alarm will trigger once after the time given in `TimeSpec` + OneShot(TimeSpec), + /// Alarm will trigger after a specified delay and then every interval of + /// time. + IntervalDelayed(TimeSpec, TimeSpec), + /// Alarm will trigger every specified interval of time. + Interval(TimeSpec), + } + + #[cfg(any(target_os = "android", target_os = "linux"))] + bitflags! { + /// Flags that are used for arming the timer. + pub struct TimerSetTimeFlags: libc::c_int { + const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME; + } + } + #[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "dragonfly", target_os = "illumos"))] + bitflags! { + /// Flags that are used for arming the timer. + pub struct TimerSetTimeFlags: libc::c_int { + const TFD_TIMER_ABSTIME = libc::TIMER_ABSTIME; + } + } + + impl From for Expiration { + fn from(timerspec: TimerSpec) -> Expiration { + match timerspec { + TimerSpec(libc::itimerspec { + it_interval: + libc::timespec { + tv_sec: 0, + tv_nsec: 0, + }, + it_value: ts, + }) => Expiration::OneShot(ts.into()), + TimerSpec(libc::itimerspec { + it_interval: int_ts, + it_value: val_ts, + }) => { + if (int_ts.tv_sec == val_ts.tv_sec) && (int_ts.tv_nsec == val_ts.tv_nsec) { + Expiration::Interval(int_ts.into()) + } else { + Expiration::IntervalDelayed(val_ts.into(), int_ts.into()) + } + } + } + } + } +} + pub trait TimeValLike: Sized { #[inline] fn zero() -> Self { diff --git a/src/sys/timer.rs b/src/sys/timer.rs new file mode 100644 index 0000000000..349346bb10 --- /dev/null +++ b/src/sys/timer.rs @@ -0,0 +1,175 @@ +//! Timer API via signals. +//! +//! Timer is a POSIX API to create timers and get expiration notifications +//! through queued Unix signals, for the current process. This is similar to +//! Linux's timerfd mechanism, except that API is specific to Linux and makes +//! use of file polling. +//! +//! For more documentation, please read [timer_create](https://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_create.html). +//! +//! # Examples +//! +//! Create an interval timer that signals SIGALARM every 250 milliseconds. +//! +//! ```no_run +//! use nix::sys::signal::{self, SigEvent, SigHandler, SigevNotify, Signal}; +//! use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; +//! use nix::time::ClockId; +//! use std::convert::TryFrom; +//! use std::sync::atomic::{AtomicU64, Ordering}; +//! use std::thread::yield_now; +//! use std::time::Duration; +//! +//! const SIG: Signal = Signal::SIGALRM; +//! static ALARMS: AtomicU64 = AtomicU64::new(0); +//! +//! extern "C" fn handle_alarm(signal: libc::c_int) { +//! let signal = Signal::try_from(signal).unwrap(); +//! if signal == SIG { +//! ALARMS.fetch_add(1, Ordering::Relaxed); +//! } +//! } +//! +//! fn main() { +//! let clockid = ClockId::CLOCK_MONOTONIC; +//! let sigevent = SigEvent::new(SigevNotify::SigevSignal { +//! signal: SIG, +//! si_value: 0, +//! }); +//! +//! let mut timer = Timer::new(clockid, sigevent).unwrap(); +//! let expiration = Expiration::Interval(Duration::from_millis(250).into()); +//! let flags = TimerSetTimeFlags::empty(); +//! timer.set(expiration, flags).expect("could not set timer"); +//! +//! let handler = SigHandler::Handler(handle_alarm); +//! unsafe { signal::signal(SIG, handler) }.unwrap(); +//! +//! loop { +//! let alarms = ALARMS.load(Ordering::Relaxed); +//! if alarms >= 10 { +//! println!("total alarms handled: {}", alarms); +//! break; +//! } +//! yield_now() +//! } +//! } +//! ``` +use crate::sys::signal::SigEvent; +use crate::sys::time::timer::TimerSpec; +pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags}; +use crate::time::ClockId; +use crate::{errno::Errno, Result}; +use core::mem; + +/// A Unix signal per-process timer. +#[derive(Debug)] +#[repr(transparent)] +pub struct Timer(libc::timer_t); + +impl Timer { + /// Creates a new timer based on the clock defined by `clockid`. The details + /// of the signal and its handler are defined by the passed `sigevent`. + pub fn new(clockid: ClockId, mut sigevent: SigEvent) -> Result { + let mut timer_id: mem::MaybeUninit = mem::MaybeUninit::uninit(); + Errno::result(unsafe { + libc::timer_create( + clockid.as_raw(), + sigevent.as_mut_ptr(), + timer_id.as_mut_ptr(), + ) + }) + .map(|_| { + // SAFETY: libc::timer_create is responsible for initializing + // timer_id. + unsafe { Self(timer_id.assume_init()) } + }) + } + + /// Set a new alarm on the timer. + /// + /// # Types of alarm + /// + /// There are 3 types of alarms you can set: + /// + /// - one shot: the alarm will trigger once after the specified amount of + /// time. + /// Example: I want an alarm to go off in 60s and then disable itself. + /// + /// - interval: the alarm will trigger every specified interval of time. + /// Example: I want an alarm to go off every 60s. The alarm will first + /// go off 60s after I set it and every 60s after that. The alarm will + /// not disable itself. + /// + /// - interval delayed: the alarm will trigger after a certain amount of + /// time and then trigger at a specified interval. + /// Example: I want an alarm to go off every 60s but only start in 1h. + /// The alarm will first trigger 1h after I set it and then every 60s + /// after that. The alarm will not disable itself. + /// + /// # Relative vs absolute alarm + /// + /// If you do not set any `TimerSetTimeFlags`, then the `TimeSpec` you pass + /// to the `Expiration` you want is relative. If however you want an alarm + /// to go off at a certain point in time, you can set `TFD_TIMER_ABSTIME`. + /// Then the one shot TimeSpec and the delay TimeSpec of the delayed + /// interval are going to be interpreted as absolute. + /// + /// # Disabling alarms + /// + /// Note: Only one alarm can be set for any given timer. Setting a new alarm + /// actually removes the previous one. + /// + /// Note: Setting a one shot alarm with a 0s TimeSpec disable the alarm + /// altogether. + pub fn set(&mut self, expiration: Expiration, flags: TimerSetTimeFlags) -> Result<()> { + let timerspec: TimerSpec = expiration.into(); + Errno::result(unsafe { + libc::timer_settime( + self.0, + flags.bits(), + timerspec.as_ref(), + core::ptr::null_mut(), + ) + }) + .map(drop) + } + + /// Get the parameters for the alarm currently set, if any. + pub fn get(&self) -> Result> { + let mut timerspec = TimerSpec::none(); + Errno::result(unsafe { libc::timer_gettime(self.0, timerspec.as_mut()) }).map(|_| { + if timerspec.as_ref().it_interval.tv_sec == 0 + && timerspec.as_ref().it_interval.tv_nsec == 0 + && timerspec.as_ref().it_value.tv_sec == 0 + && timerspec.as_ref().it_value.tv_nsec == 0 + { + None + } else { + Some(timerspec.into()) + } + }) + } + + /// Return the number of timers that have overrun + /// + /// Each timer is able to queue one signal to the process at a time, meaning + /// if the signal is not handled before the next expiration the timer has + /// 'overrun'. This function returns how many times that has happened to + /// this timer, up to `libc::DELAYTIMER_MAX`. If more than the maximum + /// number of overruns have happened the return is capped to the maximum. + pub fn overruns(&self) -> i32 { + unsafe { libc::timer_getoverrun(self.0) } + } +} + +impl Drop for Timer { + fn drop(&mut self) { + if !std::thread::panicking() { + let result = Errno::result(unsafe { libc::timer_delete(self.0) }); + if let Err(Errno::EINVAL) = result { + panic!("close of Timer encountered EINVAL"); + } + } + } +} diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs index 705a3c4d65..bc5a75d4ce 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -28,10 +28,10 @@ //! // We wait for the timer to expire. //! timer.wait().unwrap(); //! ``` -use crate::sys::time::TimeSpec; +use crate::sys::time::timer::TimerSpec; +pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags}; use crate::unistd::read; use crate::{errno::Errno, Result}; -use bitflags::bitflags; use libc::c_int; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; @@ -77,93 +77,6 @@ libc_bitflags! { } } -bitflags! { - /// Flags that are used for arming the timer. - pub struct TimerSetTimeFlags: libc::c_int { - const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME; - } -} - -#[derive(Debug, Clone, Copy)] -struct TimerSpec(libc::itimerspec); - -impl TimerSpec { - pub const fn none() -> Self { - Self(libc::itimerspec { - it_interval: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, - it_value: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, - }) - } -} - -impl AsRef for TimerSpec { - fn as_ref(&self) -> &libc::itimerspec { - &self.0 - } -} - -impl From for TimerSpec { - fn from(expiration: Expiration) -> TimerSpec { - match expiration { - Expiration::OneShot(t) => TimerSpec(libc::itimerspec { - it_interval: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, - it_value: *t.as_ref(), - }), - Expiration::IntervalDelayed(start, interval) => TimerSpec(libc::itimerspec { - it_interval: *interval.as_ref(), - it_value: *start.as_ref(), - }), - Expiration::Interval(t) => TimerSpec(libc::itimerspec { - it_interval: *t.as_ref(), - it_value: *t.as_ref(), - }), - } - } -} - -impl From for Expiration { - fn from(timerspec: TimerSpec) -> Expiration { - match timerspec { - TimerSpec(libc::itimerspec { - it_interval: - libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, - it_value: ts, - }) => Expiration::OneShot(ts.into()), - TimerSpec(libc::itimerspec { - it_interval: int_ts, - it_value: val_ts, - }) => { - if (int_ts.tv_sec == val_ts.tv_sec) && (int_ts.tv_nsec == val_ts.tv_nsec) { - Expiration::Interval(int_ts.into()) - } else { - Expiration::IntervalDelayed(val_ts.into(), int_ts.into()) - } - } - } - } -} - -/// An enumeration allowing the definition of the expiration time of an alarm, -/// recurring or not. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum Expiration { - OneShot(TimeSpec), - IntervalDelayed(TimeSpec, TimeSpec), - Interval(TimeSpec), -} - impl TimerFd { /// Creates a new timer based on the clock defined by `clockid`. The /// underlying fd can be assigned specific flags with `flags` (CLOEXEC, @@ -181,7 +94,7 @@ impl TimerFd { /// /// - one shot: the alarm will trigger once after the specified amount of /// time. - /// Example: I want an alarm to go off in 60s and then disables itself. + /// Example: I want an alarm to go off in 60s and then disable itself. /// /// - interval: the alarm will trigger every specified interval of time. /// Example: I want an alarm to go off every 60s. The alarm will first @@ -225,13 +138,11 @@ impl TimerFd { /// Get the parameters for the alarm currently set, if any. pub fn get(&self) -> Result> { let mut timerspec = TimerSpec::none(); - let timerspec_ptr: *mut libc::itimerspec = &mut timerspec.0; - - Errno::result(unsafe { libc::timerfd_gettime(self.fd, timerspec_ptr) }).map(|_| { - if timerspec.0.it_interval.tv_sec == 0 - && timerspec.0.it_interval.tv_nsec == 0 - && timerspec.0.it_value.tv_sec == 0 - && timerspec.0.it_value.tv_nsec == 0 + Errno::result(unsafe { libc::timerfd_gettime(self.fd, timerspec.as_mut()) }).map(|_| { + if timerspec.as_ref().it_interval.tv_sec == 0 + && timerspec.as_ref().it_interval.tv_nsec == 0 + && timerspec.as_ref().it_value.tv_sec == 0 + && timerspec.as_ref().it_value.tv_nsec == 0 { None } else { @@ -259,7 +170,7 @@ impl TimerFd { pub fn wait(&self) -> Result<()> { while let Err(e) = read(self.fd, &mut [0u8; 8]) { if e != Errno::EINTR { - return Err(e) + return Err(e); } } @@ -270,9 +181,7 @@ impl TimerFd { impl Drop for TimerFd { fn drop(&mut self) { if !std::thread::panicking() { - let result = Errno::result(unsafe { - libc::close(self.fd) - }); + let result = Errno::result(unsafe { libc::close(self.fd) }); if let Err(Errno::EBADF) = result { panic!("close of TimerFd encountered EBADF"); } diff --git a/test/test.rs b/test/test.rs index 922caa5f63..83cb46450e 100644 --- a/test/test.rs +++ b/test/test.rs @@ -41,6 +41,17 @@ mod test_sendfile; mod test_stat; mod test_time; mod test_unistd; +#[cfg(all( + any( + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd" + ), + feature = "time", + feature = "signal" +))] +mod test_timer; use std::os::unix::io::RawFd; use std::path::PathBuf; diff --git a/test/test_timer.rs b/test/test_timer.rs new file mode 100644 index 0000000000..31a740b0d6 --- /dev/null +++ b/test/test_timer.rs @@ -0,0 +1,91 @@ +use nix::sys::signal::{ + sigaction, SaFlags, SigAction, SigEvent, SigHandler, SigSet, SigevNotify, Signal, +}; +use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; +use nix::time::ClockId; +use std::convert::TryFrom; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::time::{Duration, Instant}; + +const SIG: Signal = Signal::SIGALRM; +static ALARM_CALLED: AtomicBool = AtomicBool::new(false); + +pub extern "C" fn handle_sigalarm(raw_signal: libc::c_int) { + let signal = Signal::try_from(raw_signal).unwrap(); + if signal == SIG { + ALARM_CALLED.store(true, Ordering::Release); + } +} + +#[test] +fn alarm_fires() { + // Avoid interfering with other signal using tests by taking a mutex shared + // among other tests in this crate. + let _m = crate::SIGNAL_MTX.lock(); + + // + // Setup + // + + // Create a handler for the test signal, `SIG`. The handler is responsible + // for flipping `ALARM_CALLED`. + let handler = SigHandler::Handler(handle_sigalarm); + let signal_action = SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); + let old_handler = + unsafe { sigaction(SIG, &signal_action).expect("unable to set signal handler for alarm") }; + + // Create the timer. We use the monotonic clock here, though any would do + // really. The timer is set to fire every 250 milliseconds with no delay for + // the initial firing. + let clockid = ClockId::CLOCK_MONOTONIC; + let sigevent = SigEvent::new(SigevNotify::SigevSignal { + signal: SIG, + si_value: 0, + }); + let mut timer = Timer::new(clockid, sigevent).expect("failed to create timer"); + let expiration = Expiration::Interval(Duration::from_millis(250).into()); + let flags = TimerSetTimeFlags::empty(); + timer.set(expiration, flags).expect("could not set timer"); + + // + // Test + // + + // Determine that there's still an expiration tracked by the + // timer. Depending on when this runs either an `Expiration::Interval` or + // `Expiration::IntervalDelayed` will be present. That is, if the timer has + // not fired yet we'll get our original `expiration`, else the one that + // represents a delay to the next expiration. We're only interested in the + // timer still being extant. + match timer.get() { + Ok(Some(exp)) => { + assert!(matches!( + exp, + Expiration::Interval(..) | Expiration::IntervalDelayed(..) + )) + } + _ => panic!("timer lost its expiration"), + } + + // Wait for 2 firings of the alarm before checking that it has fired and + // been handled at least the once. If we wait for 3 seconds and the handler + // is never called something has gone sideways and the test fails. + let starttime = Instant::now(); + loop { + thread::sleep(Duration::from_millis(500)); + if ALARM_CALLED.load(Ordering::Acquire) { + break; + } + if starttime.elapsed() > Duration::from_secs(3) { + panic!("Timeout waiting for SIGALRM"); + } + } + + // Replace the old signal handler now that we've completed the test. If the + // test fails this process panics, so the fact we might not get here is + // okay. + unsafe { + sigaction(SIG, &old_handler).expect("unable to reset signal handler"); + } +} From 58d7c04dfbba9ebc853b58e6c0890eac68130e47 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Thu, 30 Dec 2021 06:25:24 -0600 Subject: [PATCH 026/358] Fix mq tests on NetBSD and DragonFly NetBSD (and DragonFly, which borrows its implementation) include additional flags beyond O_NONBLOCK in MqAttr, such as the flags passed to mq_open(). --- test/test_mq.rs | 64 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/test/test_mq.rs b/test/test_mq.rs index 430df5ddcc..088ee7e0aa 100644 --- a/test/test_mq.rs +++ b/test/test_mq.rs @@ -1,3 +1,4 @@ +use cfg_if::cfg_if; use std::ffi::CString; use std::str; @@ -6,6 +7,25 @@ use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive, mq_attr_member_t}; use nix::mqueue::{MqAttr, MQ_OFlag}; use nix::sys::stat::Mode; +// Defined as a macro such that the error source is reported as the caller's location. +macro_rules! assert_attr_eq { + ($read_attr:ident, $initial_attr:ident) => { + cfg_if! { + if #[cfg(any(target_os = "dragonfly", target_os = "netbsd"))] { + // NetBSD (and others which inherit its implementation) include other flags + // in read_attr, such as those specified by oflag. Just make sure at least + // the correct bits are set. + assert_eq!($read_attr.flags() & $initial_attr.flags(), $initial_attr.flags()); + assert_eq!($read_attr.maxmsg(), $initial_attr.maxmsg()); + assert_eq!($read_attr.msgsize(), $initial_attr.msgsize()); + assert_eq!($read_attr.curmsgs(), $initial_attr.curmsgs()); + } else { + assert_eq!($read_attr, $initial_attr); + } + } + } +} + #[test] fn test_mq_send_and_receive() { const MSG_SIZE: mq_attr_member_t = 32; @@ -37,7 +57,6 @@ fn test_mq_send_and_receive() { #[test] -#[cfg(not(any(target_os = "netbsd")))] fn test_mq_getattr() { use nix::mqueue::mq_getattr; const MSG_SIZE: mq_attr_member_t = 32; @@ -53,13 +72,12 @@ fn test_mq_getattr() { let mqd = r.unwrap(); let read_attr = mq_getattr(mqd).unwrap(); - assert_eq!(read_attr, initial_attr); + assert_attr_eq!(read_attr, initial_attr); mq_close(mqd).unwrap(); } // FIXME: Fix failures for mips in QEMU #[test] -#[cfg(not(any(target_os = "netbsd")))] #[cfg_attr(all( qemu, any(target_arch = "mips", target_arch = "mips64") @@ -79,28 +97,33 @@ fn test_mq_setattr() { }; let mqd = r.unwrap(); - let new_attr = MqAttr::new(0, 20, MSG_SIZE * 2, 100); + let new_attr = MqAttr::new(0, 20, MSG_SIZE * 2, 100); let old_attr = mq_setattr(mqd, &new_attr).unwrap(); - assert_eq!(old_attr, initial_attr); + assert_attr_eq!(old_attr, initial_attr); - let new_attr_get = mq_getattr(mqd).unwrap(); - // The following tests make sense. No changes here because according to the Linux man page only + // No changes here because according to the Linux man page only // O_NONBLOCK can be set (see tests below) - assert_ne!(new_attr_get, new_attr); + #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] + { + let new_attr_get = mq_getattr(mqd).unwrap(); + assert_ne!(new_attr_get, new_attr); + } - let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t, 10, MSG_SIZE, 0); + let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t, 10, MSG_SIZE, 0); mq_setattr(mqd, &new_attr_non_blocking).unwrap(); let new_attr_get = mq_getattr(mqd).unwrap(); // now the O_NONBLOCK flag has been set - assert_ne!(new_attr_get, initial_attr); - assert_eq!(new_attr_get, new_attr_non_blocking); + #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] + { + assert_ne!(new_attr_get, initial_attr); + } + assert_attr_eq!(new_attr_get, new_attr_non_blocking); mq_close(mqd).unwrap(); } // FIXME: Fix failures for mips in QEMU #[test] -#[cfg(not(any(target_os = "netbsd")))] #[cfg_attr(all( qemu, any(target_arch = "mips", target_arch = "mips64") @@ -121,20 +144,21 @@ fn test_mq_set_nonblocking() { let mqd = r.unwrap(); mq_set_nonblock(mqd).unwrap(); let new_attr = mq_getattr(mqd); - assert_eq!(new_attr.unwrap().flags(), MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t); + let o_nonblock_bits = MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t; + assert_eq!(new_attr.unwrap().flags() & o_nonblock_bits, o_nonblock_bits); mq_remove_nonblock(mqd).unwrap(); let new_attr = mq_getattr(mqd); - assert_eq!(new_attr.unwrap().flags(), 0); + assert_eq!(new_attr.unwrap().flags() & o_nonblock_bits, 0); mq_close(mqd).unwrap(); } #[test] -#[cfg(not(any(target_os = "netbsd")))] fn test_mq_unlink() { use nix::mqueue::mq_unlink; const MSG_SIZE: mq_attr_member_t = 32; let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); + #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] let mq_name_not_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; @@ -148,8 +172,14 @@ fn test_mq_unlink() { let res_unlink = mq_unlink(mq_name_opened); assert_eq!(res_unlink, Ok(()) ); - let res_unlink_not_opened = mq_unlink(mq_name_not_opened); - assert_eq!(res_unlink_not_opened, Err(Errno::ENOENT) ); + // NetBSD (and others which inherit its implementation) defer removing the message + // queue name until all references are closed, whereas Linux and others remove the + // message queue name immediately. + #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] + { + let res_unlink_not_opened = mq_unlink(mq_name_not_opened); + assert_eq!(res_unlink_not_opened, Err(Errno::ENOENT) ); + } mq_close(mqd).unwrap(); let res_unlink_after_close = mq_unlink(mq_name_opened); From e5b9b972b2e61a0bda96f1fadb2fa3b60a4b7690 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 2 Jan 2022 14:36:24 -0700 Subject: [PATCH 027/358] Fix intermittency in test_timer::alarm_fires The test was disabling the signal handler before disabling the timer. Fix intermittent failures by: * Reversing the cleanup order. * Sleeping for a while before removing the signal handler, since POSIX does not guarantee that timer_delete will clear pending signals. Also, speed up the timer to make the test suite complete faster. --- test/test_timer.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/test/test_timer.rs b/test/test_timer.rs index 31a740b0d6..d07d9633d0 100644 --- a/test/test_timer.rs +++ b/test/test_timer.rs @@ -23,6 +23,7 @@ fn alarm_fires() { // Avoid interfering with other signal using tests by taking a mutex shared // among other tests in this crate. let _m = crate::SIGNAL_MTX.lock(); + const TIMER_PERIOD: Duration = Duration::from_millis(100); // // Setup @@ -44,7 +45,7 @@ fn alarm_fires() { si_value: 0, }); let mut timer = Timer::new(clockid, sigevent).expect("failed to create timer"); - let expiration = Expiration::Interval(Duration::from_millis(250).into()); + let expiration = Expiration::Interval(TIMER_PERIOD.into()); let flags = TimerSetTimeFlags::empty(); timer.set(expiration, flags).expect("could not set timer"); @@ -73,7 +74,7 @@ fn alarm_fires() { // is never called something has gone sideways and the test fails. let starttime = Instant::now(); loop { - thread::sleep(Duration::from_millis(500)); + thread::sleep(2 * TIMER_PERIOD); if ALARM_CALLED.load(Ordering::Acquire) { break; } @@ -82,9 +83,16 @@ fn alarm_fires() { } } - // Replace the old signal handler now that we've completed the test. If the - // test fails this process panics, so the fact we might not get here is - // okay. + // Cleanup: + // 1) deregister the OS's timer. + // 2) Wait for a full timer period, since POSIX does not require that + // disabling the timer will clear pending signals, and on NetBSD at least + // it does not. + // 2) Replace the old signal handler now that we've completed the test. If + // the test fails this process panics, so the fact we might not get here + // is okay. + drop(timer); + thread::sleep(TIMER_PERIOD); unsafe { sigaction(SIG, &old_handler).expect("unable to reset signal handler"); } From b7dd35e9b3f128bc8ffebe00d362f7cfa3144309 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 2 Jan 2022 14:12:34 -0600 Subject: [PATCH 028/358] Correct MAP_FIXED documentation for NetBSD The previous documentation described the default behavior, rather than the behavior when the flag was set. Also fix a test which is failing due to passing this flag erroneously. --- src/sys/mman.rs | 2 +- test/sys/test_mman.rs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/sys/mman.rs b/src/sys/mman.rs index 017c3f6e17..7302a65a2f 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -195,7 +195,7 @@ libc_bitflags!{ #[cfg(target_os = "linux")] #[cfg_attr(docsrs, doc(cfg(all())))] MREMAP_FIXED; - /// Permits to use the old and new address as hints to relocate the mapping. + /// Place the mapping at exactly the address specified in `new_address`. #[cfg(target_os = "netbsd")] #[cfg_attr(docsrs, doc(cfg(all())))] MAP_FIXED; diff --git a/test/sys/test_mman.rs b/test/sys/test_mman.rs index a7ceedcbd1..8858375a3c 100644 --- a/test/sys/test_mman.rs +++ b/test/sys/test_mman.rs @@ -73,16 +73,11 @@ fn test_mremap_shrink() { assert_eq !(slice[ONE_K - 1], 0xFF); let slice : &mut[u8] = unsafe { - #[cfg(target_os = "linux")] let mem = mremap(slice.as_mut_ptr() as * mut c_void, 10 * ONE_K, ONE_K, MRemapFlags::empty(), None) .unwrap(); // Since we didn't supply MREMAP_MAYMOVE, the address should be the // same. - #[cfg(target_os = "netbsd")] - let mem = mremap(slice.as_mut_ptr() as * mut c_void, 10 * ONE_K, ONE_K, - MRemapFlags::MAP_FIXED, None) - .unwrap(); assert_eq !(mem, slice.as_mut_ptr() as * mut c_void); std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K) }; From 4d5c090fcf9f6f51d4303e903676f2d487d60272 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Fri, 24 Dec 2021 17:57:20 -0600 Subject: [PATCH 029/358] Add sendfile(2) for DragonFly --- CHANGELOG.md | 2 ++ src/sys/mod.rs | 1 + src/sys/sendfile.rs | 46 +++++++++++++++++++++++++++++++++++++++++- test/test.rs | 1 + test/test_sendfile.rs | 47 ++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 95 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b097d6a11..1235a71e84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1564](https://github.com/nix-rust/nix/pull/1564)) - Added POSIX per-process timer support (#[1622](https://github.com/nix-rust/nix/pull/1622)) +- Added `sendfile` on DragonFly. + (#[1615](https://github.com/nix-rust/nix/pull/1615)) ### Changed ### Fixed diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 654a4d87bf..0bd0bc9f88 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -110,6 +110,7 @@ feature! { } #[cfg(any(target_os = "android", + target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "linux", diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs index 1a87a6800a..5ec0b52679 100644 --- a/src/sys/sendfile.rs +++ b/src/sys/sendfile.rs @@ -64,7 +64,8 @@ pub fn sendfile64( } cfg_if! { - if #[cfg(any(target_os = "freebsd", + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", target_os = "ios", target_os = "macos"))] { use crate::sys::uio::IoVec; @@ -184,6 +185,49 @@ cfg_if! { }; (Errno::result(return_code).and(Ok(())), bytes_sent) } + } else if #[cfg(target_os = "dragonfly")] { + /// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`. + /// + /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if + /// an error occurs. + /// + /// `in_fd` must describe a regular file. `out_sock` must describe a stream socket. + /// + /// If `offset` falls past the end of the file, the function returns success and zero bytes + /// written. + /// + /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of + /// file (EOF). + /// + /// `headers` and `trailers` specify optional slices of byte slices to be sent before and + /// after the data read from `in_fd`, respectively. The length of headers and trailers sent + /// is included in the returned count of bytes written. The values of `offset` and `count` + /// do not apply to headers or trailers. + /// + /// For more information, see + /// [the sendfile(2) man page.](https://leaf.dragonflybsd.org/cgi/web-man?command=sendfile§ion=2) + pub fn sendfile( + in_fd: RawFd, + out_sock: RawFd, + offset: off_t, + count: Option, + headers: Option<&[&[u8]]>, + trailers: Option<&[&[u8]]>, + ) -> (Result<()>, off_t) { + let mut bytes_sent: off_t = 0; + let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); + let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); + let return_code = unsafe { + libc::sendfile(in_fd, + out_sock, + offset, + count.unwrap_or(0), + hdtr_ptr as *mut libc::sf_hdtr, + &mut bytes_sent as *mut off_t, + 0) + }; + (Errno::result(return_code).and(Ok(())), bytes_sent) + } } else if #[cfg(any(target_os = "ios", target_os = "macos"))] { /// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to /// `out_sock`. diff --git a/test/test.rs b/test/test.rs index 83cb46450e..3cac48f77f 100644 --- a/test/test.rs +++ b/test/test.rs @@ -33,6 +33,7 @@ mod test_pty; target_os = "linux"))] mod test_sched; #[cfg(any(target_os = "android", + target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "linux", diff --git a/test/test_sendfile.rs b/test/test_sendfile.rs index b6559d329b..e56ff12faf 100644 --- a/test/test_sendfile.rs +++ b/test/test_sendfile.rs @@ -8,7 +8,7 @@ use tempfile::tempfile; cfg_if! { if #[cfg(any(target_os = "android", target_os = "linux"))] { use nix::unistd::{close, pipe, read}; - } else if #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))] { + } else if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos"))] { use std::net::Shutdown; use std::os::unix::net::UnixStream; } @@ -105,6 +105,51 @@ fn test_sendfile_freebsd() { assert_eq!(expected_string, read_string); } +#[cfg(target_os = "dragonfly")] +#[test] +fn test_sendfile_dragonfly() { + // Declare the content + let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; + let body = "Xabcdef123456"; + let body_offset = 1; + let trailer_strings = vec!["\n", "Served by Make Believe\n"]; + + // Write the body to a file + let mut tmp = tempfile().unwrap(); + tmp.write_all(body.as_bytes()).unwrap(); + + // Prepare headers and trailers for sendfile + let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect(); + let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect(); + + // Prepare socket pair + let (mut rd, wr) = UnixStream::pair().unwrap(); + + // Call the test method + let (res, bytes_written) = sendfile( + tmp.as_raw_fd(), + wr.as_raw_fd(), + body_offset as off_t, + None, + Some(headers.as_slice()), + Some(trailers.as_slice()), + ); + assert!(res.is_ok()); + wr.shutdown(Shutdown::Both).unwrap(); + + // Prepare the expected result + let expected_string = + header_strings.concat() + &body[body_offset..] + &trailer_strings.concat(); + + // Verify the message that was sent + assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); + + let mut read_string = String::new(); + let bytes_read = rd.read_to_string(&mut read_string).unwrap(); + assert_eq!(bytes_written as usize, bytes_read); + assert_eq!(expected_string, read_string); +} + #[cfg(any(target_os = "ios", target_os = "macos"))] #[test] fn test_sendfile_darwin() { From 1b32230831542f060d14b2ad31baf119277f8739 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Mon, 3 Jan 2022 04:25:47 -0600 Subject: [PATCH 030/358] Add getresuid/gid and setresuid/gid on BSDs --- CHANGELOG.md | 2 ++ src/unistd.rs | 26 ++++++++++++++++++++------ test/test_unistd.rs | 12 ++++++++++-- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1235a71e84..48c803b4bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1622](https://github.com/nix-rust/nix/pull/1622)) - Added `sendfile` on DragonFly. (#[1615](https://github.com/nix-rust/nix/pull/1615)) +- Added `getresuid`, `setresuid`, `getresgid`, and `setresgid` on DragonFly, FreeBSD, and OpenBSD. + (#[1628](https://github.com/nix-rust/nix/pull/1628)) ### Changed ### Fixed diff --git a/src/unistd.rs b/src/unistd.rs index 7aa1cffe39..8da4f93238 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -30,11 +30,18 @@ feature! { pub use self::pivot_root::*; } -#[cfg(any(target_os = "android", target_os = "freebsd", - target_os = "linux", target_os = "openbsd"))] +#[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd"))] pub use self::setres::*; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd"))] pub use self::getres::*; feature! { @@ -2691,8 +2698,11 @@ mod pivot_root { } } -#[cfg(any(target_os = "android", target_os = "freebsd", - target_os = "linux", target_os = "openbsd"))] +#[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd"))] mod setres { feature! { #![feature = "users"] @@ -2735,7 +2745,11 @@ mod setres { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd"))] mod getres { feature! { #![feature = "users"] diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 59ab24e462..0f56b929d3 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -621,7 +621,11 @@ fn test_sysconf_unsupported() { } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd"))] #[test] fn test_getresuid() { let resuids = getresuid().unwrap(); @@ -630,7 +634,11 @@ fn test_getresuid() { assert!(resuids.saved.as_raw() != libc::uid_t::max_value()); } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd"))] #[test] fn test_getresgid() { let resgids = getresgid().unwrap(); From ebd4acebc004ac98bba07adb2d009f747552ab4a Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Mon, 10 Jan 2022 21:57:55 -0600 Subject: [PATCH 031/358] Change port used by test_txtime to avoid conflict --- test/sys/test_socket.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 5262d3b813..01f5f87875 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -2013,7 +2013,7 @@ pub fn test_txtime() { require_kernel_version!(test_txtime, ">= 5.8"); - let std_sa = SocketAddr::from_str("127.0.0.1:6790").unwrap(); + let std_sa = SocketAddr::from_str("127.0.0.1:6802").unwrap(); let inet_addr = InetAddr::from_std(&std_sa); let sock_addr = SockAddr::new_inet(inet_addr); From 3674d58b6fb2d1533fa3a5ae2daeb014a6004b75 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 19 Dec 2021 13:34:09 -0600 Subject: [PATCH 032/358] Re-enable deprecation warnings on DragonFly Use latest nightly compiler. --- .cirrus.yml | 29 +++-------------------------- Cargo.lock.msrv | 13 +++---------- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 4e1da038ef..c6f4e0b2d2 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -265,32 +265,6 @@ task: << : *BUILD before_cache_script: rm -rf $CARGO_HOME/registry/index -# DragonflyBSD temporarily needs a pinned nightly toolchain -# rustc is broken on DragonflyBSD as of Dec-5, probably by -# https://github.com/rust-lang/rust/commit/e68887e67cc6b7bb4ea5113a40eaa4c0831bda13 -task: - container: - image: rust:1.46 - name: DragonFly BSD x86_64 - env: - BUILD: check - ZFLAGS: -Zbuild-std - TARGET: x86_64-unknown-dragonfly - # Redox requires a nightly compiler. - # If stuff breaks, change nightly to the date at - # https://gitlab.redox-os.org/redox-os/redox/-/blob/master/rust-toolchain - TOOLCHAIN: nightly-2021-12-04 - # Temporarily allow deprecation on DragonflyBSD until an alternative is - # available. - #https://github.com/rust-lang/libc/pull/2522 - RUSTFLAGS: -D warnings -A deprecated - setup_script: - - rustup toolchain add $TOOLCHAIN --profile minimal - - rustup component add rust-src --toolchain $TOOLCHAIN - - rustup component add clippy --toolchain $TOOLCHAIN - << : *BUILD - before_cache_script: rm -rf $CARGO_HOME/registry/index - # Rust Tier 3 targets can't use Rustup task: container: @@ -300,6 +274,9 @@ task: 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 diff --git a/Cargo.lock.msrv b/Cargo.lock.msrv index 955bccf4b5..a917bb6bb6 100644 --- a/Cargo.lock.msrv +++ b/Cargo.lock.msrv @@ -37,12 +37,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "cc" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1" - [[package]] name = "cfg-if" version = "0.1.2" @@ -104,9 +98,9 @@ checksum = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" [[package]] name = "libc" -version = "0.2.102" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "lock_api" @@ -128,12 +122,11 @@ dependencies = [ [[package]] name = "nix" -version = "0.23.0" +version = "0.23.1" dependencies = [ "assert-impl", "bitflags", "caps", - "cc", "cfg-if 1.0.0", "lazy_static", "libc", From 84e3c56bcc144fb4964caa69fb1dddeccb35be82 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 16 Jan 2022 10:10:13 -0600 Subject: [PATCH 033/358] Remove EventFlag::EV_SYSFLAG It is not stable across OpenBSD versions and is reserved by the system on FreeBSD and NetBSD. --- CHANGELOG.md | 2 ++ Cargo.toml | 2 +- src/sys/event.rs | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48c803b4bc..75fc82def4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Removed public access to the inner fields of `NetlinkAddr`, `AlgAddr`, `SysControlAddr`, `LinkAddr`, and `VsockAddr`. (#[1614](https://github.com/nix-rust/nix/pull/1614)) +- Removed `EventFlag::EV_SYSFLAG`. + (#[1635](https://github.com/nix-rust/nix/pull/1635)) ## [0.23.1] - 2021-12-16 diff --git a/Cargo.toml b/Cargo.toml index 6550db11c3..dbe05683dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.112", features = [ "extra_traits" ] } +libc = { git = "https://github.com/rust-lang/libc", rev = "e470e3b6a1f940e0024d40d3b79fc73fe29c7f17", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" diff --git a/src/sys/event.rs b/src/sys/event.rs index c648f5ebc8..9262accf2c 100644 --- a/src/sys/event.rs +++ b/src/sys/event.rs @@ -114,7 +114,6 @@ libc_bitflags!{ target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] EV_RECEIPT; - EV_SYSFLAGS; } } From 5f0072130e3d5e942601cc06da9934f2e3ab5c07 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Tue, 18 Jan 2022 16:42:52 -0600 Subject: [PATCH 034/358] Add MAP_FIXED_NOREPLACE on Linux --- CHANGELOG.md | 2 ++ src/sys/mman.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75fc82def4..05a28ca412 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1615](https://github.com/nix-rust/nix/pull/1615)) - Added `getresuid`, `setresuid`, `getresgid`, and `setresgid` on DragonFly, FreeBSD, and OpenBSD. (#[1628](https://github.com/nix-rust/nix/pull/1628)) +- Added `MAP_FIXED_NOREPLACE` on Linux. + (#[1636](https://github.com/nix-rust/nix/pull/1636)) ### Changed ### Fixed diff --git a/src/sys/mman.rs b/src/sys/mman.rs index 7302a65a2f..523b468341 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -43,6 +43,10 @@ libc_bitflags!{ MAP_PRIVATE; /// Place the mapping at exactly the address specified in `addr`. MAP_FIXED; + /// Place the mapping at exactly the address specified in `addr`, but never clobber an existing range. + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + MAP_FIXED_NOREPLACE; /// To be used with `MAP_FIXED`, to forbid the system /// to select a different address than the one specified. #[cfg(target_os = "freebsd")] From 65039212d1b1dce51c250ad552a92a7a077c54a8 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Fri, 14 Jan 2022 08:04:52 -0600 Subject: [PATCH 035/358] Define UMOUNT_NOFOLLOW, FUSE_SUPER_MAGIC on Linux Requested-by: jiangliu --- CHANGELOG.md | 2 ++ src/mount/linux.rs | 1 + src/sys/statfs.rs | 3 +++ 3 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75fc82def4..5d84e7eb3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1622](https://github.com/nix-rust/nix/pull/1622)) - Added `sendfile` on DragonFly. (#[1615](https://github.com/nix-rust/nix/pull/1615)) +- Added `UMOUNT_NOFOLLOW`, `FUSE_SUPER_MAGIC` on Linux. + (#[1634](https://github.com/nix-rust/nix/pull/1634)) - Added `getresuid`, `setresuid`, `getresgid`, and `setresgid` on DragonFly, FreeBSD, and OpenBSD. (#[1628](https://github.com/nix-rust/nix/pull/1628)) diff --git a/src/mount/linux.rs b/src/mount/linux.rs index 4cb2fa5490..4c976dcb5a 100644 --- a/src/mount/linux.rs +++ b/src/mount/linux.rs @@ -53,6 +53,7 @@ libc_bitflags!( MNT_FORCE; MNT_DETACH; MNT_EXPIRE; + UMOUNT_NOFOLLOW; } ); diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 622734753a..e46733e703 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -73,6 +73,9 @@ pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC as fs_type_t) 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 FUSE_SUPER_MAGIC: FsType = FsType(libc::FUSE_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)] From 475da53d562293553934d0e579e91f2bf3be30f7 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 22 Jan 2022 14:37:48 -0700 Subject: [PATCH 036/358] Better type safety for mqueue On some platforms, mqd_t is a pointer. That means code like the below can trigger a segfault. Fix it by defining a Newtype around mqd_t that prevents use-after-free and dangling pointer scenarios. ```rust fn invalid_mqd_t() { let mqd: libc::mqd_t = std::ptr::null_mut(); mq_close(mqd).unwrap(); } ``` Also, get test coverage for mqueue in CI on FreeBSD. --- .cirrus.yml | 1 + CHANGELOG.md | 5 ++++ src/mqueue.rs | 70 +++++++++++++++++++++++++++++++++++++------------ test/test_mq.rs | 22 ++++++++-------- 4 files changed, 70 insertions(+), 28 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index c6f4e0b2d2..38416655f2 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -40,6 +40,7 @@ task: freebsd_instance: image: freebsd-12-2-release-amd64 setup_script: + - kldload mqueuefs - fetch https://sh.rustup.rs -o rustup.sh - sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN - . $HOME/.cargo/env diff --git a/CHANGELOG.md b/CHANGELOG.md index 418ea62ef8..1ae85e31a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,11 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1636](https://github.com/nix-rust/nix/pull/1636)) ### Changed + +- `mqueue` functions now operate on a distinct type, `nix::mqueue::MqdT`. + Accessors take this type by reference, not by value. + (#[1639](https://github.com/nix-rust/nix/pull/1639)) + ### Fixed ### Removed diff --git a/src/mqueue.rs b/src/mqueue.rs index 20740b54f9..792a5d2293 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -1,12 +1,40 @@ //! Posix Message Queue functions //! +//! # Example +//! +// no_run because a kernel module may be required. +//! ```no_run +//! # use std::ffi::CString; +//! # use nix::mqueue::*; +//! use nix::sys::stat::Mode; +//! +//! const MSG_SIZE: mq_attr_member_t = 32; +//! let mq_name= CString::new("/a_nix_test_queue").unwrap(); +//! +//! let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; +//! let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; +//! let mqd0 = mq_open(&mq_name, oflag0, mode, None).unwrap(); +//! let msg_to_send = b"msg_1"; +//! mq_send(&mqd0, msg_to_send, 1).unwrap(); +//! +//! let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY; +//! let mqd1 = mq_open(&mq_name, oflag1, mode, None).unwrap(); +//! let mut buf = [0u8; 32]; +//! let mut prio = 0u32; +//! let len = mq_receive(&mqd1, &mut buf, &mut prio).unwrap(); +//! assert_eq!(prio, 1); +//! assert_eq!(msg_to_send, &buf[0..len]); +//! +//! mq_close(mqd1).unwrap(); +//! mq_close(mqd0).unwrap(); +//! ``` //! [Further reading and details on the C API](https://man7.org/linux/man-pages/man7/mq_overview.7.html) use crate::Result; use crate::errno::Errno; use libc::{self, c_char, mqd_t, size_t}; -use std::ffi::CString; +use std::ffi::CStr; use crate::sys::stat::Mode; use std::mem; @@ -34,6 +62,14 @@ pub struct MqAttr { mq_attr: libc::mq_attr, } +/// Identifies an open POSIX Message Queue +// A safer wrapper around libc::mqd_t, which is a pointer on some platforms +// Deliberately is not Clone to prevent use-after-close scenarios +#[repr(transparent)] +#[derive(Debug)] +#[allow(missing_copy_implementations)] +pub struct MqdT(mqd_t); + // x32 compatibility // See https://sourceware.org/bugzilla/show_bug.cgi?id=21279 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] @@ -87,11 +123,11 @@ impl MqAttr { /// See also [`mq_open(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html) // The mode.bits cast is only lossless on some OSes #[allow(clippy::cast_lossless)] -pub fn mq_open(name: &CString, +pub fn mq_open(name: &CStr, oflag: MQ_OFlag, mode: Mode, attr: Option<&MqAttr>) - -> Result { + -> Result { let res = match attr { Some(mq_attr) => unsafe { libc::mq_open(name.as_ptr(), @@ -101,13 +137,13 @@ pub fn mq_open(name: &CString, }, None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) }, }; - Errno::result(res) + Errno::result(res).map(MqdT) } /// Remove a message queue /// /// See also [`mq_unlink(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html) -pub fn mq_unlink(name: &CString) -> Result<()> { +pub fn mq_unlink(name: &CStr) -> Result<()> { let res = unsafe { libc::mq_unlink(name.as_ptr()) }; Errno::result(res).map(drop) } @@ -115,18 +151,18 @@ pub fn mq_unlink(name: &CString) -> Result<()> { /// Close a message queue /// /// See also [`mq_close(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_close.html) -pub fn mq_close(mqdes: mqd_t) -> Result<()> { - let res = unsafe { libc::mq_close(mqdes) }; +pub fn mq_close(mqdes: MqdT) -> Result<()> { + let res = unsafe { libc::mq_close(mqdes.0) }; Errno::result(res).map(drop) } /// Receive a message from a message queue /// /// See also [`mq_receive(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html) -pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Result { +pub fn mq_receive(mqdes: &MqdT, message: &mut [u8], msg_prio: &mut u32) -> Result { let len = message.len() as size_t; let res = unsafe { - libc::mq_receive(mqdes, + libc::mq_receive(mqdes.0, message.as_mut_ptr() as *mut c_char, len, msg_prio as *mut u32) @@ -137,9 +173,9 @@ pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Resul /// Send a message to a message queue /// /// See also [`mq_send(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html) -pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> { +pub fn mq_send(mqdes: &MqdT, message: &[u8], msq_prio: u32) -> Result<()> { let res = unsafe { - libc::mq_send(mqdes, + libc::mq_send(mqdes.0, message.as_ptr() as *const c_char, message.len(), msq_prio) @@ -150,9 +186,9 @@ pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> { /// Get message queue attributes /// /// See also [`mq_getattr(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html) -pub fn mq_getattr(mqd: mqd_t) -> Result { +pub fn mq_getattr(mqd: &MqdT) -> Result { let mut attr = mem::MaybeUninit::::uninit(); - let res = unsafe { libc::mq_getattr(mqd, attr.as_mut_ptr()) }; + let res = unsafe { libc::mq_getattr(mqd.0, attr.as_mut_ptr()) }; Errno::result(res).map(|_| unsafe{MqAttr { mq_attr: attr.assume_init() }}) } @@ -161,10 +197,10 @@ pub fn mq_getattr(mqd: mqd_t) -> Result { /// It is recommend to use the `mq_set_nonblock()` and `mq_remove_nonblock()` convenience functions as they are easier to use /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_setattr.html) -pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result { +pub fn mq_setattr(mqd: &MqdT, newattr: &MqAttr) -> Result { let mut attr = mem::MaybeUninit::::uninit(); let res = unsafe { - libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, attr.as_mut_ptr()) + libc::mq_setattr(mqd.0, &newattr.mq_attr as *const libc::mq_attr, attr.as_mut_ptr()) }; Errno::result(res).map(|_| unsafe{ MqAttr { mq_attr: attr.assume_init() }}) } @@ -173,7 +209,7 @@ pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result { /// Sets the `O_NONBLOCK` attribute for a given message queue descriptor /// Returns the old attributes #[allow(clippy::useless_conversion)] // Not useless on all OSes -pub fn mq_set_nonblock(mqd: mqd_t) -> Result { +pub fn mq_set_nonblock(mqd: &MqdT) -> Result { let oldattr = mq_getattr(mqd)?; let newattr = MqAttr::new(mq_attr_member_t::from(MQ_OFlag::O_NONBLOCK.bits()), oldattr.mq_attr.mq_maxmsg, @@ -185,7 +221,7 @@ pub fn mq_set_nonblock(mqd: mqd_t) -> Result { /// Convenience function. /// Removes `O_NONBLOCK` attribute for a given message queue descriptor /// Returns the old attributes -pub fn mq_remove_nonblock(mqd: mqd_t) -> Result { +pub fn mq_remove_nonblock(mqd: &MqdT) -> Result { let oldattr = mq_getattr(mqd)?; let newattr = MqAttr::new(0, oldattr.mq_attr.mq_maxmsg, diff --git a/test/test_mq.rs b/test/test_mq.rs index 088ee7e0aa..8aff840ddc 100644 --- a/test/test_mq.rs +++ b/test/test_mq.rs @@ -41,13 +41,13 @@ fn test_mq_send_and_receive() { }; let mqd0 = r0.unwrap(); let msg_to_send = "msg_1"; - mq_send(mqd0, msg_to_send.as_bytes(), 1).unwrap(); + mq_send(&mqd0, msg_to_send.as_bytes(), 1).unwrap(); let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY; let mqd1 = mq_open(mq_name, oflag1, mode, Some(&attr)).unwrap(); let mut buf = [0u8; 32]; let mut prio = 0u32; - let len = mq_receive(mqd1, &mut buf, &mut prio).unwrap(); + let len = mq_receive(&mqd1, &mut buf, &mut prio).unwrap(); assert_eq!(prio, 1); mq_close(mqd1).unwrap(); @@ -71,7 +71,7 @@ fn test_mq_getattr() { }; let mqd = r.unwrap(); - let read_attr = mq_getattr(mqd).unwrap(); + let read_attr = mq_getattr(&mqd).unwrap(); assert_attr_eq!(read_attr, initial_attr); mq_close(mqd).unwrap(); } @@ -98,20 +98,20 @@ fn test_mq_setattr() { let mqd = r.unwrap(); let new_attr = MqAttr::new(0, 20, MSG_SIZE * 2, 100); - let old_attr = mq_setattr(mqd, &new_attr).unwrap(); + let old_attr = mq_setattr(&mqd, &new_attr).unwrap(); assert_attr_eq!(old_attr, initial_attr); // No changes here because according to the Linux man page only // O_NONBLOCK can be set (see tests below) #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] { - let new_attr_get = mq_getattr(mqd).unwrap(); + let new_attr_get = mq_getattr(&mqd).unwrap(); assert_ne!(new_attr_get, new_attr); } let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t, 10, MSG_SIZE, 0); - mq_setattr(mqd, &new_attr_non_blocking).unwrap(); - let new_attr_get = mq_getattr(mqd).unwrap(); + mq_setattr(&mqd, &new_attr_non_blocking).unwrap(); + let new_attr_get = mq_getattr(&mqd).unwrap(); // now the O_NONBLOCK flag has been set #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] @@ -142,12 +142,12 @@ fn test_mq_set_nonblocking() { return; }; let mqd = r.unwrap(); - mq_set_nonblock(mqd).unwrap(); - let new_attr = mq_getattr(mqd); + mq_set_nonblock(&mqd).unwrap(); + let new_attr = mq_getattr(&mqd); let o_nonblock_bits = MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t; assert_eq!(new_attr.unwrap().flags() & o_nonblock_bits, o_nonblock_bits); - mq_remove_nonblock(mqd).unwrap(); - let new_attr = mq_getattr(mqd); + mq_remove_nonblock(&mqd).unwrap(); + let new_attr = mq_getattr(&mqd); assert_eq!(new_attr.unwrap().flags() & o_nonblock_bits, 0); mq_close(mqd).unwrap(); } From 91049bc03be6a15f10f898fee89ad03a05bb886d Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 22 Jan 2022 14:46:07 -0700 Subject: [PATCH 037/358] Suppress clippy::not_unsafe_ptr_arg_deref warnings in ptrace on BSD Technically these functions don't violate Rust's safety rules, because libc::ptrace doesn't dereference those pointer args. Instead, it passes them directly to the kernel. --- src/sys/ptrace/bsd.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sys/ptrace/bsd.rs b/src/sys/ptrace/bsd.rs index ac7d83126c..c4cc740396 100644 --- a/src/sys/ptrace/bsd.rs +++ b/src/sys/ptrace/bsd.rs @@ -167,6 +167,9 @@ pub fn step>>(pid: Pid, sig: T) -> Result<()> { } /// Reads a word from a processes memory at the given address +// Technically, ptrace doesn't dereference the pointer. It passes it directly +// to the kernel. +#[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn read(pid: Pid, addr: AddressType) -> Result { unsafe { // Traditionally there was a difference between reading data or @@ -176,6 +179,9 @@ pub fn read(pid: Pid, addr: AddressType) -> Result { } /// Writes a word into the processes memory at the given address +// Technically, ptrace doesn't dereference the pointer. It passes it directly +// to the kernel. +#[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> { unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(drop) } } From 5419c79601a17be2264f430d56b6c5cd91a18fcc Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 22 Jan 2022 15:43:00 -0700 Subject: [PATCH 038/358] Add fspacectl on FreeBSD --- CHANGELOG.md | 2 + Cargo.toml | 2 +- src/fcntl.rs | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ae85e31a6..523bf30419 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1628](https://github.com/nix-rust/nix/pull/1628)) - Added `MAP_FIXED_NOREPLACE` on Linux. (#[1636](https://github.com/nix-rust/nix/pull/1636)) +- Added `fspacectl` on FreeBSD + (#[1640](https://github.com/nix-rust/nix/pull/1640)) ### Changed diff --git a/Cargo.toml b/Cargo.toml index dbe05683dd..c0cd0d5348 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { git = "https://github.com/rust-lang/libc", rev = "e470e3b6a1f940e0024d40d3b79fc73fe29c7f17", features = [ "extra_traits" ] } +libc = { git = "https://github.com/rust-lang/libc", rev = "7600416f1ca896b501d58b0f44f1869d566359d6", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" diff --git a/src/fcntl.rs b/src/fcntl.rs index c02a81a9a6..99a473d369 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -697,6 +697,139 @@ pub fn fallocate( Errno::result(res).map(drop) } +/// Argument to [`fspacectl`] describing the range to zero. The first member is +/// the file offset, and the second is the length of the region. +#[cfg(any(target_os = "freebsd"))] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct SpacectlRange(pub libc::off_t, pub libc::off_t); + +#[cfg(any(target_os = "freebsd"))] +impl SpacectlRange { + #[inline] + pub fn is_empty(&self) -> bool { + self.1 == 0 + } + + #[inline] + pub fn len(&self) -> libc::off_t { + self.1 + } + + #[inline] + pub fn offset(&self) -> libc::off_t { + self.0 + } +} + +/// Punch holes in a file. +/// +/// `fspacectl` instructs the file system to deallocate a portion of a file. +/// After a successful operation, this region of the file will return all zeroes +/// if read. If the file system supports deallocation, then it may free the +/// underlying storage, too. +/// +/// # Arguments +/// +/// - `fd` - File to operate on +/// - `range.0` - File offset at which to begin deallocation +/// - `range.1` - Length of the region to deallocate +/// +/// # Returns +/// +/// The operation may deallocate less than the entire requested region. On +/// success, it returns the region that still remains to be deallocated. The +/// caller should loop until the returned region is empty. +/// +/// # Example +/// +/// ``` +/// # use std::io::Write; +/// # use std::os::unix::fs::FileExt; +/// # use std::os::unix::io::AsRawFd; +/// # use nix::fcntl::*; +/// # use tempfile::tempfile; +/// const INITIAL: &[u8] = b"0123456789abcdef"; +/// let mut f = tempfile().unwrap(); +/// f.write_all(INITIAL).unwrap(); +/// let mut range = SpacectlRange(3, 6); +/// while (!range.is_empty()) { +/// let r = fspacectl(f.as_raw_fd(), range); +/// # if r == Err(nix::Error::ENOSYS) { +/// # // not supported until FreeBSD 14.0 +/// # return; +/// # } +/// range = r.unwrap(); +/// } +/// let mut buf = vec![0; INITIAL.len()]; +/// f.read_exact_at(&mut buf, 0).unwrap(); +/// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); +/// ``` +#[cfg(target_os = "freebsd")] +pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result { + let mut rqsr = libc::spacectl_range{r_offset: range.0, r_len: range.1}; + let res = unsafe { libc::fspacectl( + fd, + libc::SPACECTL_DEALLOC, // Only one command is supported ATM + &rqsr, + 0, // No flags are currently supported + &mut rqsr + )}; + Errno::result(res).map(|_| SpacectlRange(rqsr.r_offset, rqsr.r_len)) +} + +/// Like [`fspacectl`], but will never return incomplete. +/// +/// # Arguments +/// +/// - `fd` - File to operate on +/// - `offset` - File offset at which to begin deallocation +/// - `len` - Length of the region to deallocate +/// +/// # Returns +/// +/// Returns `()` on success. On failure, the region may or may not be partially +/// deallocated. +/// +/// # Example +/// +/// ``` +/// # use std::io::Write; +/// # use std::os::unix::fs::FileExt; +/// # use std::os::unix::io::AsRawFd; +/// # use nix::fcntl::*; +/// # use tempfile::tempfile; +/// const INITIAL: &[u8] = b"0123456789abcdef"; +/// let mut f = tempfile().unwrap(); +/// f.write_all(INITIAL).unwrap(); +/// let r = fspacectl_all(f.as_raw_fd(), 3, 6); +/// # if r == Err(nix::Error::ENOSYS) { +/// # // not supported until FreeBSD 14.0 +/// # return; +/// # } +/// r.unwrap(); +/// let mut buf = vec![0; INITIAL.len()]; +/// f.read_exact_at(&mut buf, 0).unwrap(); +/// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); +/// ``` +#[cfg(target_os = "freebsd")] +pub fn fspacectl_all(fd: RawFd, offset: libc::off_t, len: libc::off_t) + -> Result<()> +{ + let mut rqsr = libc::spacectl_range{r_offset: offset, r_len: len}; + while rqsr.r_len > 0 { + let res = unsafe { libc::fspacectl( + fd, + libc::SPACECTL_DEALLOC, // Only one command is supported ATM + &rqsr, + 0, // No flags are currently supported + &mut rqsr + )}; + if let Err(e) = Errno::result(res) { + return Err(e); + } + } + Ok(()) +} #[cfg(any( target_os = "linux", From e2ce5efece04811d96336a9f896bbe7d50e6af86 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 23 Jan 2022 08:37:56 -0700 Subject: [PATCH 039/358] Disable the fspacectl tests They fail to link prior to FreeBSD 14.0, which we don't use in CI. So mark them as no_run. The only alternative I see would be to add a build script. --- src/fcntl.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/fcntl.rs b/src/fcntl.rs index 99a473d369..6c713608ee 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -742,7 +742,8 @@ impl SpacectlRange { /// /// # Example /// -/// ``` +// no_run because it fails to link until FreeBSD 14.0 +/// ```no_run /// # use std::io::Write; /// # use std::os::unix::fs::FileExt; /// # use std::os::unix::io::AsRawFd; @@ -753,12 +754,7 @@ impl SpacectlRange { /// f.write_all(INITIAL).unwrap(); /// let mut range = SpacectlRange(3, 6); /// while (!range.is_empty()) { -/// let r = fspacectl(f.as_raw_fd(), range); -/// # if r == Err(nix::Error::ENOSYS) { -/// # // not supported until FreeBSD 14.0 -/// # return; -/// # } -/// range = r.unwrap(); +/// range = fspacectl(f.as_raw_fd(), range).unwrap(); /// } /// let mut buf = vec![0; INITIAL.len()]; /// f.read_exact_at(&mut buf, 0).unwrap(); @@ -792,7 +788,8 @@ pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result { /// /// # Example /// -/// ``` +// no_run because it fails to link until FreeBSD 14.0 +/// ```no_run /// # use std::io::Write; /// # use std::os::unix::fs::FileExt; /// # use std::os::unix::io::AsRawFd; @@ -801,12 +798,7 @@ pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result { /// const INITIAL: &[u8] = b"0123456789abcdef"; /// let mut f = tempfile().unwrap(); /// f.write_all(INITIAL).unwrap(); -/// let r = fspacectl_all(f.as_raw_fd(), 3, 6); -/// # if r == Err(nix::Error::ENOSYS) { -/// # // not supported until FreeBSD 14.0 -/// # return; -/// # } -/// r.unwrap(); +/// fspacectl_all(f.as_raw_fd(), 3, 6).unwrap(); /// let mut buf = vec![0; INITIAL.len()]; /// f.read_exact_at(&mut buf, 0).unwrap(); /// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); From ad7e3c719ce43e0210e71763109c42383ee5aa33 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 23 Jan 2022 13:20:19 -0600 Subject: [PATCH 040/358] InetAddr::from_std should set sin_len/sin6_len on the BSDs --- CHANGELOG.md | 4 ++++ src/sys/socket/addr.rs | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 523bf30419..39bceab7b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1639](https://github.com/nix-rust/nix/pull/1639)) ### Fixed + +- `InetAddr::from_std` now sets the `sin_len`/`sin6_len` fields on the BSDs. + (#[1642](https://github.com/nix-rust/nix/pull/1642)) + ### Removed - Removed public access to the inner fields of `NetlinkAddr`, `AlgAddr`, diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 67e5d6c64f..4517c5489f 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -330,6 +330,11 @@ impl InetAddr { match *std { net::SocketAddr::V4(ref addr) => { InetAddr::V4(libc::sockaddr_in { + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "haiku", target_os = "hermit", + target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd"))] + sin_len: mem::size_of::() as u8, sin_family: AddressFamily::Inet as sa_family_t, sin_port: addr.port().to_be(), // network byte order sin_addr: Ipv4Addr::from_std(addr.ip()).0, @@ -338,6 +343,11 @@ impl InetAddr { } net::SocketAddr::V6(ref addr) => { InetAddr::V6(libc::sockaddr_in6 { + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "haiku", target_os = "hermit", + target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd"))] + sin6_len: mem::size_of::() as u8, sin6_family: AddressFamily::Inet6 as sa_family_t, sin6_port: addr.port().to_be(), // network byte order sin6_addr: Ipv6Addr::from_std(addr.ip()).0, From 50d22ce0e535bc840a067e3b6faa3fd409445fce Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 23 Jan 2022 14:52:02 -0600 Subject: [PATCH 041/358] Make memoffset dependency optional Only the socket feature depends on memoffset. Allow clients to skip pulling memoffset in as a dependency if they don't need it. --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c0cd0d5348..5cdf95c5c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ bitflags = "1.1" cfg-if = "1.0" [target.'cfg(not(target_os = "redox"))'.dependencies] -memoffset = "0.6.3" +memoffset = { version = "0.6.3", optional = true } [features] default = [ @@ -68,7 +68,7 @@ reboot = [] resource = [] sched = ["process"] signal = ["process"] -socket = [] +socket = ["memoffset"] term = [] time = [] ucontext = ["signal"] From 6c4b9133f14d4488dc1b86411568b49e99fbe629 Mon Sep 17 00:00:00 2001 From: Jonah Petri Date: Tue, 7 Dec 2021 16:57:52 -0500 Subject: [PATCH 042/358] uclibc support --- .cirrus.yml | 3 +++ README.md | 1 + bors.toml | 1 + src/sys/mod.rs | 2 +- src/sys/personality.rs | 4 ++-- src/sys/ptrace/linux.rs | 7 ++++--- src/sys/resource.rs | 10 +++++----- src/sys/signal.rs | 16 ++++++++++++---- src/sys/socket/addr.rs | 4 ++-- src/sys/statfs.rs | 34 +++++++++++++++++++++++++++++----- src/sys/uio.rs | 8 ++++++-- src/time.rs | 1 - test/sys/mod.rs | 2 +- test/sys/test_aio_drop.rs | 1 + test/sys/test_uio.rs | 2 +- test/test_fcntl.rs | 5 +++++ 16 files changed, 74 insertions(+), 27 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 38416655f2..3207b70419 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -281,6 +281,9 @@ task: - name: OpenBSD x86_64 env: TARGET: x86_64-unknown-openbsd + - name: Linux armv7 uclibceabihf + env: + TARGET: armv7-unknown-linux-uclibceabihf setup_script: - rustup component add rust-src << : *BUILD diff --git a/README.md b/README.md index a8759f1ce8..3a38f4e5bb 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ Tier 2: * x86_64-unknown-netbsd Tier 3: + * armv7-unknown-linux-uclibceabihf * x86_64-fuchsia * x86_64-unknown-dragonfly * x86_64-unknown-linux-gnux32 diff --git a/bors.toml b/bors.toml index 03810b7e8e..ee43cf2923 100644 --- a/bors.toml +++ b/bors.toml @@ -14,6 +14,7 @@ status = [ "Linux arm gnueabi", "Linux arm-musleabi", "Linux armv7 gnueabihf", + "Linux armv7 uclibceabihf", "Linux i686 musl", "Linux i686", "Linux mipsel", diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 0bd0bc9f88..2fd2a698ba 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -2,7 +2,7 @@ #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", - target_os = "linux", + all(target_os = "linux", not(target_env = "uclibc")), target_os = "macos", target_os = "netbsd"))] feature! { diff --git a/src/sys/personality.rs b/src/sys/personality.rs index b15956c469..e64c906d1a 100644 --- a/src/sys/personality.rs +++ b/src/sys/personality.rs @@ -11,13 +11,13 @@ libc_bitflags! { ADDR_NO_RANDOMIZE; ADDR_LIMIT_32BIT; ADDR_LIMIT_3GB; - #[cfg(not(target_env = "musl"))] + #[cfg(not(any(target_env = "musl", target_env = "uclibc")))] FDPIC_FUNCPTRS; MMAP_PAGE_ZERO; READ_IMPLIES_EXEC; SHORT_INODE; STICKY_TIMEOUTS; - #[cfg(not(target_env = "musl"))] + #[cfg(not(any(target_env = "musl", target_env = "uclibc")))] UNAME26; WHOLE_SECONDS; } diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs index fb6ff1996d..24152d7d5a 100644 --- a/src/sys/ptrace/linux.rs +++ b/src/sys/ptrace/linux.rs @@ -20,7 +20,8 @@ use libc::user_regs_struct; cfg_if! { if #[cfg(any(all(target_os = "linux", target_arch = "s390x"), - all(target_os = "linux", target_env = "gnu")))] { + all(target_os = "linux", target_env = "gnu"), + target_env = "uclibc"))] { #[doc(hidden)] pub type RequestType = ::libc::c_uint; } else { @@ -30,8 +31,8 @@ cfg_if! { } libc_enum!{ - #[cfg_attr(not(any(target_env = "musl", target_os = "android")), repr(u32))] - #[cfg_attr(any(target_env = "musl", target_os = "android"), repr(i32))] + #[cfg_attr(not(any(target_env = "musl", target_env = "uclibc", target_os = "android")), repr(u32))] + #[cfg_attr(any(target_env = "musl", target_env = "uclibc", target_os = "android"), repr(i32))] /// Ptrace Request enum defining the action to be taken. #[non_exhaustive] pub enum Request { diff --git a/src/sys/resource.rs b/src/sys/resource.rs index 7f2927b4a0..ba206aa208 100644 --- a/src/sys/resource.rs +++ b/src/sys/resource.rs @@ -7,9 +7,9 @@ pub use libc::rlim_t; use std::mem; cfg_if! { - if #[cfg(all(target_os = "linux", target_env = "gnu"))]{ + if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ use libc::{__rlimit_resource_t, rlimit, RLIM_INFINITY}; - }else if #[cfg(any( + } else if #[cfg(any( target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", @@ -199,9 +199,9 @@ pub fn getrlimit(resource: Resource) -> Result<(Option, Option)> let mut old_rlim = mem::MaybeUninit::::uninit(); cfg_if! { - if #[cfg(all(target_os = "linux", target_env = "gnu"))]{ + if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) }; - }else{ + } else { let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) }; } } @@ -253,7 +253,7 @@ pub fn setrlimit( rlim_max: hard_limit.unwrap_or(RLIM_INFINITY), }; cfg_if! { - if #[cfg(all(target_os = "linux", target_env = "gnu"))]{ + if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) }; }else{ let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) }; diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 9750d89080..ddc02483ed 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -11,6 +11,7 @@ use std::str::FromStr; #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] use std::os::unix::io::RawFd; use std::ptr; +use cfg_if::cfg_if; #[cfg(not(any(target_os = "openbsd", target_os = "redox")))] #[cfg(any(feature = "aio", feature = "signal"))] @@ -420,10 +421,15 @@ pub const SIGPOLL : Signal = SIGIO; /// Alias for [`SIGSYS`] pub const SIGUNUSED : Signal = SIGSYS; -#[cfg(not(target_os = "redox"))] -type SaFlags_t = libc::c_int; -#[cfg(target_os = "redox")] -type SaFlags_t = libc::c_ulong; +cfg_if! { + if #[cfg(target_os = "redox")] { + type SaFlags_t = libc::c_ulong; + } else if #[cfg(target_env = "uclibc")] { + type SaFlags_t = libc::c_ulong; + } else { + type SaFlags_t = libc::c_int; + } +} } #[cfg(feature = "signal")] @@ -1046,6 +1052,8 @@ mod sigevent { SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))] SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, + #[cfg(all(target_os = "linux", target_env = "uclibc"))] + SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))] SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined }; diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 4517c5489f..51999a3d9e 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -120,10 +120,10 @@ pub enum AddressFamily { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Llc = libc::AF_LLC, - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] #[cfg_attr(docsrs, doc(cfg(all())))] Ib = libc::AF_IB, - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] #[cfg_attr(docsrs, doc(cfg(all())))] Mpls = libc::AF_MPLS, #[cfg(any(target_os = "android", target_os = "linux"))] diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index e46733e703..838ca3ac98 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -31,7 +31,9 @@ type fs_type_t = libc::c_ulong; type fs_type_t = libc::c_uint; #[cfg(all(target_os = "linux", target_env = "musl"))] type fs_type_t = libc::c_ulong; -#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))] +#[cfg(all(target_os = "linux", target_env = "uclibc"))] +type fs_type_t = libc::c_int; +#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl", target_env = "uclibc"))))] type fs_type_t = libc::__fsword_t; /// Describes the file system type as known by the operating system. @@ -71,7 +73,7 @@ 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")))] +#[cfg(all(target_os = "linux", not(any(target_env = "musl", target_env = "uclibc"))))] #[allow(missing_docs)] pub const FUSE_SUPER_MAGIC: FsType = FsType(libc::FUSE_SUPER_MAGIC as fs_type_t); #[cfg(all(target_os = "linux", not(target_env = "musl")))] @@ -192,12 +194,19 @@ impl Statfs { } /// Optimal transfer block size - #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))] + #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl", target_env = "uclibc"))))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> libc::__fsword_t { self.0.f_bsize } + /// Optimal transfer block size + #[cfg(all(target_os = "linux", target_env = "uclibc"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn optimal_transfer_size(&self) -> libc::c_int { + self.0.f_bsize + } + /// Optimal transfer block size #[cfg(target_os = "dragonfly")] #[cfg_attr(docsrs, doc(cfg(all())))] @@ -237,7 +246,15 @@ impl Statfs { /// Size of a block // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 - #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))] + #[cfg(all(target_os = "linux", target_env = "uclibc"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn block_size(&self) -> libc::c_int { + self.0.f_bsize + } + + /// Size of a block + // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 + #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl", target_env = "uclibc"))))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> libc::__fsword_t { self.0.f_bsize @@ -286,7 +303,14 @@ impl Statfs { } /// Maximum length of filenames - #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))] + #[cfg(all(target_os = "linux", target_env = "uclibc"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn maximum_name_length(&self) -> libc::c_int { + self.0.f_namelen + } + + /// Maximum length of filenames + #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl", target_env = "uclibc"))))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn maximum_name_length(&self) -> libc::__fsword_t { self.0.f_namelen diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 125c2e6c30..a1fc8e5fea 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -34,6 +34,8 @@ pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result { #[cfg_attr(docsrs, doc(cfg(all())))] pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], offset: off_t) -> Result { + #[cfg(target_env = "uclibc")] + let offset = offset as libc::off64_t; // uclibc doesn't use off_t let res = unsafe { libc::pwritev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset) }; @@ -52,6 +54,8 @@ pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], #[cfg_attr(docsrs, doc(cfg(all())))] pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>], offset: off_t) -> Result { + #[cfg(target_env = "uclibc")] + let offset = offset as libc::off64_t; // uclibc doesn't use off_t let res = unsafe { libc::preadv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset) }; @@ -127,7 +131,7 @@ feature! { /// [ptrace]: ../ptrace/index.html /// [`IoVec`]: struct.IoVec.html /// [`RemoteIoVec`]: struct.RemoteIoVec.html -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] pub fn process_vm_writev( pid: crate::unistd::Pid, local_iov: &[IoVec<&[u8]>], @@ -162,7 +166,7 @@ pub fn process_vm_writev( /// [`ptrace`]: ../ptrace/index.html /// [`IoVec`]: struct.IoVec.html /// [`RemoteIoVec`]: struct.RemoteIoVec.html -#[cfg(any(target_os = "linux"))] +#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] pub fn process_vm_readv( pid: crate::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], diff --git a/src/time.rs b/src/time.rs index 01a8fd0024..6a385b90bd 100644 --- a/src/time.rs +++ b/src/time.rs @@ -237,7 +237,6 @@ pub fn clock_gettime(clock_id: ClockId) -> Result { #[cfg(not(any( target_os = "macos", target_os = "ios", - target_env = "uclibc", target_os = "redox", target_os = "hermit", )))] diff --git a/test/sys/mod.rs b/test/sys/mod.rs index 60904bd174..91c0aae708 100644 --- a/test/sys/mod.rs +++ b/test/sys/mod.rs @@ -7,7 +7,7 @@ mod test_signal; // cases on DragonFly. #[cfg(any(target_os = "freebsd", target_os = "ios", - target_os = "linux", + all(target_os = "linux", not(target_env = "uclibc")), target_os = "macos", target_os = "netbsd"))] mod test_aio; diff --git a/test/sys/test_aio_drop.rs b/test/sys/test_aio_drop.rs index 71a2183bc1..f9ff97af6c 100644 --- a/test/sys/test_aio_drop.rs +++ b/test/sys/test_aio_drop.rs @@ -4,6 +4,7 @@ #[test] #[should_panic(expected = "Dropped an in-progress AioCb")] #[cfg(all(not(target_env = "musl"), + not(target_env = "uclibc"), any(target_os = "linux", target_os = "ios", target_os = "macos", diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index c63b58103c..5353c516e4 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -204,7 +204,7 @@ fn test_preadv() { } #[test] -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] // uclibc doesn't implement process_vm_readv // qemu-user doesn't implement process_vm_readv/writev on most arches #[cfg_attr(qemu, ignore)] fn test_process_vm_readv() { diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index b24a49eef5..95e224e2d4 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -30,6 +30,9 @@ use std::os::unix::fs; #[test] #[cfg(not(target_os = "redox"))] +// QEMU does not handle openat well enough to satisfy this test +// https://gitlab.com/qemu-project/qemu/-/issues/829 +#[cfg_attr(qemu, ignore)] fn test_openat() { const CONTENTS: &[u8] = b"abcd"; let mut tmp = NamedTempFile::new().unwrap(); @@ -357,6 +360,7 @@ mod linux_android { #[test] #[cfg(all(target_os = "linux", not(target_env = "musl")))] + #[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile fn test_ofd_write_lock() { use nix::sys::stat::fstat; use std::mem; @@ -394,6 +398,7 @@ mod linux_android { #[test] #[cfg(all(target_os = "linux", not(target_env = "musl")))] + #[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile fn test_ofd_read_lock() { use nix::sys::stat::fstat; use std::mem; From 3b00f37bfbb2947bce628815663924844661323f Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sat, 29 Jan 2022 22:50:29 -0600 Subject: [PATCH 043/358] Fix typo in pread docs --- src/sys/uio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/uio.rs b/src/sys/uio.rs index a1fc8e5fea..d9b3bb16db 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -76,7 +76,7 @@ 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. +/// Low-level read from a file, with specified offset. /// /// See also [pread(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html) // TODO: move to unistd From b637f12bf97b343093ab3b42d1013abafbb4df50 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sat, 29 Jan 2022 23:25:29 -0600 Subject: [PATCH 044/358] Add support for aarch64-apple-darwin Replace 'OSX' language with 'macOS', to match Rust's language. --- .cirrus.yml | 15 +++++++++++---- README.md | 3 ++- bors.toml | 3 ++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 3207b70419..4fd93a36b7 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -58,9 +58,9 @@ task: - cargo hack check --each-feature --target i686-unknown-freebsd before_cache_script: rm -rf $CARGO_HOME/registry/index -# Test OSX in a full VM +# Test macOS x86_64 in a full VM task: - name: OSX x86_64 + name: macOS x86_64 env: TARGET: x86_64-apple-darwin osx_instance: @@ -211,8 +211,8 @@ task: NOHACK: 1 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. + # 1.49.0 and above. Below that it's possible to cross-build from a macOS + # host, but macOS VMs are more expensive than Linux VMs. TOOLCHAIN: 1.49.0 - name: iOS x86_64 env: @@ -236,6 +236,13 @@ task: - name: Linux x32 env: TARGET: x86_64-unknown-linux-gnux32 + - name: macOS aarch64 + env: + TARGET: aarch64-apple-darwin + # macOS aarch64 toolchain isn't available via rustup until 1.49 + TOOLCHAIN: 1.49.0 + container: + image: rust:1.49 - name: NetBSD x86_64 env: TARGET: x86_64-unknown-netbsd diff --git a/README.md b/README.md index 3a38f4e5bb..b0c27b16f3 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ Tier 1: * x86_64-unknown-linux-musl Tier 2: + * aarch64-apple-darwin * aarch64-apple-ios * aarch64-linux-android * arm-linux-androideabi @@ -87,7 +88,7 @@ Tier 3: ## Minimum Supported Rust Version (MSRV) -nix is supported on Rust 1.46.0 and higher. It's MSRV will not be +nix is supported on Rust 1.46.0 and higher. Its MSRV will not be changed in the future without bumping the major or minor version. ## Contributing diff --git a/bors.toml b/bors.toml index ee43cf2923..b22877a767 100644 --- a/bors.toml +++ b/bors.toml @@ -25,10 +25,11 @@ status = [ "Linux x32", "Linux x86_64 musl", "Linux x86_64", + "macOS aarch64", + "macOS x86_64", "Minver", "NetBSD x86_64", "OpenBSD x86_64", - "OSX x86_64", "Redox x86_64", "Rust Stable", "iOS aarch64", From 7d0344141c63be4b08f1668a298766ebc81ffcc3 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Mon, 31 Jan 2022 21:32:28 -0600 Subject: [PATCH 045/358] Document inotify.rs --- src/sys/inotify.rs | 24 ++++++++++++++++++++++++ src/sys/mod.rs | 1 - 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/sys/inotify.rs b/src/sys/inotify.rs index d6697a4a21..b19dbe12dd 100644 --- a/src/sys/inotify.rs +++ b/src/sys/inotify.rs @@ -41,31 +41,53 @@ use cfg_if::cfg_if; libc_bitflags! { /// Configuration options for [`inotify_add_watch`](fn.inotify_add_watch.html). pub struct AddWatchFlags: u32 { + /// File was accessed. IN_ACCESS; + /// File was modified. IN_MODIFY; + /// Metadata changed. IN_ATTRIB; + /// Writable file was closed. IN_CLOSE_WRITE; + /// Nonwritable file was closed. IN_CLOSE_NOWRITE; + /// File was opened. IN_OPEN; + /// File was moved from X. IN_MOVED_FROM; + /// File was moved to Y. IN_MOVED_TO; + /// Subfile was created. IN_CREATE; + /// Subfile was deleted. IN_DELETE; + /// Self was deleted. IN_DELETE_SELF; + /// Self was moved. IN_MOVE_SELF; + /// Backing filesystem was unmounted. IN_UNMOUNT; + /// Event queue overflowed. IN_Q_OVERFLOW; + /// File was ignored. IN_IGNORED; + /// Combination of `IN_CLOSE_WRITE` and `IN_CLOSE_NOWRITE`. IN_CLOSE; + /// Combination of `IN_MOVED_FROM` and `IN_MOVED_TO`. IN_MOVE; + /// Only watch the path if it is a directory. IN_ONLYDIR; + /// Don't follow symlinks. IN_DONT_FOLLOW; + /// Event occurred against directory. IN_ISDIR; + /// Only send event once. IN_ONESHOT; + /// All of the events. IN_ALL_EVENTS; } } @@ -73,7 +95,9 @@ libc_bitflags! { libc_bitflags! { /// Configuration options for [`inotify_init1`](fn.inotify_init1.html). pub struct InitFlags: c_int { + /// Set the `FD_CLOEXEC` flag on the file descriptor. IN_CLOEXEC; + /// Set the `O_NONBLOCK` flag on the open file description referred to by the new file descriptor. IN_NONBLOCK; } } diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 2fd2a698ba..91423accae 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -192,7 +192,6 @@ feature! { #[cfg(any(target_os = "android", target_os = "linux"))] feature! { #![feature = "inotify"] - #[allow(missing_docs)] pub mod inotify; } From e6f01f20e1e1d1ebd4c8685c742c9381f3967252 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Mon, 31 Jan 2022 21:34:57 -0600 Subject: [PATCH 046/358] Document mman.rs No documentation provided for MADV_CAN_REUSE, as Darwin doesn't actually document its functionality. --- src/sys/mman.rs | 5 +++++ src/sys/mod.rs | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sys/mman.rs b/src/sys/mman.rs index 523b468341..a7469a1792 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -299,6 +299,7 @@ libc_enum!{ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] MADV_CORE, + /// This process should not be killed when swap space is exhausted. #[cfg(any(target_os = "freebsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] MADV_PROTECT, @@ -314,14 +315,18 @@ libc_enum!{ #[cfg(any(target_os = "ios", target_os = "macos"))] #[cfg_attr(docsrs, doc(cfg(all())))] MADV_ZERO_WIRED_PAGES, + /// Pages can be reused (by anyone). #[cfg(any(target_os = "ios", target_os = "macos"))] #[cfg_attr(docsrs, doc(cfg(all())))] MADV_FREE_REUSABLE, + /// Caller wants to reuse those pages. #[cfg(any(target_os = "ios", target_os = "macos"))] #[cfg_attr(docsrs, doc(cfg(all())))] MADV_FREE_REUSE, + // Darwin doesn't document this flag's behavior. #[cfg(any(target_os = "ios", target_os = "macos"))] #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(missing_docs)] MADV_CAN_REUSE, } } diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 91423accae..2e9ca226ef 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -55,7 +55,6 @@ feature! { #[cfg(not(target_os = "redox"))] feature! { #![feature = "mman"] - #[allow(missing_docs)] pub mod mman; } From 7c9a7af4fce3ab4c958996b23e4e409b2eb0ddf9 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Mon, 31 Jan 2022 22:23:10 -0600 Subject: [PATCH 047/358] Document personality.rs --- src/sys/mod.rs | 1 - src/sys/personality.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 2e9ca226ef..63d1a181cc 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -61,7 +61,6 @@ feature! { #[cfg(target_os = "linux")] feature! { #![feature = "personality"] - #[allow(missing_docs)] pub mod personality; } diff --git a/src/sys/personality.rs b/src/sys/personality.rs index e64c906d1a..2af6687823 100644 --- a/src/sys/personality.rs +++ b/src/sys/personality.rs @@ -1,3 +1,4 @@ +//! Process execution domains use crate::Result; use crate::errno::Errno; @@ -7,18 +8,44 @@ libc_bitflags! { /// Flags used and returned by [`get()`](fn.get.html) and /// [`set()`](fn.set.html). pub struct Persona: c_int { + /// Provide the legacy virtual address space layout. ADDR_COMPAT_LAYOUT; + /// Disable address-space-layout randomization. ADDR_NO_RANDOMIZE; + /// Limit the address space to 32 bits. ADDR_LIMIT_32BIT; + /// Use `0xc0000000` as the offset at which to search a virtual memory + /// chunk on [`mmap(2)`], otherwise use `0xffffe000`. + /// + /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html ADDR_LIMIT_3GB; + /// User-space function pointers to signal handlers point to descriptors. #[cfg(not(any(target_env = "musl", target_env = "uclibc")))] + #[cfg_attr(docsrs, doc(cfg(all())))] FDPIC_FUNCPTRS; + /// Map page 0 as read-only. MMAP_PAGE_ZERO; + /// `PROT_READ` implies `PROT_EXEC` for [`mmap(2)`]. + /// + /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html READ_IMPLIES_EXEC; + /// No effects. SHORT_INODE; + /// [`select(2)`], [`pselect(2)`], and [`ppoll(2)`] do not modify the + /// returned timeout argument when interrupted by a signal handler. + /// + /// [`select(2)`]: https://man7.org/linux/man-pages/man2/select.2.html + /// [`pselect(2)`]: https://man7.org/linux/man-pages/man2/pselect.2.html + /// [`ppoll(2)`]: https://man7.org/linux/man-pages/man2/ppoll.2.html STICKY_TIMEOUTS; + /// Have [`uname(2)`] report a 2.6.40+ version number rather than a 3.x + /// version number. + /// + /// [`uname(2)`]: https://man7.org/linux/man-pages/man2/uname.2.html #[cfg(not(any(target_env = "musl", target_env = "uclibc")))] + #[cfg_attr(docsrs, doc(cfg(all())))] UNAME26; + /// No effects. WHOLE_SECONDS; } } From d3ff2666d699fd839e8ef530ad8d5bcea568dcff Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Mon, 31 Jan 2022 22:36:03 -0600 Subject: [PATCH 048/358] Document reboot.rs --- src/sys/mod.rs | 1 - src/sys/reboot.rs | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 63d1a181cc..7ad819d22b 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -91,7 +91,6 @@ feature! { #[cfg(target_os = "linux")] feature! { #![feature = "reboot"] - #[allow(missing_docs)] pub mod reboot; } diff --git a/src/sys/reboot.rs b/src/sys/reboot.rs index 46ab68b632..2a8009e4f8 100644 --- a/src/sys/reboot.rs +++ b/src/sys/reboot.rs @@ -13,15 +13,22 @@ libc_enum! { #[repr(i32)] #[non_exhaustive] pub enum RebootMode { + /// Halt the system. RB_HALT_SYSTEM, + /// Execute a kernel that has been loaded earlier with + /// [`kexec_load(2)`](https://man7.org/linux/man-pages/man2/kexec_load.2.html). RB_KEXEC, + /// Stop the system and switch off power, if possible. RB_POWER_OFF, + /// Restart the system. RB_AUTOBOOT, - // we do not support Restart2, + // we do not support Restart2. + /// Suspend the system using software suspend. RB_SW_SUSPEND, } } +/// Reboots or shuts down the system. pub fn reboot(how: RebootMode) -> Result { unsafe { libc::reboot(how as libc::c_int) From 7baf6d12c88bfba20b77c68353826702c7248fcd Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Mon, 31 Jan 2022 22:45:21 -0600 Subject: [PATCH 049/358] Document timerfd.rs --- src/sys/mod.rs | 1 - src/sys/timerfd.rs | 11 +++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 7ad819d22b..151d9e9d08 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -195,7 +195,6 @@ feature! { #[cfg(any(target_os = "android", target_os = "linux"))] feature! { #![feature = "time"] - #[allow(missing_docs)] pub mod timerfd; } diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs index bc5a75d4ce..18acbae30b 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -60,10 +60,19 @@ libc_enum! { #[repr(i32)] #[non_exhaustive] pub enum ClockId { + /// A settable system-wide real-time clock. CLOCK_REALTIME, + /// A non-settable monotonically increasing clock. + /// + /// Does not change after system startup. + /// Does not measure time while the system is suspended. CLOCK_MONOTONIC, + /// Like `CLOCK_MONOTONIC`, except that `CLOCK_BOOTTIME` includes the time + /// that the system was suspended. CLOCK_BOOTTIME, + /// Like `CLOCK_REALTIME`, but will wake the system if it is suspended. CLOCK_REALTIME_ALARM, + /// Like `CLOCK_BOOTTIME`, but will wake the system if it is suspended. CLOCK_BOOTTIME_ALARM, } } @@ -72,7 +81,9 @@ libc_bitflags! { /// Additional flags to change the behaviour of the file descriptor at the /// time of creation. pub struct TimerFlags: c_int { + /// Set the `O_NONBLOCK` flag on the open file description referred to by the new file descriptor. TFD_NONBLOCK; + /// Set the `FD_CLOEXEC` flag on the file descriptor. TFD_CLOEXEC; } } From 9269056e8e6543ae957a32141e33fd425e9e94d2 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 23 Jan 2022 19:04:17 -0600 Subject: [PATCH 050/358] Add accept4 on supported platforms --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39bceab7b0..7433db1342 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1636](https://github.com/nix-rust/nix/pull/1636)) - Added `fspacectl` on FreeBSD (#[1640](https://github.com/nix-rust/nix/pull/1640)) +- Added `accept4` on DragonFly, Emscripten, Fuchsia, Illumos, and NetBSD. + (#[1654](https://github.com/nix-rust/nix/pull/1654)) ### Changed diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 42a032c933..54327951ed 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1794,8 +1794,13 @@ pub fn accept(sockfd: RawFd) -> Result { target_arch = "x86_64" ) ), + target_os = "dragonfly", + target_os = "emscripten", target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", target_os = "linux", + target_os = "netbsd", target_os = "openbsd"))] pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result { let res = unsafe { libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) }; From 6e09f6c6e50a8330da56fe46c3d23fafb2cbf2b1 Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Mon, 7 Feb 2022 08:29:11 +0800 Subject: [PATCH 051/358] use version of libc published on crates https://github.com/rust-lang/libc/pull/2543 was merged and is available starting from 0.2.114. Using published version of libc makes it easier to use git version of nix --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5cdf95c5c6..039341d463 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { git = "https://github.com/rust-lang/libc", rev = "7600416f1ca896b501d58b0f44f1869d566359d6", features = [ "extra_traits" ] } +libc = { version = "0.2.114", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" From 378530d6159a6732053ae02585df7ac5a8961c37 Mon Sep 17 00:00:00 2001 From: Dean Li Date: Sat, 16 Oct 2021 12:33:50 +0800 Subject: [PATCH 052/358] Impl `AsRawFd` for `OwningIter` For issue #1558 --- src/dir.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/dir.rs b/src/dir.rs index 62e7b4d5b6..396b54fb03 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -142,6 +142,14 @@ impl Iterator for OwningIter { } } +/// The file descriptor continues to be owned by the `OwningIter`, +/// so callers must not keep a `RawFd` after the `OwningIter` is dropped. +impl AsRawFd for OwningIter { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + impl IntoIterator for Dir { type Item = Result; type IntoIter = OwningIter; From 08e40c0fee3c81ca67317f610ba88ac71a0f3ee4 Mon Sep 17 00:00:00 2001 From: Dean Li Date: Sun, 17 Oct 2021 13:50:54 +0800 Subject: [PATCH 053/358] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7433db1342..82f89bb2dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1640](https://github.com/nix-rust/nix/pull/1640)) - Added `accept4` on DragonFly, Emscripten, Fuchsia, Illumos, and NetBSD. (#[1654](https://github.com/nix-rust/nix/pull/1654)) +- Added `AsRawFd` implementation on `OwningIter`. + (#[1563](https://github.com/nix-rust/nix/pull/1563)) ### Changed From abd76aa75963904add5ac00364b887f13241cb7a Mon Sep 17 00:00:00 2001 From: rupansh-arch Date: Mon, 18 Oct 2021 03:56:26 +0530 Subject: [PATCH 054/358] enable process_vm_readv, process_vm_writev for android CHANGELOG: add process_vm_* entry process_vm_*: fix documentation for android expose process_vm_readv, process_vm_writev for android Signed-off-by: rupansh-arch --- CHANGELOG.md | 2 ++ src/sys/uio.rs | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82f89bb2dd..dc8143b318 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1654](https://github.com/nix-rust/nix/pull/1654)) - Added `AsRawFd` implementation on `OwningIter`. (#[1563](https://github.com/nix-rust/nix/pull/1563)) +- Added `process_vm_readv` and `process_vm_writev` on Android. + (#[1557](https://github.com/nix-rust/nix/pull/1557)) ### Changed diff --git a/src/sys/uio.rs b/src/sys/uio.rs index d9b3bb16db..4229830050 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -97,7 +97,7 @@ pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result{ /// therefore not represented in Rust by an actual slice as `IoVec` is. It /// is used with [`process_vm_readv`](fn.process_vm_readv.html) /// and [`process_vm_writev`](fn.process_vm_writev.html). -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg_attr(docsrs, doc(cfg(all())))] #[repr(C)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -125,13 +125,13 @@ feature! { /// `CAP_SYS_PTRACE`), or you must be running as the same user as the /// target process and the OS must have unprivileged debugging enabled. /// -/// This function is only available on Linux. +/// This function is only available on Linux and Android(SDK23+). /// /// [`process_vm_writev`(2)]: https://man7.org/linux/man-pages/man2/process_vm_writev.2.html /// [ptrace]: ../ptrace/index.html /// [`IoVec`]: struct.IoVec.html /// [`RemoteIoVec`]: struct.RemoteIoVec.html -#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] +#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] pub fn process_vm_writev( pid: crate::unistd::Pid, local_iov: &[IoVec<&[u8]>], @@ -160,13 +160,13 @@ pub fn process_vm_writev( /// `CAP_SYS_PTRACE`), or you must be running as the same user as the /// target process and the OS must have unprivileged debugging enabled. /// -/// This function is only available on Linux. +/// This function is only available on Linux and Android(SDK23+). /// /// [`process_vm_readv`(2)]: https://man7.org/linux/man-pages/man2/process_vm_readv.2.html /// [`ptrace`]: ../ptrace/index.html /// [`IoVec`]: struct.IoVec.html /// [`RemoteIoVec`]: struct.RemoteIoVec.html -#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] +#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] pub fn process_vm_readv( pid: crate::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], From 263e8709fac2c4560ebeeea06a7f6fa6adb89d05 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 13 Feb 2022 09:28:27 -0600 Subject: [PATCH 055/358] Enable uconxtext module for s390x Added to libc by https://github.com/rust-lang/libc/commit/38569c719befeb5b5051caeb6b0ff628ccd0ff90 --- CHANGELOG.md | 2 ++ src/lib.rs | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc8143b318..765ab11a09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1563](https://github.com/nix-rust/nix/pull/1563)) - Added `process_vm_readv` and `process_vm_writev` on Android. (#[1557](https://github.com/nix-rust/nix/pull/1557)) +- Added `nix::uncontext` module on s390x. + (#[1662](https://github.com/nix-rust/nix/pull/1662)) ### Changed diff --git a/src/lib.rs b/src/lib.rs index 5d6a0cba45..86dbaffd25 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -146,7 +146,8 @@ feature! { // 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")))] + any(target_arch = "s390x", target_arch = "x86", + target_arch = "x86_64")))] feature! { #![feature = "ucontext"] #[allow(missing_docs)] From bb54af538d607530f3a67679ad8c0ca8cd5759b3 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Wed, 2 Feb 2022 19:40:50 -0800 Subject: [PATCH 056/358] 30X performance improvement in with_nix_path by not initializing memory Signed-off-by: Alex Saveau --- .gitignore | 1 + src/lib.rs | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 87f1a14769..0b0404b4a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ syntax: glob Cargo.lock target +.idea *.diff *.rej *.orig diff --git a/src/lib.rs b/src/lib.rs index 5d6a0cba45..6d7ff55b99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -163,8 +163,9 @@ pub mod unistd; use libc::PATH_MAX; -use std::result; +use std::{ptr, result, slice}; use std::ffi::{CStr, OsStr}; +use std::mem::MaybeUninit; use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; @@ -260,15 +261,22 @@ impl NixPath for [u8] { } fn with_nix_path(&self, f: F) -> Result - where F: FnOnce(&CStr) -> T { - let mut buf = [0u8; PATH_MAX as usize]; - + where + F: FnOnce(&CStr) -> T, + { if self.len() >= PATH_MAX as usize { - return Err(Errno::ENAMETOOLONG) + return Err(Errno::ENAMETOOLONG); + } + + let mut buf = MaybeUninit::<[u8; PATH_MAX as usize]>::uninit(); + let buf_ptr = buf.as_mut_ptr() as *mut u8; + + unsafe { + ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len()); + buf_ptr.add(self.len()).write(0); } - buf[..self.len()].copy_from_slice(self); - match CStr::from_bytes_with_nul(&buf[..=self.len()]) { + match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, self.len() + 1) }) { Ok(s) => Ok(f(s)), Err(_) => Err(Errno::EINVAL), } From 2196824f1e79e0338386bd394cb59f878ea2e058 Mon Sep 17 00:00:00 2001 From: WATANABE Yuki Date: Sun, 20 Feb 2022 13:17:09 +0900 Subject: [PATCH 057/358] Implement Extend and From/IntoIterator for SigSet --- CHANGELOG.md | 7 +++++ src/sys/signal.rs | 70 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 69 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 765ab11a09..942d7b3dac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,12 +47,19 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1557](https://github.com/nix-rust/nix/pull/1557)) - Added `nix::uncontext` module on s390x. (#[1662](https://github.com/nix-rust/nix/pull/1662)) +- Implemented `Extend`, `FromIterator`, and `IntoIterator` for `SigSet` and + added `SigSet::iter` and `SigSetIter`. + (#[1553](https://github.com/nix-rust/nix/pull/1553)) ### Changed - `mqueue` functions now operate on a distinct type, `nix::mqueue::MqdT`. Accessors take this type by reference, not by value. (#[1639](https://github.com/nix-rust/nix/pull/1639)) +- Removed `SigSet::extend` in favor of `>::extend`. + Because of this change, you now need `use std::iter::Extend` to call `extend` + on a `SigSet`. + (#[1553](https://github.com/nix-rust/nix/pull/1553)) ### Fixed diff --git a/src/sys/signal.rs b/src/sys/signal.rs index ddc02483ed..f10a213339 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -482,6 +482,9 @@ feature! { #![feature = "signal"] use crate::unistd::Pid; +use std::iter::Extend; +use std::iter::FromIterator; +use std::iter::IntoIterator; /// Specifies a set of [`Signal`]s that may be blocked, waited for, etc. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -532,14 +535,9 @@ 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) { - self.add(signal); - } - } + /// Returns an iterator that yields the signals contained in this set. + pub fn iter(&self) -> SigSetIter<'_> { + self.into_iter() } /// Gets the currently blocked (masked) set of signals for the calling thread. @@ -593,6 +591,55 @@ impl AsRef for SigSet { } } +// TODO: Consider specialization for the case where T is &SigSet and libc::sigorset is available. +impl Extend for SigSet { + fn extend(&mut self, iter: T) + where T: IntoIterator { + for signal in iter { + self.add(signal); + } + } +} + +impl FromIterator for SigSet { + fn from_iter(iter: T) -> Self + where T: IntoIterator { + let mut sigset = SigSet::empty(); + sigset.extend(iter); + sigset + } +} + +/// Iterator for a [`SigSet`]. +/// +/// Call [`SigSet::iter`] to create an iterator. +#[derive(Clone, Debug)] +pub struct SigSetIter<'a> { + sigset: &'a SigSet, + inner: SignalIterator, +} + +impl Iterator for SigSetIter<'_> { + type Item = Signal; + fn next(&mut self) -> Option { + loop { + match self.inner.next() { + None => return None, + Some(signal) if self.sigset.contains(signal) => return Some(signal), + Some(_signal) => continue, + } + } + } +} + +impl<'a> IntoIterator for &'a SigSet { + type Item = Signal; + type IntoIter = SigSetIter<'a>; + fn into_iter(self) -> Self::IntoIter { + SigSetIter { sigset: self, inner: Signal::iterator() } + } +} + /// A signal handler. #[allow(unknown_lints)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -1235,6 +1282,13 @@ mod tests { }).join().unwrap(); } + #[test] + fn test_from_and_into_iterator() { + let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]); + let signals = sigset.into_iter().collect::>(); + assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]); + } + #[test] #[cfg(not(target_os = "redox"))] fn test_sigaction() { From 1a51fbe157a93a342c9d855eaf1c387821413372 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Mon, 21 Feb 2022 17:45:29 -0600 Subject: [PATCH 058/358] Add ENOTRECOVERABLE and EOWNERDEAD error codes on DragonFly --- CHANGELOG.md | 2 ++ src/errno.rs | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 942d7b3dac..d85b42d066 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Implemented `Extend`, `FromIterator`, and `IntoIterator` for `SigSet` and added `SigSet::iter` and `SigSetIter`. (#[1553](https://github.com/nix-rust/nix/pull/1553)) +- Added `ENOTRECOVERABLE` and `EOWNERDEAD` error codes on DragonFly. + (#[1665](https://github.com/nix-rust/nix/pull/1665)) ### Changed diff --git a/src/errno.rs b/src/errno.rs index 3da246e823..17744fe22a 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -608,11 +608,13 @@ fn desc(errno: Errno) -> &'static str { EPROTO => "Protocol error", #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "ios", target_os = "openbsd"))] + target_os = "dragonfly", target_os = "ios", + target_os = "openbsd"))] ENOTRECOVERABLE => "State not recoverable", #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "ios", target_os = "openbsd"))] + target_os = "dragonfly", target_os = "ios", + target_os = "openbsd"))] EOWNERDEAD => "Previous owner died", #[cfg(any(target_os = "macos", target_os = "freebsd", @@ -1663,6 +1665,8 @@ mod consts { ENOLINK = libc::ENOLINK, EPROTO = libc::EPROTO, ENOMEDIUM = libc::ENOMEDIUM, + ENOTRECOVERABLE = libc::ENOTRECOVERABLE, + EOWNERDEAD = libc::EOWNERDEAD, EASYNC = libc::EASYNC, } From 22bb1056126cee98dcf747eb48fc5fb5736fe7d7 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 21 Feb 2022 15:04:39 -0500 Subject: [PATCH 059/358] also implement Read and Write for &PtyMaster --- CHANGELOG.md | 2 ++ src/pty.rs | 15 +++++++++++++++ test/test_pty.rs | 10 ++++++++++ 3 files changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d85b42d066..6568167749 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1553](https://github.com/nix-rust/nix/pull/1553)) - Added `ENOTRECOVERABLE` and `EOWNERDEAD` error codes on DragonFly. (#[1665](https://github.com/nix-rust/nix/pull/1665)) +- Implemented `Read` and `Write` for `&PtyMaster` + (#[1664](https://github.com/nix-rust/nix/pull/1664)) ### Changed diff --git a/src/pty.rs b/src/pty.rs index ae304d83d3..bb266a65bb 100644 --- a/src/pty.rs +++ b/src/pty.rs @@ -95,6 +95,21 @@ impl io::Write for PtyMaster { } } +impl io::Read for &PtyMaster { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + unistd::read(self.0, buf).map_err(io::Error::from) + } +} + +impl io::Write for &PtyMaster { + fn write(&mut self, buf: &[u8]) -> io::Result { + unistd::write(self.0, buf).map_err(io::Error::from) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + /// Grant access to a slave pseudoterminal (see /// [`grantpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html)) /// diff --git a/test/test_pty.rs b/test/test_pty.rs index 71932f2d6e..1a7cab81a0 100644 --- a/test/test_pty.rs +++ b/test/test_pty.rs @@ -170,6 +170,11 @@ fn test_read_ptty_pair() { slave.write_all(b"hello").unwrap(); master.read_exact(&mut buf).unwrap(); assert_eq!(&buf, b"hello"); + + let mut master = &master; + slave.write_all(b"hello").unwrap(); + master.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"hello"); } /// Test `io::Write` on the PTTY master @@ -182,6 +187,11 @@ fn test_write_ptty_pair() { master.write_all(b"adios").unwrap(); slave.read_exact(&mut buf).unwrap(); assert_eq!(&buf, b"adios"); + + let mut master = &master; + master.write_all(b"adios").unwrap(); + slave.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"adios"); } #[test] From 1a2ee3da3026a14d42498f5ca4e4b2c1a75bc81d Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 27 Feb 2022 09:54:15 -0600 Subject: [PATCH 060/358] Define _POSIX_VDISABLE on Android to fix doc test --- src/sys/termios.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sys/termios.rs b/src/sys/termios.rs index 92204a051d..8870f6be7b 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -497,7 +497,8 @@ impl SpecialCharacterIndices { } pub use libc::NCCS; -#[cfg(any(target_os = "dragonfly", +#[cfg(any(target_os = "android", + target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "macos", From 378a66dd1837a634ef714166f657cb7111c291ec Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Wed, 2 Feb 2022 19:40:50 -0800 Subject: [PATCH 061/358] Remove `PATH_MAX` restriction from `with_nix_path` Signed-off-by: Alex Saveau --- CHANGELOG.md | 3 +++ src/lib.rs | 47 ++++++++++++++++++++++++++++------------------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6568167749..c474b2fb0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). Because of this change, you now need `use std::iter::Extend` to call `extend` on a `SigSet`. (#[1553](https://github.com/nix-rust/nix/pull/1553)) +- Removed the the `PATH_MAX` restriction from APIs accepting paths. Paths + will now be allocated on the heap if they are too long. In addition, large + instruction count improvements (~30x) were made to path handling. ### Fixed diff --git a/src/lib.rs b/src/lib.rs index 0cfd3fb4e8..6809382978 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -156,19 +156,11 @@ feature! { #[allow(missing_docs)] pub mod unistd; -/* - * - * ===== Result / Error ===== - * - */ - -use libc::PATH_MAX; - -use std::{ptr, result, slice}; -use std::ffi::{CStr, OsStr}; +use std::ffi::{CStr, CString, OsStr}; use std::mem::MaybeUninit; use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; +use std::{ptr, result, slice}; use errno::Errno; @@ -242,12 +234,9 @@ impl NixPath for CStr { } fn with_nix_path(&self, f: F) -> Result - where F: FnOnce(&CStr) -> T { - // Equivalence with the [u8] impl. - if self.len() >= PATH_MAX as usize { - return Err(Errno::ENAMETOOLONG) - } - + where + F: FnOnce(&CStr) -> T, + { Ok(f(self)) } } @@ -265,11 +254,19 @@ impl NixPath for [u8] { where F: FnOnce(&CStr) -> T, { - if self.len() >= PATH_MAX as usize { - return Err(Errno::ENAMETOOLONG); + // The real PATH_MAX is typically 4096, but it's statistically unlikely to have a path + // longer than ~300 bytes. See the the PR description to get stats for your own machine. + // https://github.com/nix-rust/nix/pull/1656 + // + // By being smaller than a memory page, we also avoid the compiler inserting a probe frame: + // https://docs.rs/compiler_builtins/latest/compiler_builtins/probestack/index.html + const MAX_STACK_ALLOCATION: usize = 1024; + + if self.len() >= MAX_STACK_ALLOCATION { + return with_nix_path_allocating(self, f); } - let mut buf = MaybeUninit::<[u8; PATH_MAX as usize]>::uninit(); + let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit(); let buf_ptr = buf.as_mut_ptr() as *mut u8; unsafe { @@ -284,6 +281,18 @@ impl NixPath for [u8] { } } +#[cold] +#[inline(never)] +fn with_nix_path_allocating(from: &[u8], f: F) -> Result +where + F: FnOnce(&CStr) -> T, +{ + match CString::new(from) { + Ok(s) => Ok(f(&s)), + Err(_) => Err(Errno::EINVAL), + } +} + impl NixPath for Path { fn is_empty(&self) -> bool { NixPath::is_empty(self.as_os_str()) From 490a0c52b7350bd3028ffe427094e45e418b2a34 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Sat, 5 Mar 2022 22:30:15 -0800 Subject: [PATCH 062/358] Fix complation on riscv32 Signed-off-by: Khem Raj --- src/sys/statfs.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 838ca3ac98..98f7e5dd45 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -344,7 +344,7 @@ impl Statfs { } /// Total data blocks in filesystem - #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks(&self) -> u64 { self.0.f_blocks @@ -358,7 +358,7 @@ impl Statfs { target_os = "freebsd", target_os = "openbsd", target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))) + all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) )))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks(&self) -> libc::c_ulong { @@ -386,7 +386,7 @@ impl Statfs { } /// Free blocks in filesystem - #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_free(&self) -> u64 { self.0.f_bfree @@ -400,7 +400,7 @@ impl Statfs { target_os = "freebsd", target_os = "openbsd", target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))) + all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) )))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_free(&self) -> libc::c_ulong { @@ -429,7 +429,7 @@ impl Statfs { } /// Free blocks available to unprivileged user - #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_available(&self) -> u64 { self.0.f_bavail @@ -443,7 +443,7 @@ impl Statfs { target_os = "freebsd", target_os = "openbsd", target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))) + all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) )))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_available(&self) -> libc::c_ulong { @@ -471,7 +471,7 @@ impl Statfs { } /// Total file nodes in filesystem - #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files(&self) -> libc::fsfilcnt_t { self.0.f_files @@ -485,7 +485,7 @@ impl Statfs { target_os = "freebsd", target_os = "openbsd", target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))) + all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) )))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files(&self) -> libc::c_ulong { @@ -519,7 +519,7 @@ impl Statfs { } /// Free file nodes in filesystem - #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> libc::fsfilcnt_t { self.0.f_ffree @@ -533,7 +533,7 @@ impl Statfs { target_os = "freebsd", target_os = "openbsd", target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))) + all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) )))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> libc::c_ulong { From 01cd9d2cfc19ecf465a2cf3ae3dd9335351a3568 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Sat, 5 Mar 2022 00:37:01 -0800 Subject: [PATCH 063/358] linux.rs: Define consts for rv32 architecture Upstream-Status: Pending Signed-off-by: Khem Raj --- src/sys/ioctl/linux.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sys/ioctl/linux.rs b/src/sys/ioctl/linux.rs index 68ebaba9bf..08cd0c33b4 100644 --- a/src/sys/ioctl/linux.rs +++ b/src/sys/ioctl/linux.rs @@ -34,6 +34,7 @@ mod consts { target_arch = "s390x", target_arch = "x86_64", target_arch = "aarch64", + target_arch = "riscv32", target_arch = "riscv64"))] mod consts { #[doc(hidden)] From a092c5ccc7c613b8149e98f85d0179ba01c73445 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sun, 6 Mar 2022 02:19:59 -0600 Subject: [PATCH 064/358] Add MsgFlag::MSG_NOSIGNAL --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c474b2fb0b..98550b358e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1665](https://github.com/nix-rust/nix/pull/1665)) - Implemented `Read` and `Write` for `&PtyMaster` (#[1664](https://github.com/nix-rust/nix/pull/1664)) +- Added `MSG_NOSIGNAL` for Android, Dragonfly, FreeBSD, Fuchsia, Haiku, Illumos, Linux, NetBSD, OpenBSD and Solaris. + (#[1670](https://github.com/nix-rust/nix/pull/1670)) ### Changed diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 54327951ed..9c37e43bfb 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -316,6 +316,20 @@ libc_bitflags!{ target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] MSG_CMSG_CLOEXEC; + /// Requests not to send `SIGPIPE` errors when the other end breaks the connection. + /// (For more details, see [send(2)](https://linux.die.net/man/2/send)). + #[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MSG_NOSIGNAL; } } From 84d89e4fc2cdfa41e83da660ee65fd61a095585e Mon Sep 17 00:00:00 2001 From: bin liu Date: Wed, 9 Mar 2022 15:59:15 +0800 Subject: [PATCH 065/358] docs: fix link in doc for cmsg_space in sys/socket Link to cmsg_space macro for recvmmsg and recvmsg should be the doc's root of crate as macro is an exported macro. Signed-off-by: bin liu --- src/sys/socket/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 9c37e43bfb..7ed2d82dd7 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1471,7 +1471,7 @@ pub struct RecvMmsgData<'a, I> /// /// * `iov`: Scatter-gather list of buffers to receive the message /// * `cmsg_buffer`: Space to receive ancillary data. Should be created by -/// [`cmsg_space!`](macro.cmsg_space.html) +/// [`cmsg_space!`](../../macro.cmsg_space.html) /// /// # Returns /// A `Vec` with multiple `RecvMsg`, one per received message @@ -1692,7 +1692,7 @@ fn pack_mhdr_to_send<'a, I, C>( /// * `fd`: Socket file descriptor /// * `iov`: Scatter-gather list of buffers to receive the message /// * `cmsg_buffer`: Space to receive ancillary data. Should be created by -/// [`cmsg_space!`](macro.cmsg_space.html) +/// [`cmsg_space!`](../../macro.cmsg_space.html) /// * `flags`: Optional flags passed directly to the operating system. /// /// # References From df417e295bb1b34a76d9eec486d4759504da25ac Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 5 Mar 2022 11:37:53 +0100 Subject: [PATCH 066/358] wait: implement waitid() waitid() has a number of additional features that waitpid() is missing: - WNOWAIT is only accepted for waitid() on Linux (and possibly other platforms) - Support for waiting on PID file descriptors on Linux For now support is added for all platforms with waitid() that have proper siginfo_t support in libc. NetBSD support is currently a work in progress [1]. Tests for the signal/exit code are currently skipped on MIPS platforms due to bugs in qemu-user's translation of siginfo_t (fixed in [2] and [3]; the second fix is not in a released qemu version yet). [1] https://github.com/rust-lang/libc/pull/2476 [2] https://lists.nongnu.org/archive/html/qemu-devel/2021-01/msg04810.html [3] https://lists.nongnu.org/archive/html/qemu-devel/2021-10/msg05433.html --- CHANGELOG.md | 2 + src/sys/wait.rs | 111 +++++++++++++++++++++++++++++++++++++++ test/sys/test_wait.rs | 118 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 229 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98550b358e..2ad743cba6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1664](https://github.com/nix-rust/nix/pull/1664)) - Added `MSG_NOSIGNAL` for Android, Dragonfly, FreeBSD, Fuchsia, Haiku, Illumos, Linux, NetBSD, OpenBSD and Solaris. (#[1670](https://github.com/nix-rust/nix/pull/1670)) +- Added `waitid`. + (#[1584](https://github.com/nix-rust/nix/pull/1584)) ### Changed diff --git a/src/sys/wait.rs b/src/sys/wait.rs index 20ca1c1907..5fb2075fd9 100644 --- a/src/sys/wait.rs +++ b/src/sys/wait.rs @@ -6,6 +6,11 @@ use crate::Result; use cfg_if::cfg_if; use libc::{self, c_int}; use std::convert::TryFrom; +#[cfg(any( + target_os = "android", + all(target_os = "linux", not(target_env = "uclibc")), +))] +use std::os::unix::io::RawFd; libc_bitflags!( /// Controls the behavior of [`waitpid`]. @@ -233,6 +238,61 @@ impl WaitStatus { WaitStatus::Continued(pid) }) } + + /// Convert a `siginfo_t` as returned by `waitid` to a `WaitStatus` + /// + /// # Errors + /// + /// Returns an `Error` corresponding to `EINVAL` for invalid values. + /// + /// # Safety + /// + /// siginfo_t is actually a union, not all fields may be initialized. + /// The functions si_pid() and si_status() must be valid to call on + /// the passed siginfo_t. + #[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "haiku", + all(target_os = "linux", not(target_env = "uclibc")), + ))] + unsafe fn from_siginfo(siginfo: &libc::siginfo_t) -> Result { + let si_pid = siginfo.si_pid(); + if si_pid == 0 { + return Ok(WaitStatus::StillAlive); + } + + assert_eq!(siginfo.si_signo, libc::SIGCHLD); + + let pid = Pid::from_raw(si_pid); + let si_status = siginfo.si_status(); + + let status = match siginfo.si_code { + libc::CLD_EXITED => WaitStatus::Exited(pid, si_status), + libc::CLD_KILLED | libc::CLD_DUMPED => WaitStatus::Signaled( + pid, + Signal::try_from(si_status)?, + siginfo.si_code == libc::CLD_DUMPED, + ), + libc::CLD_STOPPED => WaitStatus::Stopped(pid, Signal::try_from(si_status)?), + libc::CLD_CONTINUED => WaitStatus::Continued(pid), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::CLD_TRAPPED => { + if si_status == libc::SIGTRAP | 0x80 { + WaitStatus::PtraceSyscall(pid) + } else { + WaitStatus::PtraceEvent( + pid, + Signal::try_from(si_status & 0xff)?, + (si_status >> 8) as c_int, + ) + } + } + _ => return Err(Errno::EINVAL), + }; + + Ok(status) + } } /// Wait for a process to change status @@ -268,3 +328,54 @@ pub fn waitpid>>(pid: P, options: Option) -> Re pub fn wait() -> Result { waitpid(None, None) } + +/// The ID argument for `waitid` +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "haiku", + all(target_os = "linux", not(target_env = "uclibc")), +))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Id { + /// Wait for any child + All, + /// Wait for the child whose process ID matches the given PID + Pid(Pid), + /// Wait for the child whose process group ID matches the given PID + /// + /// If the PID is zero, the caller's process group is used since Linux 5.4. + PGid(Pid), + /// Wait for the child referred to by the given PID file descriptor + #[cfg(any(target_os = "android", target_os = "linux"))] + PIDFd(RawFd), +} + +/// Wait for a process to change status +/// +/// See also [waitid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitid.html) +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "haiku", + all(target_os = "linux", not(target_env = "uclibc")), +))] +pub fn waitid(id: Id, flags: WaitPidFlag) -> Result { + let (idtype, idval) = match id { + Id::All => (libc::P_ALL, 0), + Id::Pid(pid) => (libc::P_PID, pid.as_raw() as libc::id_t), + Id::PGid(pid) => (libc::P_PGID, pid.as_raw() as libc::id_t), + #[cfg(any(target_os = "android", target_os = "linux"))] + Id::PIDFd(fd) => (libc::P_PIDFD, fd as libc::id_t), + }; + + let siginfo = unsafe { + // Memory is zeroed rather than uninitialized, as not all platforms + // initialize the memory in the StillAlive case + let mut siginfo: libc::siginfo_t = std::mem::zeroed(); + Errno::result(libc::waitid(idtype, idval, &mut siginfo, flags.bits()))?; + siginfo + }; + + unsafe { WaitStatus::from_siginfo(&siginfo) } +} diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs index afe4f42b29..90d9fcf51c 100644 --- a/test/sys/test_wait.rs +++ b/test/sys/test_wait.rs @@ -23,6 +23,33 @@ fn test_wait_signal() { } } +#[test] +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "haiku", + all(target_os = "linux", not(target_env = "uclibc")), +))] +#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] +fn test_waitid_signal() { + let _m = crate::FORK_MTX.lock(); + + // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe. + match unsafe{fork()}.expect("Error: Fork Failed") { + Child => { + pause(); + unsafe { _exit(123) } + }, + Parent { child } => { + kill(child, Some(SIGKILL)).expect("Error: Kill Failed"); + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::Signaled(child, SIGKILL, false)), + ); + }, + } +} + #[test] fn test_wait_exit() { let _m = crate::FORK_MTX.lock(); @@ -36,6 +63,29 @@ fn test_wait_exit() { } } +#[test] +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "haiku", + all(target_os = "linux", not(target_env = "uclibc")), +))] +#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] +fn test_waitid_exit() { + let _m = crate::FORK_MTX.lock(); + + // Safe: Child only calls `_exit`, which is async-signal-safe. + match unsafe{fork()}.expect("Error: Fork Failed") { + Child => unsafe { _exit(12); }, + Parent { child } => { + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::Exited(child, 12)), + ); + } + } +} + #[test] fn test_waitstatus_from_raw() { let pid = Pid::from_raw(1); @@ -57,6 +107,25 @@ fn test_waitstatus_pid() { } } +#[test] +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "haiku", + all(target_os = "linux", not(target_env = "uclibc")), +))] +fn test_waitid_pid() { + let _m = crate::FORK_MTX.lock(); + + match unsafe { fork() }.unwrap() { + Child => unsafe { _exit(0) }, + Parent { child } => { + let status = waitid(Id::Pid(child), WaitPidFlag::WEXITED).unwrap(); + assert_eq!(status.pid(), Some(child)); + } + } +} + #[cfg(any(target_os = "linux", target_os = "android"))] // FIXME: qemu-user doesn't implement ptrace on most arches #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] @@ -77,7 +146,7 @@ mod ptrace { unsafe { _exit(0) } } - fn ptrace_parent(child: Pid) { + fn ptrace_wait_parent(child: Pid) { // Wait for the raised SIGTRAP assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, SIGTRAP))); // We want to test a syscall stop and a PTRACE_EVENT stop @@ -94,6 +163,39 @@ mod ptrace { assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0))); } + #[cfg(not(target_env = "uclibc"))] + fn ptrace_waitid_parent(child: Pid) { + // Wait for the raised SIGTRAP + // + // Unlike waitpid(), waitid() can distinguish trap events from regular + // stop events, so unlike ptrace_wait_parent(), we get a PtraceEvent here + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::PtraceEvent(child, SIGTRAP, 0)), + ); + // We want to test a syscall stop and a PTRACE_EVENT stop + assert!(ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT).is_ok()); + + // First, stop on the next system call, which will be exit() + assert!(ptrace::syscall(child, None).is_ok()); + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::PtraceSyscall(child)), + ); + // Then get the ptrace event for the process exiting + assert!(ptrace::cont(child, None).is_ok()); + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::PtraceEvent(child, SIGTRAP, Event::PTRACE_EVENT_EXIT as i32)), + ); + // Finally get the normal wait() result, now that the process has exited + assert!(ptrace::cont(child, None).is_ok()); + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::Exited(child, 0)), + ); + } + #[test] fn test_wait_ptrace() { require_capability!("test_wait_ptrace", CAP_SYS_PTRACE); @@ -101,7 +203,19 @@ mod ptrace { match unsafe{fork()}.expect("Error: Fork Failed") { Child => ptrace_child(), - Parent { child } => ptrace_parent(child), + Parent { child } => ptrace_wait_parent(child), + } + } + + #[test] + #[cfg(not(target_env = "uclibc"))] + fn test_waitid_ptrace() { + require_capability!("test_waitid_ptrace", CAP_SYS_PTRACE); + let _m = crate::FORK_MTX.lock(); + + match unsafe{fork()}.expect("Error: Fork Failed") { + Child => ptrace_child(), + Parent { child } => ptrace_waitid_parent(child), } } } From f0f67954fe4a0d279c5a9483c6636020863de75a Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 13 Mar 2022 16:16:25 -0600 Subject: [PATCH 067/358] Fix a panic in Linkaddr::addr The function assumed something about the values of the sockaddr_dl's fields. But because the inner type is public, we musn't do that. The only solution is to change the function's signature to return an Option. --- CHANGELOG.md | 2 ++ src/sys/socket/addr.rs | 71 +++++++++++++++++++++++++++++------------- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ad743cba6..2e2e06b2e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - `InetAddr::from_std` now sets the `sin_len`/`sin6_len` fields on the BSDs. (#[1642](https://github.com/nix-rust/nix/pull/1642)) +- Fixed a panic in `LinkAddr::addr`. That function now returns an `Option`. + (#[1675](https://github.com/nix-rust/nix/pull/1675)) ### Removed diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 51999a3d9e..9fd9e30acd 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1446,33 +1446,38 @@ mod datalink { } /// Physical-layer address (MAC) - pub fn addr(&self) -> [u8; 6] { + pub fn addr(&self) -> Option<[u8; 6]> { let nlen = self.nlen(); let data = self.0.sdl_data; - assert!(!self.is_empty()); - - [ - data[nlen] as u8, - data[nlen + 1] as u8, - data[nlen + 2] as u8, - data[nlen + 3] as u8, - data[nlen + 4] as u8, - data[nlen + 5] as u8, - ] + if self.is_empty() { + None + } else { + Some([ + data[nlen] as u8, + data[nlen + 1] as u8, + data[nlen + 2] as u8, + data[nlen + 3] as u8, + data[nlen + 4] as u8, + data[nlen + 5] as u8, + ]) + } } } impl fmt::Display for LinkAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let addr = self.addr(); - write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", - addr[0], - addr[1], - addr[2], - addr[3], - addr[4], - addr[5]) + if let Some(addr) = self.addr() { + write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", + addr[0], + addr[1], + addr[2], + addr[3], + addr[4], + addr[5]) + } else { + Ok(()) + } } } } @@ -1558,6 +1563,28 @@ mod tests { target_os = "openbsd"))] use super::*; + /// Don't panic when trying to display an empty datalink address + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[test] + fn test_datalink_display() { + let la = LinkAddr(libc::sockaddr_dl{ + sdl_len: 56, + sdl_family: 18, + sdl_index: 5, + sdl_type: 24, + sdl_nlen: 3, + sdl_alen: 0, + sdl_slen: 0, + .. unsafe{mem::zeroed()} + }); + format!("{}", la); + } + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -1593,7 +1620,8 @@ mod tests { match sock_addr { SockAddr::Link(ether_addr) => { - assert_eq!(ether_addr.addr(), [24u8, 101, 144, 221, 76, 176]); + assert_eq!(ether_addr.addr(), + Some([24u8, 101, 144, 221, 76, 176])); }, _ => { unreachable!() } }; @@ -1615,7 +1643,8 @@ mod tests { match sock_addr { SockAddr::Link(ether_addr) => { - assert_eq!(ether_addr.addr(), [24u8, 101, 144, 221, 76, 176]); + assert_eq!(ether_addr.addr(), + Some([24u8, 101, 144, 221, 76, 176])); }, _ => { unreachable!() } }; From e08c47cf1ee92381d7cc43a16db44d4f25fe74f8 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 13 Mar 2022 16:36:34 -0600 Subject: [PATCH 068/358] Fix the build on DragonflyBSD with -Zminimal-versions --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 039341d463..e5b0831e66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.114", features = [ "extra_traits" ] } +libc = { version = "0.2.115", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" From cf628ca60907cbd50dfc30286b3ed3cdb6560ab2 Mon Sep 17 00:00:00 2001 From: Arnavion Date: Sun, 13 Mar 2022 17:33:02 -0700 Subject: [PATCH 069/358] Change getrlimit and setrlimit to use rlim_t directly. Fixes #1666 --- CHANGELOG.md | 3 +++ src/sys/resource.rs | 37 ++++++++++++++++++------------------- test/test_resource.rs | 4 ++-- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e2e06b2e5..7f59926f7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Removed the the `PATH_MAX` restriction from APIs accepting paths. Paths will now be allocated on the heap if they are too long. In addition, large instruction count improvements (~30x) were made to path handling. +- Changed `getrlimit` and `setrlimit` to use `rlim_t` directly + instead of `Option`. + (#[1668](https://github.com/nix-rust/nix/pull/1668)) ### Fixed diff --git a/src/sys/resource.rs b/src/sys/resource.rs index ba206aa208..fca7418bfa 100644 --- a/src/sys/resource.rs +++ b/src/sys/resource.rs @@ -8,7 +8,7 @@ use std::mem; cfg_if! { if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ - use libc::{__rlimit_resource_t, rlimit, RLIM_INFINITY}; + use libc::{__rlimit_resource_t, rlimit}; } else if #[cfg(any( target_os = "freebsd", target_os = "openbsd", @@ -19,7 +19,7 @@ cfg_if! { target_os = "dragonfly", all(target_os = "linux", not(target_env = "gnu")) ))]{ - use libc::{c_int, rlimit, RLIM_INFINITY}; + use libc::{c_int, rlimit}; } } @@ -173,8 +173,8 @@ libc_enum! { /// Get the current processes resource limits /// -/// A value of `None` indicates the value equals to `RLIM_INFINITY` which means -/// there is no limit. +/// The special value `RLIM_INFINITY` indicates that no limit will be +/// enforced. /// /// # Parameters /// @@ -186,8 +186,8 @@ libc_enum! { /// # use nix::sys::resource::{getrlimit, Resource}; /// /// let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); -/// println!("current soft_limit: {:?}", soft_limit); -/// println!("current hard_limit: {:?}", hard_limit); +/// println!("current soft_limit: {}", soft_limit); +/// println!("current hard_limit: {}", hard_limit); /// ``` /// /// # References @@ -195,7 +195,7 @@ libc_enum! { /// [getrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215) /// /// [`Resource`]: enum.Resource.html -pub fn getrlimit(resource: Resource) -> Result<(Option, Option)> { +pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> { let mut old_rlim = mem::MaybeUninit::::uninit(); cfg_if! { @@ -208,7 +208,7 @@ pub fn getrlimit(resource: Resource) -> Result<(Option, Option)> Errno::result(res).map(|_| { let rlimit { rlim_cur, rlim_max } = unsafe { old_rlim.assume_init() }; - (Some(rlim_cur), Some(rlim_max)) + (rlim_cur, rlim_max) }) } @@ -218,21 +218,20 @@ pub fn getrlimit(resource: Resource) -> Result<(Option, Option)> /// /// * `resource`: The [`Resource`] that we want to set the limits of. /// * `soft_limit`: The value that the kernel enforces for the corresponding -/// resource. Note: `None` input will be replaced by constant `RLIM_INFINITY`. +/// resource. /// * `hard_limit`: The ceiling for the soft limit. Must be lower or equal to -/// the current hard limit for non-root users. Note: `None` input will be -/// replaced by constant `RLIM_INFINITY`. +/// the current hard limit for non-root users. /// -/// > Note: for some os (linux_gnu), setting hard_limit to `RLIM_INFINITY` can -/// > results `EPERM` Error. So you will need to set the number explicitly. +/// The special value `RLIM_INFINITY` indicates that no limit will be +/// enforced. /// /// # Examples /// /// ``` /// # use nix::sys::resource::{setrlimit, Resource}; /// -/// let soft_limit = Some(512); -/// let hard_limit = Some(1024); +/// let soft_limit = 512; +/// let hard_limit = 1024; /// setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); /// ``` /// @@ -245,12 +244,12 @@ pub fn getrlimit(resource: Resource) -> Result<(Option, Option)> /// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`. pub fn setrlimit( resource: Resource, - soft_limit: Option, - hard_limit: Option, + soft_limit: rlim_t, + hard_limit: rlim_t, ) -> Result<()> { let new_rlim = rlimit { - rlim_cur: soft_limit.unwrap_or(RLIM_INFINITY), - rlim_max: hard_limit.unwrap_or(RLIM_INFINITY), + rlim_cur: soft_limit, + rlim_max: hard_limit, }; cfg_if! { if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{ diff --git a/test/test_resource.rs b/test/test_resource.rs index 5969750091..c89d601e27 100644 --- a/test/test_resource.rs +++ b/test/test_resource.rs @@ -12,9 +12,9 @@ use nix::sys::resource::{getrlimit, setrlimit, Resource}; #[test] #[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))] pub fn test_resource_limits_nofile() { - let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); + let (mut soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); - let soft_limit = Some(soft_limit.map_or(1024, |v| v - 1)); + soft_limit -= 1; assert_ne!(soft_limit, hard_limit); setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); From d97e292a5da5cb74f7a7c901e882fca022c387a4 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 13 Mar 2022 22:57:00 -0600 Subject: [PATCH 070/358] Use the same signature for LinkAddr::addr on all platforms This should've been done as part of #1675 --- CHANGELOG.md | 1 + src/sys/socket/addr.rs | 26 +++++++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f59926f7e..e54639b79f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,6 +81,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1642](https://github.com/nix-rust/nix/pull/1642)) - Fixed a panic in `LinkAddr::addr`. That function now returns an `Option`. (#[1675](https://github.com/nix-rust/nix/pull/1675)) + (#[1677](https://github.com/nix-rust/nix/pull/1677)) ### Removed diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 9fd9e30acd..7803ec76c7 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1351,28 +1351,32 @@ mod datalink { } /// Physical-layer address (MAC) - pub fn addr(&self) -> [u8; 6] { - [ + // Returns an Option just for cross-platform compatibility + pub fn addr(&self) -> Option<[u8; 6]> { + Some([ self.0.sll_addr[0] as u8, self.0.sll_addr[1] as u8, self.0.sll_addr[2] as u8, self.0.sll_addr[3] as u8, self.0.sll_addr[4] as u8, self.0.sll_addr[5] as u8, - ] + ]) } } impl fmt::Display for LinkAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let addr = self.addr(); - write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", - addr[0], - addr[1], - addr[2], - addr[3], - addr[4], - addr[5]) + if let Some(addr) = self.addr() { + write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", + addr[0], + addr[1], + addr[2], + addr[3], + addr[4], + addr[5]) + } else { + Ok(()) + } } } } From 70f614fbd6a8c17c0b05e3e65f282c8dbbd73abe Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 19 Mar 2022 22:11:20 -0600 Subject: [PATCH 071/358] [skip ci] spellcheck a comment for sethostname --- src/unistd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 8da4f93238..272fb0cd9d 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -943,8 +943,8 @@ feature! { /// /// Given a name, attempt to update the system host name to the given string. /// On some systems, the host name is limited to as few as 64 bytes. An error -/// will be return if the name is not valid or the current process does not have -/// permissions to update the host name. +/// will be returned if the name is not valid or the current process does not +/// have permissions to update the host name. #[cfg(not(target_os = "redox"))] pub fn sethostname>(name: S) -> Result<()> { // Handle some differences in type of the len arg across platforms. From ff6f8b8a26c8d61f4341e441acf405402b46a430 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 20 Mar 2022 09:24:21 -0500 Subject: [PATCH 072/358] Redox renamed sigaction.sa_handler to .sa_sigaction --- Cargo.toml | 2 +- src/sys/signal.rs | 36 ++---------------------------------- 2 files changed, 3 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e5b0831e66..1e2aad22cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.115", features = [ "extra_traits" ] } +libc = { version = "0.2.121", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" diff --git a/src/sys/signal.rs b/src/sys/signal.rs index f10a213339..f982b4e79b 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -670,21 +670,12 @@ impl SigAction { /// is the `SigAction` variant). `mask` specifies other signals to block during execution of /// the signal-catching function. pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction { - #[cfg(target_os = "redox")] - unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) { - (*p).sa_handler = match handler { - SigHandler::SigDfl => libc::SIG_DFL, - SigHandler::SigIgn => libc::SIG_IGN, - SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize, - }; - } - - #[cfg(not(target_os = "redox"))] unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) { (*p).sa_sigaction = match handler { SigHandler::SigDfl => libc::SIG_DFL, SigHandler::SigIgn => libc::SIG_IGN, SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize, + #[cfg(not(target_os = "redox"))] SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize, }; } @@ -716,12 +707,11 @@ impl SigAction { } /// Returns the action's handler. - #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub fn handler(&self) -> SigHandler { match self.sigaction.sa_sigaction { libc::SIG_DFL => SigHandler::SigDfl, libc::SIG_IGN => SigHandler::SigIgn, + #[cfg(not(target_os = "redox"))] p if self.flags().contains(SaFlags::SA_SIGINFO) => SigHandler::SigAction( // Safe for one of two reasons: @@ -749,28 +739,6 @@ impl SigAction { as extern fn(libc::c_int)), } } - - /// Returns the action's handler. - #[cfg(target_os = "redox")] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn handler(&self) -> SigHandler { - match self.sigaction.sa_handler { - libc::SIG_DFL => SigHandler::SigDfl, - libc::SIG_IGN => SigHandler::SigIgn, - p => SigHandler::Handler( - // Safe for one of two reasons: - // * The SigHandler was created by SigHandler::new, in which - // case the pointer is correct, or - // * The SigHandler was created by signal or sigaction, which - // are unsafe functions, so the caller should've somehow - // ensured that it is correctly initialized. - unsafe{ - *(&p as *const usize - as *const extern fn(libc::c_int)) - } - as extern fn(libc::c_int)), - } - } } /// Changes the action taken by a process on receipt of a specific signal. From e3983d16208333b33382e40f116c0de25bb90469 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 20 Mar 2022 09:26:11 -0500 Subject: [PATCH 073/358] uclibc uses a u32 for RLIMIT definitions --- src/sys/resource.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/resource.rs b/src/sys/resource.rs index fca7418bfa..76ceaf5b90 100644 --- a/src/sys/resource.rs +++ b/src/sys/resource.rs @@ -39,7 +39,7 @@ libc_enum! { // // https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html // https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs - #[cfg_attr(all(target_os = "linux", target_env = "gnu"), repr(u32))] + #[cfg_attr(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), repr(u32))] #[cfg_attr(any( target_os = "freebsd", target_os = "openbsd", @@ -48,7 +48,7 @@ libc_enum! { target_os = "ios", target_os = "android", target_os = "dragonfly", - all(target_os = "linux", not(target_env = "gnu")) + all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc"))) ), repr(i32))] #[non_exhaustive] pub enum Resource { From 76d70b4b25ef499c8bb0a322590eb86e3370b548 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 21 Dec 2021 06:10:50 -0700 Subject: [PATCH 074/358] Replace the Sockaddr enum with a union The SockAddr enum is quite large, and the user must allocate space for the whole thing even though he usually knows what type he needs. Furthermore, thanks to the sa_family field, the sockaddr types are basically an enum even in C. So replace the ungainly enum with a SockaddrLike trait implemented by all sockaddr types and a SockaddrStorage union that has safe accessors. Also, deprecate InetAddr, which only existed to support SockAddr. Supplants #1504 Fixes #1544 --- CHANGELOG.md | 3 + src/ifaddrs.rs | 24 +- src/lib.rs | 1 + src/sys/socket/addr.rs | 1238 ++++++++++++++++++++++++++++++++++---- src/sys/socket/mod.rs | 197 +++--- test/sys/test_socket.rs | 320 +++++----- test/sys/test_sockopt.rs | 9 +- 7 files changed, 1402 insertions(+), 390 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e54639b79f..737148af47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Changed `getrlimit` and `setrlimit` to use `rlim_t` directly instead of `Option`. (#[1668](https://github.com/nix-rust/nix/pull/1668)) +- Deprecated `InetAddr` and `SockAddr` in favor of `SockaddrIn`, `SockaddrIn6`, + and `SockaddrStorage`. + (#[1684](https://github.com/nix-rust/nix/pull/1684)) ### Fixed diff --git a/src/ifaddrs.rs b/src/ifaddrs.rs index ed6328f3ef..f834d30762 100644 --- a/src/ifaddrs.rs +++ b/src/ifaddrs.rs @@ -10,7 +10,7 @@ use std::mem; use std::option::Option; use crate::{Result, Errno}; -use crate::sys::socket::SockAddr; +use crate::sys::socket::{SockaddrLike, SockaddrStorage}; use crate::net::if_::*; /// Describes a single address for an interface as returned by `getifaddrs`. @@ -21,13 +21,13 @@ pub struct InterfaceAddress { /// Flags as from `SIOCGIFFLAGS` ioctl pub flags: InterfaceFlags, /// Network address of this interface - pub address: Option, + pub address: Option, /// Netmask of this interface - pub netmask: Option, + pub netmask: Option, /// Broadcast address of this interface, if applicable - pub broadcast: Option, + pub broadcast: Option, /// Point-to-point destination address - pub destination: Option, + pub destination: Option, } cfg_if! { @@ -46,8 +46,8 @@ impl InterfaceAddress { /// Create an `InterfaceAddress` from the libc struct. fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress { let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) }; - let address = unsafe { SockAddr::from_libc_sockaddr(info.ifa_addr) }; - let netmask = unsafe { SockAddr::from_libc_sockaddr(info.ifa_netmask) }; + let address = unsafe { SockaddrStorage::from_raw(info.ifa_addr, None) }; + let netmask = unsafe { SockaddrStorage::from_raw(info.ifa_netmask, None) }; let mut addr = InterfaceAddress { interface_name: ifname.to_string_lossy().to_string(), flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32), @@ -59,9 +59,9 @@ impl InterfaceAddress { let ifu = get_ifu_from_sockaddr(info); if addr.flags.contains(InterfaceFlags::IFF_POINTOPOINT) { - addr.destination = unsafe { SockAddr::from_libc_sockaddr(ifu) }; + addr.destination = unsafe { SockaddrStorage::from_raw(ifu, None) }; } else if addr.flags.contains(InterfaceFlags::IFF_BROADCAST) { - addr.broadcast = unsafe { SockAddr::from_libc_sockaddr(ifu) }; + addr.broadcast = unsafe { SockaddrStorage::from_raw(ifu, None) }; } addr @@ -103,9 +103,9 @@ impl Iterator for InterfaceAddressIterator { /// Note that the underlying implementation differs between OSes. Only the /// most common address families are supported by the nix crate (due to /// lack of time and complexity of testing). The address family is encoded -/// in the specific variant of `SockAddr` returned for the fields `address`, -/// `netmask`, `broadcast`, and `destination`. For any entry not supported, -/// the returned list will contain a `None` entry. +/// in the specific variant of `SockaddrStorage` returned for the fields +/// `address`, `netmask`, `broadcast`, and `destination`. For any entry not +/// supported, the returned list will contain a `None` entry. /// /// # Example /// ``` diff --git a/src/lib.rs b/src/lib.rs index 6809382978..172ca3a1d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ //! * `reboot` - Reboot the system //! * `resource` - Process resource limits //! * `sched` - Manipulate process's scheduling +//! * `socket` - Sockets, whether for networking or local use //! * `signal` - Send and receive signals to processes //! * `term` - Terminal control APIs //! * `time` - Query the operating system's clocks diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 7803ec76c7..9d22beea58 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -34,6 +34,11 @@ pub use self::vsock::VsockAddr; /// These constants specify the protocol family to be used /// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) +/// +/// # References +/// +/// [address_families(7)](https://man7.org/linux/man-pages/man7/address_families.7.html) +// Should this be u8? #[repr(i32)] #[non_exhaustive] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] @@ -68,9 +73,15 @@ pub enum AddressFamily { Ipx = libc::AF_IPX, /// AppleTalk AppleTalk = libc::AF_APPLETALK, + /// AX.25 packet layer protocol. + /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] NetRom = libc::AF_NETROM, + /// Can't be used for creating sockets; mostly used for bridge + /// links in + /// [rtnetlink(7)](https://man7.org/linux/man-pages/man7/rtnetlink.7.html) + /// protocol commands. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Bridge = libc::AF_BRIDGE, @@ -82,77 +93,108 @@ pub enum AddressFamily { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] X25 = libc::AF_X25, + /// RATS (Radio Amateur Telecommunications Society) Open + /// Systems environment (ROSE) AX.25 packet layer protocol. + /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Rose = libc::AF_ROSE, + /// DECet protocol sockets. Decnet = libc::AF_DECnet, + /// Reserved for "802.2LLC project"; never used. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] NetBeui = libc::AF_NETBEUI, + /// This was a short-lived (between Linux 2.1.30 and + /// 2.1.99pre2) protocol family for firewall upcalls. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Security = libc::AF_SECURITY, + /// Key management protocol. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Key = libc::AF_KEY, + #[allow(missing_docs)] // Not documented anywhere that I can find #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Ash = libc::AF_ASH, + /// Acorn Econet protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Econet = libc::AF_ECONET, + /// Access to ATM Switched Virtual Circuits #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] AtmSvc = libc::AF_ATMSVC, + /// Reliable Datagram Sockets (RDS) protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Rds = libc::AF_RDS, + /// IBM SNA Sna = libc::AF_SNA, + /// Socket interface over IrDA #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Irda = libc::AF_IRDA, + /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE) #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Pppox = libc::AF_PPPOX, + /// Legacy protocol for wide area network (WAN) connectivity that was used + /// by Sangoma WAN cards #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Wanpipe = libc::AF_WANPIPE, + /// Logical link control (IEEE 802.2 LLC) protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Llc = libc::AF_LLC, + /// InfiniBand native addressing #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] #[cfg_attr(docsrs, doc(cfg(all())))] Ib = libc::AF_IB, + /// Multiprotocol Label Switching #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] #[cfg_attr(docsrs, doc(cfg(all())))] Mpls = libc::AF_MPLS, + /// Controller Area Network automotive bus protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Can = libc::AF_CAN, + /// TIPC, "cluster domain sockets" protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Tipc = libc::AF_TIPC, + /// Bluetooth low-level socket protocol #[cfg(not(any(target_os = "illumos", target_os = "ios", target_os = "macos", target_os = "solaris")))] #[cfg_attr(docsrs, doc(cfg(all())))] Bluetooth = libc::AF_BLUETOOTH, + /// IUCV (inter-user communication vehicle) z/VM protocol for + /// hypervisor-guest interaction #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Iucv = libc::AF_IUCV, + /// Rx, Andrew File System remote procedure call protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] RxRpc = libc::AF_RXRPC, + /// New "modular ISDN" driver interface protocol #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] #[cfg_attr(docsrs, doc(cfg(all())))] Isdn = libc::AF_ISDN, + /// Nokia cellular modem IPC/RPC interface #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Phonet = libc::AF_PHONET, + /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Ieee802154 = libc::AF_IEEE802154, + /// Ericsson's Communication CPU to Application CPU interface (CAIF) + /// protocol. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Caif = libc::AF_CAIF, @@ -160,12 +202,15 @@ pub enum AddressFamily { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Alg = libc::AF_ALG, + /// Near field communication #[cfg(target_os = "linux")] #[cfg_attr(docsrs, doc(cfg(all())))] Nfc = libc::AF_NFC, + /// VMWare VSockets protocol for hypervisor-guest interaction. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Vsock = libc::AF_VSOCK, + /// ARPANet IMP addresses #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -174,6 +219,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] ImpLink = libc::AF_IMPLINK, + /// PUP protocols, e.g. BSP #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -182,6 +228,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Pup = libc::AF_PUP, + /// MIT CHAOS protocols #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -190,12 +237,14 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Chaos = libc::AF_CHAOS, + /// Novell and Xerox protocol #[cfg(any(target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Ns = libc::AF_NS, + #[allow(missing_docs)] // Not documented anywhere that I can find #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -204,6 +253,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Iso = libc::AF_ISO, + /// Bell Labs virtual circuit switch ? #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -212,6 +262,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Datakit = libc::AF_DATAKIT, + /// CCITT protocols, X.25 etc #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -220,6 +271,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Ccitt = libc::AF_CCITT, + /// DEC Direct data link interface #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -228,6 +280,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Dli = libc::AF_DLI, + #[allow(missing_docs)] // Not documented anywhere that I can find #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -236,6 +289,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Lat = libc::AF_LAT, + /// NSC Hyperchannel #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -244,6 +298,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Hylink = libc::AF_HYLINK, + /// Link layer interface #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -253,6 +308,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Link = libc::AF_LINK, + /// connection-oriented IP, aka ST II #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -261,6 +317,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Coip = libc::AF_COIP, + /// Computer Network Technology #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -269,6 +326,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Cnt = libc::AF_CNT, + /// Native ATM access #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -318,12 +376,19 @@ impl AddressFamily { feature! { #![feature = "net"] +#[deprecated( + since = "0.24.0", + note = "use SockaddrIn, SockaddrIn6, or SockaddrStorage instead" +)] +#[allow(missing_docs)] // Since they're all deprecated anyway #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum InetAddr { V4(libc::sockaddr_in), V6(libc::sockaddr_in6), } +#[allow(missing_docs)] // It's deprecated anyway +#[allow(deprecated)] impl InetAddr { #[allow(clippy::needless_update)] // It isn't needless on all OSes pub fn from_std(std: &net::SocketAddr) -> InetAddr { @@ -417,6 +482,7 @@ impl InetAddr { } } +#[allow(deprecated)] impl fmt::Display for InetAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -431,12 +497,14 @@ impl fmt::Display for InetAddr { * ===== IpAddr ===== * */ +#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum IpAddr { V4(Ipv4Addr), V6(Ipv6Addr), } +#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 impl IpAddr { /// Create a new IpAddr that contains an IPv4 address. /// @@ -484,10 +552,12 @@ impl fmt::Display for IpAddr { * */ +#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct Ipv4Addr(pub libc::in_addr); +#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 impl Ipv4Addr { #[allow(clippy::identity_op)] // More readable this way pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { @@ -534,6 +604,7 @@ impl fmt::Display for Ipv4Addr { * */ +#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct Ipv6Addr(pub libc::in6_addr); @@ -554,6 +625,7 @@ macro_rules! to_u16_array { } } +#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 impl Ipv6Addr { #[allow(clippy::many_single_char_names)] #[allow(clippy::too_many_arguments)] @@ -586,6 +658,7 @@ impl fmt::Display for Ipv6Addr { /// A wrapper around `sockaddr_un`. #[derive(Clone, Copy, Debug)] +#[repr(C)] pub struct UnixAddr { // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts sun: libc::sockaddr_un, @@ -799,6 +872,56 @@ impl UnixAddr { } } +impl private::SockaddrLikePriv for UnixAddr {} +impl SockaddrLike for UnixAddr { + #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + fn len(&self) -> libc::socklen_t { + self.sun_len.into() + } + + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) + -> Option where Self: Sized + { + if let Some(l) = len { + if (l as usize) < offset_of!(libc::sockaddr_un, sun_path) || + l > u8::MAX as libc::socklen_t + { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_UNIX as i32 { + return None; + } + let mut su: libc::sockaddr_un = mem::zeroed(); + let sup = &mut su as *mut libc::sockaddr_un as *mut u8; + cfg_if!{ + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] { + let su_len = len.unwrap_or( + mem::size_of::() as libc::socklen_t + ); + } else { + let su_len = len.unwrap_or((*addr).sa_len as libc::socklen_t); + } + }; + ptr::copy(addr as *const u8, sup, su_len as usize); + Some(Self::from_raw_parts(su, su_len as u8)) + } +} + +impl AsRef for UnixAddr { + fn as_ref(&self) -> &libc::sockaddr_un { + &self.sun + } +} + #[cfg(any(target_os = "android", target_os = "linux"))] fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result { use fmt::Write; @@ -836,8 +959,699 @@ impl Hash for UnixAddr { } } +/// Anything that, in C, can be cast back and forth to `sockaddr`. +/// +/// Most implementors also implement `AsRef` to access their +/// inner type read-only. +#[allow(clippy::len_without_is_empty)] +pub trait SockaddrLike: private::SockaddrLikePriv { + /// Returns a raw pointer to the inner structure. Useful for FFI. + fn as_ptr(&self) -> *const libc::sockaddr { + self as *const Self as *const libc::sockaddr + } + + /// Unsafe constructor from a variable length source + /// + /// Some C APIs from provide `len`, and others do not. If it's provided it + /// will be validated. If not, it will be guessed based on the family. + /// + /// # Safety + /// + /// `addr` must be valid for the specific type of sockaddr. `len`, if + /// present, must be the length of valid data in `addr`. + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) + -> Option where Self: Sized; + + /// Return the address family of this socket + /// + /// # Examples + /// One common use is to match on the family of a union type, like this: + /// ``` + /// # use nix::sys::socket::*; + /// let fd = socket(AddressFamily::Inet, SockType::Stream, + /// SockFlag::empty(), None).unwrap(); + /// let ss: SockaddrStorage = getsockname(fd).unwrap(); + /// match ss.family().unwrap() { + /// AddressFamily::Inet => println!("{}", ss.as_sockaddr_in().unwrap()), + /// AddressFamily::Inet6 => println!("{}", ss.as_sockaddr_in6().unwrap()), + /// _ => println!("Unexpected address family") + /// } + /// ``` + fn family(&self) -> Option { + // Safe since all implementors have a sa_family field at the same + // address, and they're all repr(C) + AddressFamily::from_i32( + unsafe { + (*(self as *const Self as *const libc::sockaddr)).sa_family as i32 + } + ) + } + + cfg_if! { + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] { + /// Return the length of valid data in the sockaddr structure. + /// + /// For fixed-size sockaddrs, this should be the size of the + /// structure. But for variable-sized types like [`UnixAddr`] it + /// may be less. + fn len(&self) -> libc::socklen_t { + // Safe since all implementors have a sa_len field at the same + // address, and they're all repr(transparent). + // Robust for all implementors. + unsafe { + (*(self as *const Self as *const libc::sockaddr)).sa_len + }.into() + } + } else { + /// Return the length of valid data in the sockaddr structure. + /// + /// For fixed-size sockaddrs, this should be the size of the + /// structure. But for variable-sized types like [`UnixAddr`] it + /// may be less. + fn len(&self) -> libc::socklen_t { + // No robust default implementation is possible without an + // sa_len field. Implementors with a variable size must + // override this method. + mem::size_of_val(self) as libc::socklen_t + } + } + } + + /// Return the available space in the structure + fn size() -> libc::socklen_t where Self: Sized { + mem::size_of::() as libc::socklen_t + } +} + +impl private::SockaddrLikePriv for () { + fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { + ptr::null_mut() + } +} + +/// `()` can be used in place of a real Sockaddr when no address is expected, +/// for example for a field of `Option where S: SockaddrLike`. +// If this RFC ever stabilizes, then ! will be a better choice. +// https://github.com/rust-lang/rust/issues/35121 +impl SockaddrLike for () { + fn as_ptr(&self) -> *const libc::sockaddr { + ptr::null() + } + + unsafe fn from_raw(_: *const libc::sockaddr, _: Option) + -> Option where Self: Sized + { + None + } + + fn family(&self) -> Option { + None + } + + fn len(&self) -> libc::socklen_t { + 0 + } +} + +/// An IPv4 socket address +// This is identical to net::SocketAddrV4. But the standard library +// doesn't allow direct access to the libc fields, which we need. So we +// reimplement it here. +#[cfg(feature = "net")] +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct SockaddrIn(libc::sockaddr_in); + +#[cfg(feature = "net")] +impl SockaddrIn { + /// Returns the IP address associated with this socket address, in native + /// endian. + pub const fn ip(&self) -> libc::in_addr_t { + u32::from_be(self.0.sin_addr.s_addr) + } + + /// Creates a new socket address from IPv4 octets and a port number. + pub fn new(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self { + Self(libc::sockaddr_in { + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + sin_len: Self::size() as u8, + sin_family: AddressFamily::Inet as sa_family_t, + sin_port: u16::to_be(port), + sin_addr: libc::in_addr { + s_addr: u32::from_ne_bytes([a, b, c, d]) + }, + sin_zero: unsafe{mem::zeroed()} + }) + } + + /// Returns the port number associated with this socket address, in native + /// endian. + pub const fn port(&self) -> u16 { + u16::from_be(self.0.sin_port) + } +} + +#[cfg(feature = "net")] +impl private::SockaddrLikePriv for SockaddrIn {} +#[cfg(feature = "net")] +impl SockaddrLike for SockaddrIn { + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_INET as i32 { + return None; + } + Some(SockaddrIn(*(addr as *const libc::sockaddr_in))) + } +} + +#[cfg(feature = "net")] +impl AsRef for SockaddrIn { + fn as_ref(&self) -> &libc::sockaddr_in { + &self.0 + } +} + +#[cfg(feature = "net")] +impl fmt::Display for SockaddrIn { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let ne = u32::from_be(self.0.sin_addr.s_addr); + let port = u16::from_be(self.0.sin_port); + write!(f, "{}.{}.{}.{}:{}", + ne >> 24, + (ne >> 16) & 0xFF, + (ne >> 8) & 0xFF, + ne & 0xFF, + port) + } +} + +#[cfg(feature = "net")] +impl From for SockaddrIn { + fn from(addr: net::SocketAddrV4) -> Self { + Self(libc::sockaddr_in{ + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "haiku", target_os = "hermit", + target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd"))] + sin_len: mem::size_of::() as u8, + sin_family: AddressFamily::Inet as sa_family_t, + sin_port: addr.port().to_be(), // network byte order + sin_addr: Ipv4Addr::from_std(addr.ip()).0, + .. unsafe { mem::zeroed() } + }) + } +} + +#[cfg(feature = "net")] +impl std::str::FromStr for SockaddrIn { + type Err = net::AddrParseError; + + fn from_str(s: &str) -> std::result::Result { + net::SocketAddrV4::from_str(s).map(SockaddrIn::from) + } +} + +/// An IPv6 socket address +#[cfg(feature = "net")] +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct SockaddrIn6(libc::sockaddr_in6); + +#[cfg(feature = "net")] +impl SockaddrIn6 { + /// Returns the flow information associated with this address. + pub const fn flowinfo(&self) -> u32 { + self.0.sin6_flowinfo + } + + /// Returns the IP address associated with this socket address. + pub fn ip(&self) -> net::Ipv6Addr { + net::Ipv6Addr::from(self.0.sin6_addr.s6_addr) + } + + /// Returns the port number associated with this socket address, in native + /// endian. + pub const fn port(&self) -> u16 { + u16::from_be(self.0.sin6_port) + } + + /// Returns the scope ID associated with this address. + pub const fn scope_id(&self) -> u32 { + self.0.sin6_scope_id + } +} + +#[cfg(feature = "net")] +impl private::SockaddrLikePriv for SockaddrIn6 {} +#[cfg(feature = "net")] +impl SockaddrLike for SockaddrIn6 { + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_INET6 as i32 { + return None; + } + Some(SockaddrIn6(*(addr as *const libc::sockaddr_in6))) + } +} + +#[cfg(feature = "net")] +impl AsRef for SockaddrIn6 { + fn as_ref(&self) -> &libc::sockaddr_in6 { + &self.0 + } +} + +#[cfg(feature = "net")] +impl fmt::Display for SockaddrIn6 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // These things are really hard to display properly. Easier to let std + // do it. + let std = net::SocketAddrV6::new(self.ip(), self.port(), + self.flowinfo(), self.scope_id()); + std.fmt(f) + } +} + +#[cfg(feature = "net")] +impl From for SockaddrIn6 { + fn from(addr: net::SocketAddrV6) -> Self { + #[allow(clippy::needless_update)] // It isn't needless on Illumos + Self(libc::sockaddr_in6{ + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "haiku", target_os = "hermit", + target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd"))] + sin6_len: mem::size_of::() as u8, + sin6_family: AddressFamily::Inet6 as sa_family_t, + sin6_port: addr.port().to_be(), // network byte order + sin6_addr: Ipv6Addr::from_std(addr.ip()).0, + sin6_flowinfo: addr.flowinfo(), // host byte order + sin6_scope_id: addr.scope_id(), // host byte order + .. unsafe { mem::zeroed() } + }) + } +} + +#[cfg(feature = "net")] +impl std::str::FromStr for SockaddrIn6 { + type Err = net::AddrParseError; + + fn from_str(s: &str) -> std::result::Result { + net::SocketAddrV6::from_str(s).map(SockaddrIn6::from) + } +} + + +/// A container for any sockaddr type +/// +/// Just like C's `sockaddr_storage`, this type is large enough to hold any type +/// of sockaddr. It can be used as an argument with functions like +/// [`bind`](super::bind) and [`getsockname`](super::getsockname). Though it is +/// a union, it can be safely accessed through the `as_*` methods. +/// +/// # Example +/// ``` +/// # use nix::sys::socket::*; +/// # use std::str::FromStr; +/// let localhost = SockaddrIn::from_str("127.0.0.1:8081").unwrap(); +/// let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), +/// None).unwrap(); +/// bind(fd, &localhost).expect("bind"); +/// let ss: SockaddrStorage = getsockname(fd).expect("getsockname"); +/// assert_eq!(&localhost, ss.as_sockaddr_in().unwrap()); +/// ``` +#[derive(Clone, Copy, Eq)] +#[repr(C)] +pub union SockaddrStorage { + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + alg: AlgAddr, + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + dl: LinkAddr, + #[cfg(any(target_os = "android", target_os = "linux"))] + nl: NetlinkAddr, + #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] + #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] + sctl: SysControlAddr, + #[cfg(feature = "net")] + sin: SockaddrIn, + #[cfg(feature = "net")] + sin6: SockaddrIn6, + ss: libc::sockaddr_storage, + su: UnixAddr, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + vsock: VsockAddr +} +impl private::SockaddrLikePriv for SockaddrStorage {} +impl SockaddrLike for SockaddrStorage { + unsafe fn from_raw(addr: *const libc::sockaddr, l: Option) + -> Option where Self: Sized + { + if addr.is_null() { + return None; + } + if let Some(len) = l { + let ulen = len as usize; + if ulen < offset_of!(libc::sockaddr, sa_data) || + ulen > mem::size_of::() { + None + } else{ + let mut ss: libc::sockaddr_storage = mem::zeroed(); + let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8; + ptr::copy(addr as *const u8, ssp, len as usize); + Some(Self{ss}) + } + } else { + // If length is not available and addr is of a fixed-length type, + // copy it. If addr is of a variable length type and len is not + // available, then there's nothing we can do. + match (*addr).sa_family as i32 { + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_ALG => AlgAddr::from_raw(addr, l) + .map(|alg| Self { alg}), + #[cfg(feature = "net")] + libc::AF_INET => SockaddrIn::from_raw(addr, l) + .map(|sin| Self{ sin}), + #[cfg(feature = "net")] + libc::AF_INET6 => SockaddrIn6::from_raw(addr, l) + .map(|sin6| Self{ sin6}), + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg(feature = "net")] + libc::AF_LINK => LinkAddr::from_raw(addr, l) + .map(|dl| Self{ dl}), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_NETLINK => NetlinkAddr::from_raw(addr, l) + .map(|nl| Self{ nl }), + #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg(feature = "net")] + libc::AF_PACKET => LinkAddr::from_raw(addr, l) + .map(|dl| Self{ dl}), + #[cfg(all(feature = "ioctl", + any(target_os = "ios", target_os = "macos")))] + libc::AF_SYSTEM => SysControlAddr::from_raw(addr, l) + .map(|sctl| Self {sctl}), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_VSOCK => VsockAddr::from_raw(addr, l) + .map(|vsock| Self{vsock}), + _ => None + } + } + } +} + +macro_rules! accessors { + ( + $fname:ident, + $fname_mut:ident, + $sockty:ty, + $family:expr, + $libc_ty:ty, + $field:ident) => + { + /// Safely and falliably downcast to an immutable reference + pub fn $fname(&self) -> Option<&$sockty> { + if self.family() == Some($family) && + self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t + { + // Safe because family and len are validated + Some(unsafe{&self.$field}) + } else { + None + } + } + + /// Safely and falliably downcast to a mutable reference + pub fn $fname_mut(&mut self) -> Option<&mut $sockty> { + if self.family() == Some($family) && + self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t + { + // Safe because family and len are validated + Some(unsafe{&mut self.$field}) + } else { + None + } + } + } +} + +impl SockaddrStorage { + #[cfg(any(target_os = "android", target_os = "linux"))] + accessors!{as_alg_addr, as_alg_addr_mut, AlgAddr, + AddressFamily::Alg, libc::sockaddr_alg, alg} + + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg(feature = "net")] + accessors!{ + as_link_addr, as_link_addr_mut, LinkAddr, + AddressFamily::Link, libc::sockaddr_dl, dl} + + #[cfg(feature = "net")] + accessors!{ + as_sockaddr_in, as_sockaddr_in_mut, SockaddrIn, + AddressFamily::Inet, libc::sockaddr_in, sin} + + #[cfg(feature = "net")] + accessors!{ + as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6, + AddressFamily::Inet6, libc::sockaddr_in6, sin6} + + #[cfg(any(target_os = "android", target_os = "linux"))] + accessors!{as_netlink_addr, as_netlink_addr_mut, NetlinkAddr, + AddressFamily::Netlink, libc::sockaddr_nl, nl} + + #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] + #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] + accessors!{as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr, + AddressFamily::System, libc::sockaddr_ctl, sctl} + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + accessors!{as_vsock_addr, as_vsock_addr_mut, VsockAddr, + AddressFamily::Vsock, libc::sockaddr_vm, vsock} +} + +impl fmt::Debug for SockaddrStorage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SockaddrStorage") + // Safe because sockaddr_storage has the least specific + // field types + .field("ss", unsafe{&self.ss}) + .finish() + } +} + +impl fmt::Display for SockaddrStorage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + unsafe { + match self.ss.ss_family as i32 { + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_ALG => self.alg.fmt(f), + #[cfg(feature = "net")] + libc::AF_INET => self.sin.fmt(f), + #[cfg(feature = "net")] + libc::AF_INET6 => self.sin6.fmt(f), + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg(feature = "net")] + libc::AF_LINK => self.dl.fmt(f), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_NETLINK => self.nl.fmt(f), + #[cfg(any(target_os = "android", + target_os = "linux", + target_os = "fuchsia" + ))] + #[cfg(feature = "net")] + libc::AF_PACKET => self.dl.fmt(f), + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(feature = "ioctl")] + libc::AF_SYSTEM => self.sctl.fmt(f), + libc::AF_UNIX => self.su.fmt(f), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_VSOCK => self.vsock.fmt(f), + _ => "

".fmt(f) + } + } + } +} + +#[cfg(feature = "net")] +impl From for SockaddrStorage { + fn from(s: net::SocketAddrV4) -> Self { + unsafe { + let mut ss: Self = mem::zeroed(); + ss.sin = SockaddrIn::from(s); + ss + } + } +} + +#[cfg(feature = "net")] +impl From for SockaddrStorage { + fn from(s: net::SocketAddrV6) -> Self { + unsafe { + let mut ss: Self = mem::zeroed(); + ss.sin6 = SockaddrIn6::from(s); + ss + } + } +} + +#[cfg(feature = "net")] +impl From for SockaddrStorage { + fn from(s: net::SocketAddr) -> Self { + match s { + net::SocketAddr::V4(sa4) => Self::from(sa4), + net::SocketAddr::V6(sa6) => Self::from(sa6), + } + } +} + +impl Hash for SockaddrStorage { + fn hash(&self, s: &mut H) { + unsafe { + match self.ss.ss_family as i32 { + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_ALG => self.alg.hash(s), + #[cfg(feature = "net")] + libc::AF_INET => self.sin.hash(s), + #[cfg(feature = "net")] + libc::AF_INET6 => self.sin6.hash(s), + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg(feature = "net")] + libc::AF_LINK => self.dl.hash(s), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_NETLINK => self.nl.hash(s), + #[cfg(any(target_os = "android", + target_os = "linux", + target_os = "fuchsia" + ))] + #[cfg(feature = "net")] + libc::AF_PACKET => self.dl.hash(s), + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(feature = "ioctl")] + libc::AF_SYSTEM => self.sctl.hash(s), + libc::AF_UNIX => self.su.hash(s), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_VSOCK => self.vsock.hash(s), + _ => self.ss.hash(s) + } + } + } +} + +impl PartialEq for SockaddrStorage { + fn eq(&self, other: &Self) -> bool { + unsafe { + match (self.ss.ss_family as i32, other.ss.ss_family as i32) { + #[cfg(any(target_os = "android", target_os = "linux"))] + (libc::AF_ALG, libc::AF_ALG) => self.alg == other.alg, + #[cfg(feature = "net")] + (libc::AF_INET, libc::AF_INET) => self.sin == other.sin, + #[cfg(feature = "net")] + (libc::AF_INET6, libc::AF_INET6) => self.sin6 == other.sin6, + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg(feature = "net")] + (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl, + #[cfg(any(target_os = "android", target_os = "linux"))] + (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl, + #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg(feature = "net")] + (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl, + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(feature = "ioctl")] + (libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl, + (libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su, + #[cfg(any(target_os = "android", target_os = "linux"))] + (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock, + _ => false, + } + } + } +} + +mod private { + pub trait SockaddrLikePriv { + /// Returns a mutable raw pointer to the inner structure. + /// + /// # Safety + /// + /// This method is technically safe, but modifying the inner structure's + /// `family` or `len` fields may result in violating Nix's invariants. + /// It is best to use this method only with foreign functions that do + /// not change the sockaddr type. + fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { + self as *mut Self as *mut libc::sockaddr + } + } +} + /// Represents a socket address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[deprecated( + since = "0.24.0", + note = "use SockaddrLike or SockaddrStorage instead" +)] +#[allow(missing_docs)] // Since they're all deprecated anyway +#[allow(deprecated)] #[non_exhaustive] pub enum SockAddr { #[cfg(feature = "net")] @@ -871,6 +1685,8 @@ pub enum SockAddr { Vsock(VsockAddr), } +#[allow(missing_docs)] // Since they're all deprecated anyway +#[allow(deprecated)] impl SockAddr { feature! { #![feature = "net"] @@ -1099,6 +1915,7 @@ impl SockAddr { } } +#[allow(deprecated)] impl fmt::Display for SockAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -1129,18 +1946,41 @@ impl fmt::Display for SockAddr { } } +#[cfg(not(target_os = "fuchsia"))] +#[cfg(feature = "net")] +#[allow(deprecated)] +impl private::SockaddrLikePriv for SockAddr {} +#[cfg(not(target_os = "fuchsia"))] +#[cfg(feature = "net")] +#[allow(deprecated)] +impl SockaddrLike for SockAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, _len: Option) + -> Option + { + Self::from_libc_sockaddr(addr) + } +} + #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub mod netlink { use crate::sys::socket::addr::AddressFamily; use libc::{sa_family_t, sockaddr_nl}; use std::{fmt, mem}; + use super::*; + /// Address for the Linux kernel user interface device. + /// + /// # References + /// + /// [netlink(7)](https://man7.org/linux/man-pages/man7/netlink.7.html) #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct NetlinkAddr(pub(in super::super) sockaddr_nl); impl NetlinkAddr { + /// Construct a new socket address from its port ID and multicast groups + /// mask. pub fn new(pid: u32, groups: u32) -> NetlinkAddr { let mut addr: sockaddr_nl = unsafe { mem::zeroed() }; addr.nl_family = AddressFamily::Netlink as sa_family_t; @@ -1150,15 +1990,40 @@ pub mod netlink { NetlinkAddr(addr) } + /// Return the socket's port ID. pub const fn pid(&self) -> u32 { self.0.nl_pid } + /// Return the socket's multicast groups mask pub const fn groups(&self) -> u32 { self.0.nl_groups } } + impl private::SockaddrLikePriv for NetlinkAddr {} + impl SockaddrLike for NetlinkAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_NETLINK as i32 { + return None; + } + Some(NetlinkAddr(*(addr as *const libc::sockaddr_nl))) + } + } + + impl AsRef for NetlinkAddr { + fn as_ref(&self) -> &libc::sockaddr_nl { + &self.0 + } + } + impl fmt::Display for NetlinkAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "pid: {} groups: {}", self.pid(), self.groups()) @@ -1173,11 +2038,36 @@ pub mod alg { use std::{fmt, mem, str}; use std::hash::{Hash, Hasher}; use std::ffi::CStr; + use super::*; + /// Socket address for the Linux kernel crypto API #[derive(Copy, Clone)] #[repr(transparent)] pub struct AlgAddr(pub(in super::super) sockaddr_alg); + impl private::SockaddrLikePriv for AlgAddr {} + impl SockaddrLike for AlgAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, l: Option) + -> Option where Self: Sized + { + if let Some(l) = l { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_ALG as i32 { + return None; + } + Some(AlgAddr(*(addr as *const libc::sockaddr_alg))) + } + } + + impl AsRef for AlgAddr { + fn as_ref(&self) -> &libc::sockaddr_alg { + &self.0 + } + } + // , PartialEq, Eq, Debug, Hash impl PartialEq for AlgAddr { fn eq(&self, other: &Self) -> bool { @@ -1197,6 +2087,7 @@ pub mod alg { } impl AlgAddr { + /// Construct an `AF_ALG` socket from its cipher name and type. pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr { let mut addr: sockaddr_alg = unsafe { mem::zeroed() }; addr.salg_family = AF_ALG as u16; @@ -1207,10 +2098,12 @@ pub mod alg { } + /// Return the socket's cipher type, for example `hash` or `aead`. pub fn alg_type(&self) -> &CStr { unsafe { CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) } } + /// Return the socket's cipher name, for example `sha1`. pub fn alg_name(&self) -> &CStr { unsafe { CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) } } @@ -1240,6 +2133,7 @@ pub mod sys_control { use std::{fmt, mem}; use std::os::unix::io::RawFd; use crate::{Errno, Result}; + use super::{private, SockaddrLike}; // FIXME: Move type into `libc` #[repr(C)] @@ -1256,11 +2150,41 @@ pub mod sys_control { ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info); + /// Apple system control socket + /// + /// # References + /// + /// https://developer.apple.com/documentation/kernel/sockaddr_ctl #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct SysControlAddr(pub(in super::super) libc::sockaddr_ctl); + impl private::SockaddrLikePriv for SysControlAddr {} + impl SockaddrLike for SysControlAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_INET6 as i32 { + return None; + } + Some(SysControlAddr(*(addr as *const libc::sockaddr_ctl))) + } + } + + impl AsRef for SysControlAddr { + fn as_ref(&self) -> &libc::sockaddr_ctl { + &self.0 + } + } + impl SysControlAddr { + /// Construct a new `SysControlAddr` from its kernel unique identifier + /// and unit number. pub const fn new(id: u32, unit: u32) -> SysControlAddr { let addr = libc::sockaddr_ctl { sc_len: mem::size_of::() as c_uchar, @@ -1274,6 +2198,8 @@ pub mod sys_control { SysControlAddr(addr) } + /// Construct a new `SysControlAddr` from its human readable name and + /// unit number. pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result { if name.len() > MAX_KCTL_NAME { return Err(Errno::ENAMETOOLONG); @@ -1288,10 +2214,12 @@ pub mod sys_control { Ok(SysControlAddr::new(info.ctl_id, unit)) } + /// Return the kernel unique identifier pub const fn id(&self) -> u32 { self.0.sc_id } + /// Return the kernel controller private unit number. pub const fn unit(&self) -> u32 { self.0.sc_unit } @@ -1311,7 +2239,7 @@ pub mod sys_control { mod datalink { feature! { #![feature = "net"] - use super::{fmt, AddressFamily}; + use super::{fmt, mem, private, SockaddrLike}; /// Hardware Address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -1319,12 +2247,6 @@ mod datalink { pub struct LinkAddr(pub(in super::super) libc::sockaddr_ll); impl LinkAddr { - /// Always AF_PACKET - pub fn family(&self) -> AddressFamily { - assert_eq!(self.0.sll_family as i32, libc::AF_PACKET); - AddressFamily::Packet - } - /// Physical-layer protocol pub fn protocol(&self) -> u16 { self.0.sll_protocol @@ -1379,6 +2301,30 @@ mod datalink { } } } + impl private::SockaddrLikePriv for LinkAddr {} + impl SockaddrLike for LinkAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, + len: Option) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_PACKET as i32 { + return None; + } + Some(LinkAddr(*(addr as *const libc::sockaddr_ll))) + } + } + + impl AsRef for LinkAddr { + fn as_ref(&self) -> &libc::sockaddr_ll { + &self.0 + } + } + } } @@ -1393,7 +2339,7 @@ mod datalink { mod datalink { feature! { #![feature = "net"] - use super::{fmt, AddressFamily}; + use super::{fmt, mem, private, SockaddrLike}; /// Hardware Address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -1401,19 +2347,6 @@ mod datalink { pub struct LinkAddr(pub(in super::super) libc::sockaddr_dl); impl LinkAddr { - /// Total length of sockaddr - #[cfg(not(target_os = "illumos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn len(&self) -> usize { - self.0.sdl_len as usize - } - - /// always == AF_LINK - pub fn family(&self) -> AddressFamily { - assert_eq!(i32::from(self.0.sdl_family), libc::AF_LINK); - AddressFamily::Link - } - /// interface index, if != 0, system given index for interface pub fn ifindex(&self) -> usize { self.0.sdl_index as usize @@ -1424,7 +2357,7 @@ mod datalink { self.0.sdl_type } - // MAC address start position + /// MAC address start position pub fn nlen(&self) -> usize { self.0.sdl_nlen as usize } @@ -1484,6 +2417,30 @@ mod datalink { } } } + impl private::SockaddrLikePriv for LinkAddr {} + impl SockaddrLike for LinkAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, + len: Option) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_LINK as i32 { + return None; + } + Some(LinkAddr(*(addr as *const libc::sockaddr_dl))) + } + } + + impl AsRef for LinkAddr { + fn as_ref(&self) -> &libc::sockaddr_dl { + &self.0 + } + } + } } @@ -1494,11 +2451,40 @@ pub mod vsock { use libc::{sa_family_t, sockaddr_vm}; use std::{fmt, mem}; use std::hash::{Hash, Hasher}; + use super::*; + /// Socket address for VMWare VSockets protocol + /// + /// # References + /// + /// [vsock(7)](https://man7.org/linux/man-pages/man7/vsock.7.html) #[derive(Copy, Clone)] #[repr(transparent)] pub struct VsockAddr(pub(in super::super) sockaddr_vm); + impl private::SockaddrLikePriv for VsockAddr {} + impl SockaddrLike for VsockAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_INET6 as i32 { + return None; + } + Some(VsockAddr(*(addr as *const libc::sockaddr_vm))) + } + } + + impl AsRef for VsockAddr { + fn as_ref(&self) -> &libc::sockaddr_vm { + &self.0 + } + } + impl PartialEq for VsockAddr { fn eq(&self, other: &Self) -> bool { let (inner, other) = (self.0, other.0); @@ -1521,6 +2507,7 @@ pub mod vsock { /// The address for AF_VSOCK socket is defined as a combination of a /// 32-bit Context Identifier (CID) and a 32-bit port number. impl VsockAddr { + /// Construct a `VsockAddr` from its raw fields. pub fn new(cid: u32, port: u32) -> VsockAddr { let mut addr: sockaddr_vm = unsafe { mem::zeroed() }; addr.svm_family = AddressFamily::Vsock as sa_family_t; @@ -1556,112 +2543,135 @@ pub mod vsock { #[cfg(test)] mod tests { - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] use super::*; - /// Don't panic when trying to display an empty datalink address - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[test] - fn test_datalink_display() { - let la = LinkAddr(libc::sockaddr_dl{ - sdl_len: 56, - sdl_family: 18, - sdl_index: 5, - sdl_type: 24, - sdl_nlen: 3, - sdl_alen: 0, - sdl_slen: 0, - .. unsafe{mem::zeroed()} - }); - format!("{}", la); - } + mod link { + #[cfg(any(target_os = "ios", + target_os = "macos", + target_os = "illumos" + ))] + use super::{*, super::super::socklen_t}; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[test] - fn test_macos_loopback_datalink_addr() { - let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; - let sa = bytes.as_ptr() as *const libc::sockaddr; - let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) }; - assert!(_sock_addr.is_none()); - } + /// Don't panic when trying to display an empty datalink address + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[test] + fn test_datalink_display() { + use super::super::LinkAddr; + use std::mem; + + let la = LinkAddr(libc::sockaddr_dl{ + sdl_len: 56, + sdl_family: 18, + sdl_index: 5, + sdl_type: 24, + sdl_nlen: 3, + sdl_alen: 0, + sdl_slen: 0, + .. unsafe{mem::zeroed()} + }); + format!("{}", la); + } + + #[cfg(any(target_os = "ios", + target_os = "macos" + ))] + #[test] + fn macos_loopback() { + let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; + let sa = bytes.as_ptr() as *const libc::sockaddr; + let len = Some(bytes.len() as socklen_t); + let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); + assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); + match sock_addr.as_link_addr() { + Some(dl) => { + assert!(dl.addr().is_none()); + }, + None => panic!("Can't unwrap sockaddr storage") + } + } - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[test] - fn test_macos_tap_datalink_addr() { - let bytes = [20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, 76, -80]; - let ptr = bytes.as_ptr(); - let sa = ptr as *const libc::sockaddr; - let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) }; + #[cfg(any(target_os = "ios", + target_os = "macos" + ))] + #[test] + fn macos_tap() { + let bytes = [20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, 76, -80]; + let ptr = bytes.as_ptr(); + let sa = ptr as *const libc::sockaddr; + let len = Some(bytes.len() as socklen_t); + + let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len).unwrap() }; + assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); + match sock_addr.as_link_addr() { + Some(dl) => assert_eq!(dl.addr(), + Some([24u8, 101, 144, 221, 76, 176])), + None => panic!("Can't unwrap sockaddr storage") + } + } - assert!(_sock_addr.is_some()); + #[cfg(target_os = "illumos")] + #[test] + fn illumos_tap() { + let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176]; + let ptr = bytes.as_ptr(); + let sa = ptr as *const libc::sockaddr; + let len = Some(bytes.len() as socklen_t); + let _sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }; - let sock_addr = _sock_addr.unwrap(); + assert!(_sock_addr.is_some()); - assert_eq!(sock_addr.family(), AddressFamily::Link); + let sock_addr = _sock_addr.unwrap(); - match sock_addr { - SockAddr::Link(ether_addr) => { - assert_eq!(ether_addr.addr(), - Some([24u8, 101, 144, 221, 76, 176])); - }, - _ => { unreachable!() } - }; - } + assert_eq!(sock_addr.family().unwrap(), AddressFamily::Link); - #[cfg(target_os = "illumos")] - #[test] - fn test_illumos_tap_datalink_addr() { - let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176]; - let ptr = bytes.as_ptr(); - let sa = ptr as *const libc::sockaddr; - let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) }; + assert_eq!(sock_addr.as_link_addr().unwrap().addr(), + Some([24u8, 101, 144, 221, 76, 176])); + } + } - assert!(_sock_addr.is_some()); + mod sockaddr_in { + use super::*; + use std::str::FromStr; - let sock_addr = _sock_addr.unwrap(); + #[test] + fn display() { + let s = "127.0.0.1:8080"; + let addr = SockaddrIn::from_str(s).unwrap(); + assert_eq!(s, format!("{}", addr)); + } + } - assert_eq!(sock_addr.family(), AddressFamily::Link); + mod sockaddr_in6 { + use super::*; + use std::str::FromStr; - match sock_addr { - SockAddr::Link(ether_addr) => { - assert_eq!(ether_addr.addr(), - Some([24u8, 101, 144, 221, 76, 176])); - }, - _ => { unreachable!() } - }; + #[test] + fn display() { + let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; + let addr = SockaddrIn6::from_str(s).unwrap(); + assert_eq!(s, format!("{}", addr)); + } } - #[cfg(any(target_os = "android", target_os = "linux"))] - #[test] - fn test_abstract_sun_path() { - let name = String::from("nix\0abstract\0test"); - let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); - - let sun_path1 = unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] }; - let sun_path2 = [0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116]; - assert_eq!(sun_path1, sun_path2); + mod unixaddr { + #[cfg(any(target_os = "android", target_os = "linux"))] + use super::*; + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[test] + fn abstract_sun_path() { + let name = String::from("nix\0abstract\0test"); + let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); + + let sun_path1 = unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] }; + let sun_path2 = [0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116]; + assert_eq!(sun_path1, sun_path2); + } + } } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 7ed2d82dd7..f5004b4541 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -17,6 +17,7 @@ use crate::sys::{ uio::IoVec }; +#[deny(missing_docs)] mod addr; #[deny(missing_docs)] pub mod sockopt; @@ -27,12 +28,16 @@ pub mod sockopt; * */ +pub use self::addr::{SockaddrLike, SockaddrStorage}; + #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] +#[allow(deprecated)] pub use self::addr::{ AddressFamily, SockAddr, UnixAddr, }; +#[allow(deprecated)] #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] #[cfg(feature = "net")] pub use self::addr::{ @@ -40,14 +45,18 @@ pub use self::addr::{ IpAddr, Ipv4Addr, Ipv6Addr, - LinkAddr + LinkAddr, + SockaddrIn, + SockaddrIn6 }; #[cfg(any(target_os = "illumos", target_os = "solaris"))] +#[allow(deprecated)] pub use self::addr::{ AddressFamily, SockAddr, UnixAddr, }; +#[allow(deprecated)] #[cfg(any(target_os = "illumos", target_os = "solaris"))] #[cfg(feature = "net")] pub use self::addr::{ @@ -55,8 +64,13 @@ pub use self::addr::{ IpAddr, Ipv4Addr, Ipv6Addr, + SockaddrIn, + SockaddrIn6 }; +#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(feature = "ioctl")] +pub use crate::sys::socket::addr::sys_control::SysControlAddr; #[cfg(any(target_os = "android", target_os = "linux"))] pub use crate::sys::socket::addr::netlink::NetlinkAddr; #[cfg(any(target_os = "android", target_os = "linux"))] @@ -550,15 +564,15 @@ macro_rules! cmsg_space { } #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct RecvMsg<'a> { +pub struct RecvMsg<'a, S> { pub bytes: usize, cmsghdr: Option<&'a cmsghdr>, - pub address: Option, + pub address: Option, pub flags: MsgFlags, mhdr: msghdr, } -impl<'a> RecvMsg<'a> { +impl<'a, S> RecvMsg<'a, S> { /// Iterate over the valid control messages pointed to by this /// msghdr. pub fn cmsgs(&self) -> CmsgIterator { @@ -635,6 +649,7 @@ pub enum ControlMessageOwned { /// # use nix::sys::uio::IoVec; /// # use nix::sys::time::*; /// # use std::time::*; + /// # use std::str::FromStr; /// # fn main() { /// // Set up /// let message = "Ohayō!".as_bytes(); @@ -644,9 +659,9 @@ pub enum ControlMessageOwned { /// SockFlag::empty(), /// None).unwrap(); /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap(); - /// let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); - /// bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); - /// let address = getsockname(in_socket).unwrap(); + /// let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); + /// bind(in_socket, &localhost); + /// let address: SockaddrIn = getsockname(in_socket).unwrap(); /// // Get initial time /// let time0 = SystemTime::now(); /// // Send the message @@ -658,7 +673,8 @@ pub enum ControlMessageOwned { /// let mut buffer = vec![0u8; message.len()]; /// let mut cmsgspace = cmsg_space!(TimeVal); /// let iov = [IoVec::from_mut_slice(&mut buffer)]; - /// let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap(); + /// let r = recvmsg::(in_socket, &iov, Some(&mut cmsgspace), flags) + /// .unwrap(); /// let rtime = match r.cmsgs().next() { /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime, /// Some(_) => panic!("Unexpected control message"), @@ -1334,8 +1350,42 @@ impl<'a> ControlMessage<'a> { /// as with sendto. /// /// Allocates if cmsgs is nonempty. -pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], - flags: MsgFlags, addr: Option<&SockAddr>) -> Result +/// +/// # Examples +/// When not directing to any specific address, use `()` for the generic type +/// ``` +/// # use nix::sys::socket::*; +/// # use nix::unistd::pipe; +/// # use nix::sys::uio::IoVec; +/// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, +/// SockFlag::empty()) +/// .unwrap(); +/// let (r, w) = pipe().unwrap(); +/// +/// let iov = [IoVec::from_slice(b"hello")]; +/// let fds = [r]; +/// let cmsg = ControlMessage::ScmRights(&fds); +/// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); +/// ``` +/// When directing to a specific address, the generic type will be inferred. +/// ``` +/// # use nix::sys::socket::*; +/// # use nix::unistd::pipe; +/// # use nix::sys::uio::IoVec; +/// # use std::str::FromStr; +/// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap(); +/// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), +/// None).unwrap(); +/// let (r, w) = pipe().unwrap(); +/// +/// let iov = [IoVec::from_slice(b"hello")]; +/// let fds = [r]; +/// let cmsg = ControlMessage::ScmRights(&fds); +/// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); +/// ``` +pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], + flags: MsgFlags, addr: Option<&S>) -> Result + where S: SockaddrLike { let capacity = cmsgs.iter().map(|c| c.space()).sum(); @@ -1357,14 +1407,15 @@ pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], target_os = "netbsd", ))] #[derive(Debug)] -pub struct SendMmsgData<'a, I, C> +pub struct SendMmsgData<'a, I, C, S> where I: AsRef<[IoVec<&'a [u8]>]>, - C: AsRef<[ControlMessage<'a>]> + C: AsRef<[ControlMessage<'a>]>, + S: SockaddrLike + 'a { pub iov: I, pub cmsgs: C, - pub addr: Option, + pub addr: Option, pub _lt: std::marker::PhantomData<&'a I>, } @@ -1391,14 +1442,15 @@ pub struct SendMmsgData<'a, I, C> target_os = "freebsd", target_os = "netbsd", ))] -pub fn sendmmsg<'a, I, C>( +pub fn sendmmsg<'a, I, C, S>( fd: RawFd, - data: impl std::iter::IntoIterator>, + data: impl std::iter::IntoIterator>, flags: MsgFlags ) -> Result> where I: AsRef<[IoVec<&'a [u8]>]> + 'a, C: AsRef<[ControlMessage<'a>]> + 'a, + S: SockaddrLike + 'a { let iter = data.into_iter(); @@ -1486,15 +1538,16 @@ pub struct RecvMmsgData<'a, I> target_os = "netbsd", ))] #[allow(clippy::needless_collect)] // Complicated false positive -pub fn recvmmsg<'a, I>( +pub fn recvmmsg<'a, I, S>( fd: RawFd, data: impl std::iter::IntoIterator, IntoIter=impl ExactSizeIterator + Iterator>>, flags: MsgFlags, timeout: Option -) -> Result>> +) -> Result>> where I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, + S: Copy + SockaddrLike + 'a { let iter = data.into_iter(); @@ -1556,13 +1609,15 @@ pub fn recvmmsg<'a, I>( .collect()) } -unsafe fn read_mhdr<'a, 'b>( +unsafe fn read_mhdr<'a, 'b, S>( mhdr: msghdr, r: isize, msg_controllen: usize, - address: sockaddr_storage, + address: S, cmsg_buffer: &'a mut Option<&'b mut Vec> -) -> RecvMsg<'b> { +) -> RecvMsg<'b, S> + where S: SockaddrLike +{ let cmsghdr = { if mhdr.msg_controllen > 0 { // got control message(s) @@ -1578,27 +1633,23 @@ unsafe fn read_mhdr<'a, 'b>( }.as_ref() }; - let address = sockaddr_storage_to_addr( - &address , - mhdr.msg_namelen as usize - ).ok(); - RecvMsg { bytes: r as usize, cmsghdr, - address, + address: Some(address), flags: MsgFlags::from_bits_truncate(mhdr.msg_flags), mhdr, } } -unsafe fn pack_mhdr_to_receive<'a, I>( +unsafe fn pack_mhdr_to_receive<'a, I, S>( iov: I, cmsg_buffer: &mut Option<&mut Vec>, - address: *mut sockaddr_storage, + address: *mut S, ) -> (usize, msghdr) where I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, + S: SockaddrLike + 'a { let (msg_control, msg_controllen) = cmsg_buffer.as_mut() .map(|v| (v.as_mut_ptr(), v.capacity())) @@ -1609,8 +1660,8 @@ unsafe fn pack_mhdr_to_receive<'a, I>( // initialize it. let mut mhdr = mem::MaybeUninit::::zeroed(); let p = mhdr.as_mut_ptr(); - (*p).msg_name = address as *mut c_void; - (*p).msg_namelen = mem::size_of::() as socklen_t; + (*p).msg_name = (*address).as_mut_ptr() as *mut c_void; + (*p).msg_namelen = S::size(); (*p).msg_iov = iov.as_ref().as_ptr() as *mut iovec; (*p).msg_iovlen = iov.as_ref().len() as _; (*p).msg_control = msg_control as *mut c_void; @@ -1622,27 +1673,19 @@ unsafe fn pack_mhdr_to_receive<'a, I>( (msg_controllen, mhdr) } -fn pack_mhdr_to_send<'a, I, C>( +fn pack_mhdr_to_send<'a, I, C, S>( cmsg_buffer: &mut [u8], iov: I, cmsgs: C, - addr: Option<&SockAddr> + addr: Option<&S> ) -> msghdr where I: AsRef<[IoVec<&'a [u8]>]>, - C: AsRef<[ControlMessage<'a>]> + C: AsRef<[ControlMessage<'a>]>, + S: SockaddrLike + 'a { let capacity = cmsg_buffer.len(); - // Next encode the sending address, if provided - let (name, namelen) = match addr { - Some(addr) => { - let (x, y) = addr.as_ffi_pair(); - (x as *const _, y) - }, - None => (ptr::null(), 0), - }; - // The message header must be initialized before the individual cmsgs. let cmsg_ptr = if capacity > 0 { cmsg_buffer.as_ptr() as *mut c_void @@ -1655,8 +1698,8 @@ fn pack_mhdr_to_send<'a, I, C>( // initialize it. let mut mhdr = mem::MaybeUninit::::zeroed(); let p = mhdr.as_mut_ptr(); - (*p).msg_name = name as *mut _; - (*p).msg_namelen = namelen; + (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()) as *mut _; + (*p).msg_namelen = addr.map(S::len).unwrap_or(0); // transmute iov into a mutable pointer. sendmsg doesn't really mutate // the buffer, but the standard says that it takes a mutable pointer (*p).msg_iov = iov.as_ref().as_ptr() as *mut _; @@ -1697,9 +1740,10 @@ fn pack_mhdr_to_send<'a, I, C>( /// /// # References /// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) -pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>], +pub fn recvmsg<'a, S>(fd: RawFd, iov: &[IoVec<&mut [u8]>], mut cmsg_buffer: Option<&'a mut Vec>, - flags: MsgFlags) -> Result> + flags: MsgFlags) -> Result> + where S: SockaddrLike + 'a { let mut address = mem::MaybeUninit::uninit(); @@ -1779,10 +1823,9 @@ pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> { /// Bind a name to a socket /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html) -pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> { +pub fn bind(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { let res = unsafe { - let (ptr, len) = addr.as_ffi_pair(); - libc::bind(fd, ptr, len) + libc::bind(fd, addr.as_ptr(), addr.len()) }; Errno::result(res).map(drop) @@ -1825,10 +1868,9 @@ pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result { /// Initiate a connection on a socket /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html) -pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> { +pub fn connect(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { let res = unsafe { - let (ptr, len) = addr.as_ffi_pair(); - libc::connect(fd, ptr, len) + libc::connect(fd, addr.as_ptr(), addr.len()) }; Errno::result(res).map(drop) @@ -1855,36 +1897,38 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result { /// address of the sender. /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html) -pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) - -> Result<(usize, Option)> +pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) + -> Result<(usize, Option)> { unsafe { - let mut addr: sockaddr_storage = mem::zeroed(); - let mut len = mem::size_of::() as socklen_t; + let mut addr = mem::MaybeUninit::uninit(); + let mut len = mem::size_of::() as socklen_t; let ret = Errno::result(libc::recvfrom( sockfd, buf.as_ptr() as *mut c_void, buf.len() as size_t, 0, - &mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr, + addr.as_mut_ptr() as *mut libc::sockaddr, &mut len as *mut socklen_t))? as usize; - match sockaddr_storage_to_addr(&addr, len as usize) { - Err(Errno::ENOTCONN) => Ok((ret, None)), - Ok(addr) => Ok((ret, Some(addr))), - Err(e) => Err(e) - } + Ok((ret, T::from_raw(&addr.assume_init(), Some(len)))) } } /// Send a message to a socket /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html) -pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result { +pub fn sendto(fd: RawFd, buf: &[u8], addr: &dyn SockaddrLike, flags: MsgFlags) -> Result { let ret = unsafe { - let (ptr, len) = addr.as_ffi_pair(); - libc::sendto(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits(), ptr, len) + libc::sendto( + fd, + buf.as_ptr() as *const c_void, + buf.len() as size_t, + flags.bits(), + addr.as_ptr(), + addr.len() + ) }; Errno::result(ret).map(|r| r as usize) @@ -1954,10 +1998,10 @@ pub fn setsockopt(fd: RawFd, opt: O, val: &O::Val) -> Result<()> /// Get the address of the peer connected to the socket `fd`. /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html) -pub fn getpeername(fd: RawFd) -> Result { +pub fn getpeername(fd: RawFd) -> Result { unsafe { - let mut addr = mem::MaybeUninit::uninit(); - let mut len = mem::size_of::() as socklen_t; + let mut addr = mem::MaybeUninit::::uninit(); + let mut len = T::size(); let ret = libc::getpeername( fd, @@ -1967,17 +2011,18 @@ pub fn getpeername(fd: RawFd) -> Result { Errno::result(ret)?; - sockaddr_storage_to_addr(&addr.assume_init(), len as usize) + T::from_raw(addr.assume_init().as_ptr(), Some(len)) + .ok_or(Errno::EINVAL) } } /// Get the current address to which the socket `fd` is bound. /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html) -pub fn getsockname(fd: RawFd) -> Result { +pub fn getsockname(fd: RawFd) -> Result { unsafe { - let mut addr = mem::MaybeUninit::uninit(); - let mut len = mem::size_of::() as socklen_t; + let mut addr = mem::MaybeUninit::::uninit(); + let mut len = T::size(); let ret = libc::getsockname( fd, @@ -1987,7 +2032,8 @@ pub fn getsockname(fd: RawFd) -> Result { Errno::result(ret)?; - sockaddr_storage_to_addr(&addr.assume_init(), len as usize) + T::from_raw(addr.assume_init().as_ptr(), Some(len)) + .ok_or(Errno::EINVAL) } } @@ -1999,6 +2045,11 @@ pub fn getsockname(fd: RawFd) -> Result { /// allocated and valid. It must be at least as large as all the useful parts /// of the structure. Note that in the case of a `sockaddr_un`, `len` need not /// include the terminating null. +#[deprecated( + since = "0.24.0", + note = "use SockaddrLike or SockaddrStorage instead" +)] +#[allow(deprecated)] pub fn sockaddr_storage_to_addr( addr: &sockaddr_storage, len: usize) -> Result { diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 01f5f87875..e03edc3b40 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1,8 +1,11 @@ -use nix::sys::socket::{AddressFamily, InetAddr, SockAddr, UnixAddr, getsockname, sockaddr, sockaddr_in6, sockaddr_storage_to_addr}; +#[allow(deprecated)] +use nix::sys::socket::InetAddr; +use nix::sys::socket::{AddressFamily, + UnixAddr, getsockname, sockaddr, sockaddr_in6}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::mem::{self, MaybeUninit}; -use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV6}; +use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::os::unix::io::RawFd; use std::path::Path; use std::slice; @@ -11,6 +14,7 @@ use libc::{c_char, sockaddr_storage}; #[cfg(any(target_os = "linux", target_os= "android"))] use crate::*; +#[allow(deprecated)] #[test] pub fn test_inetv4_addr_to_sock_addr() { let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); @@ -34,8 +38,11 @@ pub fn test_inetv4_addr_to_sock_addr() { assert_eq!(actual, inet); } +#[allow(deprecated)] #[test] pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() { + use nix::sys::socket::{SockAddr, sockaddr_storage_to_addr}; + let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); let addr = InetAddr::from_std(&actual); let sockaddr = SockAddr::new_inet(addr); @@ -63,13 +70,11 @@ pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() { pub fn test_timestamping() { use nix::sys::socket::{ recvmsg, sendmsg, setsockopt, socket, sockopt::Timestamping, ControlMessageOwned, MsgFlags, - SockFlag, SockType, TimestampingFlag, + SockaddrIn, SockFlag, SockType, TimestampingFlag, }; use nix::sys::uio::IoVec; - let std_sa = SocketAddr::from_str("127.0.0.1:6790").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); let ssock = socket( AddressFamily::Inet, @@ -97,7 +102,7 @@ pub fn test_timestamping() { let iov2 = [IoVec::from_mut_slice(&mut rbuf)]; let mut cmsg = cmsg_space!(nix::sys::socket::Timestamps); sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); - let recv = recvmsg(rsock, &iov2, Some(&mut cmsg), flags).unwrap(); + let recv = recvmsg::<()>(rsock, &iov2, Some(&mut cmsg), flags).unwrap(); let mut ts = None; for c in recv.cmsgs() { @@ -115,29 +120,11 @@ pub fn test_timestamping() { assert!(std::time::Duration::from(diff).as_secs() < 60); } -#[test] -pub fn test_inetv6_addr_to_sock_addr() { - let port: u16 = 3000; - let flowinfo: u32 = 1; - let scope_id: u32 = 2; - let ip: Ipv6Addr = "fe80::1".parse().unwrap(); - - let actual = SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id)); - let addr = InetAddr::from_std(&actual); - - match addr { - InetAddr::V6(addr) => { - assert_eq!(addr.sin6_port, port.to_be()); - assert_eq!(addr.sin6_flowinfo, flowinfo); - assert_eq!(addr.sin6_scope_id, scope_id); - } - _ => panic!("nope"), - } - - assert_eq!(actual, addr.to_std()); -} +#[allow(deprecated)] #[test] pub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr() { + use nix::sys::socket::{SockAddr, sockaddr_storage_to_addr}; + let port: u16 = 3000; let flowinfo: u32 = 1; let scope_id: u32 = 2; @@ -244,13 +231,13 @@ pub fn test_abstract_uds_addr() { #[test] pub fn test_getsockname() { use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag}; - use nix::sys::socket::{bind, SockAddr}; + use nix::sys::socket::bind; let tempdir = tempfile::tempdir().unwrap(); let sockname = tempdir.path().join("sock"); let sock = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None) .expect("socket failed"); - let sockaddr = SockAddr::new_unix(&sockname).unwrap(); + let sockaddr = UnixAddr::new(&sockname).unwrap(); bind(sock, &sockaddr).expect("bind failed"); assert_eq!(sockaddr, getsockname(sock).expect("getsockname failed")); } @@ -277,10 +264,10 @@ mod recvfrom { const MSG: &[u8] = b"Hello, World!"; - fn sendrecv(rsock: RawFd, ssock: RawFd, f_send: Fs, mut f_recv: Fr) -> Option + fn sendrecv(rsock: RawFd, ssock: RawFd, f_send: Fs, mut f_recv: Fr) -> Option where Fs: Fn(RawFd, &[u8], MsgFlags) -> Result + Send + 'static, - Fr: FnMut(usize, Option), + Fr: FnMut(usize, Option), { let mut buf: [u8; 13] = [0u8; 13]; let mut l = 0; @@ -316,9 +303,8 @@ mod recvfrom { #[test] pub fn udp() { - let std_sa = SocketAddr::from_str("127.0.0.1:6789").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); let rsock = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), @@ -335,7 +321,7 @@ mod recvfrom { sendto(s, m, &sock_addr, flags) },|_, _| {}); // UDP sockets should set the from address - assert_eq!(AddressFamily::Inet, from.unwrap().family()); + assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); } #[cfg(target_os = "linux")] @@ -356,9 +342,7 @@ mod recvfrom { // with size 2 and two UDP packet with size 1 will be sent. let segment_size: u16 = 2; - let std_sa = SocketAddr::from_str("127.0.0.1:6791").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let sock_addr = SockaddrIn::new(127, 0, 0, 1, 6791); let rsock = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), @@ -429,12 +413,10 @@ mod recvfrom { pub fn udp_sendmmsg() { use nix::sys::uio::IoVec; - let std_sa = SocketAddr::from_str("127.0.0.1:6793").unwrap(); - let std_sa2 = SocketAddr::from_str("127.0.0.1:6794").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let inet_addr2 = InetAddr::from_std(&std_sa2); - let sock_addr = SockAddr::new_inet(inet_addr); - let sock_addr2 = SockAddr::new_inet(inet_addr2); + let std_sa = SocketAddrV4::from_str("127.0.0.1:6793").unwrap(); + let std_sa2 = SocketAddrV4::from_str("127.0.0.1:6794").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); + let sock_addr2 = SockaddrIn::from(std_sa2); let rsock = socket(AddressFamily::Inet, SockType::Datagram, @@ -482,7 +464,7 @@ mod recvfrom { }) }, |_, _ | {}); // UDP sockets should set the from address - assert_eq!(AddressFamily::Inet, from.unwrap().family()); + assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); } #[cfg(any( @@ -499,9 +481,8 @@ mod recvfrom { const NUM_MESSAGES_SENT: usize = 2; const DATA: [u8; 2] = [1,2]; - let std_sa = SocketAddr::from_str("127.0.0.1:6798").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let inet_addr = SocketAddrV4::from_str("127.0.0.1:6798").unwrap(); + let sock_addr = SockaddrIn::from(inet_addr); let rsock = socket(AddressFamily::Inet, SockType::Datagram, @@ -537,11 +518,11 @@ mod recvfrom { }) }; - let res = recvmmsg(rsock, &mut msgs, MsgFlags::empty(), None).expect("recvmmsg"); + let res: Vec> = recvmmsg(rsock, &mut msgs, MsgFlags::empty(), None).expect("recvmmsg"); assert_eq!(res.len(), DATA.len()); for RecvMsg { address, bytes, .. } in res.into_iter() { - assert_eq!(AddressFamily::Inet, address.unwrap().family()); + assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap()); assert_eq!(DATA.len(), bytes); } @@ -566,9 +547,8 @@ mod recvfrom { const NUM_MESSAGES_SENT: usize = 2; const DATA: [u8; 4] = [1,2,3,4]; - let std_sa = SocketAddr::from_str("127.0.0.1:6799").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let inet_addr = SocketAddrV4::from_str("127.0.0.1:6799").unwrap(); + let sock_addr = SockaddrIn::from(inet_addr); let rsock = socket(AddressFamily::Inet, SockType::Datagram, @@ -609,11 +589,11 @@ mod recvfrom { }) }; - let res = recvmmsg(rsock, &mut msgs, MsgFlags::MSG_DONTWAIT, None).expect("recvmmsg"); + let res: Vec> = recvmmsg(rsock, &mut msgs, MsgFlags::MSG_DONTWAIT, None).expect("recvmmsg"); assert_eq!(res.len(), NUM_MESSAGES_SENT); for RecvMsg { address, bytes, .. } in res.into_iter() { - assert_eq!(AddressFamily::Inet, address.unwrap().family()); + assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap()); assert_eq!(DATA.len(), bytes); } @@ -633,7 +613,7 @@ pub fn test_recvmsg_ebadf() { let mut buf = [0u8; 5]; let iov = [IoVec::from_mut_slice(&mut buf[..])]; let fd = -1; // Bad file descriptor - let r = recvmsg(fd, &iov, None, MsgFlags::empty()); + let r = recvmsg::<()>(fd, &iov, None, MsgFlags::empty()); assert_eq!(r.err().unwrap(), Errno::EBADF); } @@ -657,7 +637,7 @@ pub fn test_scm_rights() { let iov = [IoVec::from_slice(b"hello")]; let fds = [r]; let cmsg = ControlMessage::ScmRights(&fds); - assert_eq!(sendmsg(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); + assert_eq!(sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); close(r).unwrap(); close(fd1).unwrap(); } @@ -666,7 +646,7 @@ pub fn test_scm_rights() { let mut buf = [0u8; 5]; let iov = [IoVec::from_mut_slice(&mut buf[..])]; let mut cmsgspace = cmsg_space!([RawFd; 1]); - let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); for cmsg in msg.cmsgs() { if let ControlMessageOwned::ScmRights(fd) = cmsg { @@ -700,7 +680,7 @@ pub fn test_af_alg_cipher() { use nix::sys::uio::IoVec; use nix::unistd::read; use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt, - AddressFamily, SockType, SockFlag, SockAddr, + AddressFamily, SockType, SockFlag, AlgAddr, ControlMessage, MsgFlags}; use nix::sys::socket::sockopt::AlgSetKey; @@ -723,22 +703,18 @@ pub fn test_af_alg_cipher() { let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None) .expect("socket failed"); - let sockaddr = SockAddr::new_alg(alg_type, alg_name); + let sockaddr = AlgAddr::new(alg_type, alg_name); bind(sock, &sockaddr).expect("bind failed"); - if let SockAddr::Alg(alg) = sockaddr { - assert_eq!(alg.alg_name().to_string_lossy(), alg_name); - assert_eq!(alg.alg_type().to_string_lossy(), alg_type); - } else { - panic!("unexpected SockAddr"); - } + assert_eq!(sockaddr.alg_name().to_string_lossy(), alg_name); + assert_eq!(sockaddr.alg_type().to_string_lossy(), alg_type); setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt"); let session_socket = accept(sock).expect("accept failed"); let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), ControlMessage::AlgSetIv(iv.as_slice())]; let iov = IoVec::from_slice(&payload); - sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); // allocate buffer for encrypted data let mut encrypted = vec![0u8; payload_len]; @@ -750,7 +726,7 @@ pub fn test_af_alg_cipher() { let iv = vec![1u8; iv_len]; let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT), ControlMessage::AlgSetIv(iv.as_slice())]; - sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt"); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt"); // allocate buffer for decrypted data let mut decrypted = vec![0u8; payload_len]; @@ -771,7 +747,7 @@ pub fn test_af_alg_aead() { use nix::sys::uio::IoVec; use nix::unistd::{read, close}; use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt, - AddressFamily, SockType, SockFlag, SockAddr, + AddressFamily, SockType, SockFlag, AlgAddr, ControlMessage, MsgFlags}; use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize}; @@ -807,7 +783,7 @@ pub fn test_af_alg_aead() { let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None) .expect("socket failed"); - let sockaddr = SockAddr::new_alg(alg_type, alg_name); + let sockaddr = AlgAddr::new(alg_type, alg_name); bind(sock, &sockaddr).expect("bind failed"); setsockopt(sock, AlgSetAeadAuthSize, &auth_size).expect("setsockopt AlgSetAeadAuthSize"); @@ -819,7 +795,7 @@ pub fn test_af_alg_aead() { ControlMessage::AlgSetIv(iv.as_slice()), ControlMessage::AlgSetAeadAssoclen(&assoc_size)]; let iov = IoVec::from_slice(&payload); - sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); // allocate buffer for encrypted data let mut encrypted = vec![0u8; (assoc_size as usize) + payload_len + auth_size]; @@ -842,7 +818,7 @@ pub fn test_af_alg_aead() { ControlMessage::AlgSetIv(iv.as_slice()), ControlMessage::AlgSetAeadAssoclen(&assoc_size), ]; - sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt"); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt"); // allocate buffer for decrypted data let mut decrypted = vec![0u8; payload_len + (assoc_size as usize) + auth_size]; @@ -872,7 +848,7 @@ pub fn test_sendmsg_ipv4packetinfo() { use cfg_if::cfg_if; use nix::sys::uio::IoVec; use nix::sys::socket::{socket, sendmsg, bind, - AddressFamily, SockType, SockFlag, SockAddr, + AddressFamily, SockType, SockFlag, SockaddrIn, ControlMessage, MsgFlags}; let sock = socket(AddressFamily::Inet, @@ -881,39 +857,32 @@ pub fn test_sendmsg_ipv4packetinfo() { None) .expect("socket failed"); - let std_sa = SocketAddr::from_str("127.0.0.1:4000").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let sock_addr = SockaddrIn::new(127,0,0,1, 4000); bind(sock, &sock_addr).expect("bind failed"); let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; let iov = [IoVec::from_slice(&slice)]; - if let InetAddr::V4(sin) = inet_addr { - cfg_if! { - if #[cfg(target_os = "netbsd")] { - let _dontcare = sin; - let pi = libc::in_pktinfo { - ipi_ifindex: 0, /* Unspecified interface */ - ipi_addr: libc::in_addr { s_addr: 0 }, - }; - } else { - let pi = libc::in_pktinfo { - ipi_ifindex: 0, /* Unspecified interface */ - ipi_addr: libc::in_addr { s_addr: 0 }, - ipi_spec_dst: sin.sin_addr, - }; - } + cfg_if! { + if #[cfg(target_os = "netbsd")] { + let pi = libc::in_pktinfo { + ipi_ifindex: 0, /* Unspecified interface */ + ipi_addr: libc::in_addr { s_addr: 0 }, + }; + } else { + let pi = libc::in_pktinfo { + ipi_ifindex: 0, /* Unspecified interface */ + ipi_addr: libc::in_addr { s_addr: 0 }, + ipi_spec_dst: sock_addr.as_ref().sin_addr, + }; } + } - let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)]; + let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)]; - sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) - .expect("sendmsg"); - } else { - panic!("No IPv4 addresses available for testing?"); - } + sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) + .expect("sendmsg"); } // Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`. @@ -933,7 +902,7 @@ pub fn test_sendmsg_ipv6packetinfo() { use nix::errno::Errno; use nix::sys::uio::IoVec; use nix::sys::socket::{socket, sendmsg, bind, - AddressFamily, SockType, SockFlag, SockAddr, + AddressFamily, SockType, SockFlag, SockaddrIn6, ControlMessage, MsgFlags}; let sock = socket(AddressFamily::Inet6, @@ -942,9 +911,8 @@ pub fn test_sendmsg_ipv6packetinfo() { None) .expect("socket failed"); - let std_sa = SocketAddr::from_str("[::1]:6000").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap(); + let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa); if let Err(Errno::EADDRNOTAVAIL) = bind(sock, &sock_addr) { println!("IPv6 not available, skipping test."); @@ -954,19 +922,15 @@ pub fn test_sendmsg_ipv6packetinfo() { let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; let iov = [IoVec::from_slice(&slice)]; - if let InetAddr::V6(sin) = inet_addr { - let pi = libc::in6_pktinfo { - ipi6_ifindex: 0, /* Unspecified interface */ - ipi6_addr: sin.sin6_addr, - }; + let pi = libc::in6_pktinfo { + ipi6_ifindex: 0, /* Unspecified interface */ + ipi6_addr: sock_addr.as_ref().sin6_addr, + }; - let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)]; + let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)]; - sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) - .expect("sendmsg"); - } else { - println!("No IPv6 addresses available for testing: skipping testing Ipv6PacketInfo"); - } + sendmsg::(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) + .expect("sendmsg"); } /// Tests that passing multiple fds using a single `ControlMessage` works. @@ -987,7 +951,7 @@ fn test_scm_rights_single_cmsg_multiple_fds() { let mut buf = [0u8; 8]; let iovec = [IoVec::from_mut_slice(&mut buf)]; let mut space = cmsg_space!([RawFd; 2]); - let msg = recvmsg( + let msg = recvmsg::<()>( receive.as_raw_fd(), &iovec, Some(&mut space), @@ -1014,7 +978,7 @@ fn test_scm_rights_single_cmsg_multiple_fds() { let iov = [IoVec::from_slice(&slice)]; let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout let cmsg = [ControlMessage::ScmRights(&fds)]; - sendmsg(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None).unwrap(); + sendmsg::<()>(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None).unwrap(); thread.join().unwrap(); } @@ -1034,7 +998,7 @@ pub fn test_sendmsg_empty_cmsgs() { { let iov = [IoVec::from_slice(b"hello")]; - assert_eq!(sendmsg(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5); + assert_eq!(sendmsg::<()>(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5); close(fd1).unwrap(); } @@ -1042,7 +1006,7 @@ pub fn test_sendmsg_empty_cmsgs() { let mut buf = [0u8; 5]; let iov = [IoVec::from_mut_slice(&mut buf[..])]; let mut cmsgspace = cmsg_space!([RawFd; 1]); - let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); for _ in msg.cmsgs() { panic!("unexpected cmsg"); @@ -1083,7 +1047,7 @@ fn test_scm_credentials() { let cmsg = ControlMessage::ScmCredentials(&cred); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] let cmsg = ControlMessage::ScmCreds; - assert_eq!(sendmsg(send, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); + assert_eq!(sendmsg::<()>(send, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); close(send).unwrap(); } @@ -1091,7 +1055,7 @@ fn test_scm_credentials() { let mut buf = [0u8; 5]; let iov = [IoVec::from_mut_slice(&mut buf[..])]; let mut cmsgspace = cmsg_space!(UnixCredentials); - let msg = recvmsg(recv, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>(recv, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); let mut received_cred = None; for cmsg in msg.cmsgs() { @@ -1168,7 +1132,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { ControlMessage::ScmCredentials(&cred), ControlMessage::ScmRights(&fds), ]; - assert_eq!(sendmsg(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(), 5); + assert_eq!(sendmsg::<()>(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(), 5); close(r).unwrap(); close(send).unwrap(); } @@ -1176,7 +1140,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { { let mut buf = [0u8; 5]; let iov = [IoVec::from_mut_slice(&mut buf[..])]; - let msg = recvmsg(recv, &iov, Some(&mut space), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>(recv, &iov, Some(&mut space), MsgFlags::empty()).unwrap(); let mut received_cred = None; assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs"); @@ -1218,7 +1182,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { #[test] pub fn test_unixdomain() { use nix::sys::socket::{SockType, SockFlag}; - use nix::sys::socket::{bind, socket, connect, listen, accept, SockAddr}; + use nix::sys::socket::{bind, socket, connect, listen, accept, UnixAddr}; use nix::unistd::{read, write, close}; use std::thread; @@ -1226,7 +1190,7 @@ pub fn test_unixdomain() { let sockname = tempdir.path().join("sock"); let s1 = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None).expect("socket failed"); - let sockaddr = SockAddr::new_unix(&sockname).unwrap(); + let sockaddr = UnixAddr::new(&sockname).unwrap(); bind(s1, &sockaddr).expect("bind failed"); listen(s1, 10).expect("listen failed"); @@ -1254,13 +1218,14 @@ pub fn test_unixdomain() { #[test] pub fn test_syscontrol() { use nix::errno::Errno; - use nix::sys::socket::{socket, SockAddr, SockType, SockFlag, SockProtocol}; + use nix::sys::socket::{socket, SysControlAddr, SockType, SockFlag, SockProtocol}; let fd = socket(AddressFamily::System, SockType::Datagram, SockFlag::empty(), SockProtocol::KextControl) .expect("socket failed"); - let _sockaddr = SockAddr::new_sys_control(fd, "com.apple.net.utun_control", 0).expect("resolving sys_control name failed"); - assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Errno::ENOENT)); + SysControlAddr::from_name(fd, "com.apple.net.utun_control", 0) + .expect("resolving sys_control name failed"); + assert_eq!(SysControlAddr::from_name(fd, "foo.bar.lol", 0).err(), Some(Errno::ENOENT)); // requires root privileges // connect(fd, &sockaddr).expect("connect failed"); @@ -1280,6 +1245,7 @@ fn loopback_address(family: AddressFamily) -> Option iter, @@ -1292,22 +1258,10 @@ fn loopback_address(family: AddressFamily) -> Option { - match family { - AddressFamily::Inet => return Some(ifaddr), - _ => continue - } - }, - Some(SockAddr::Inet(InetAddr::V6(..))) => { - match family { - AddressFamily::Inet6 => return Some(ifaddr), - _ => continue - } - }, - _ => continue, - } + if ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK) && + ifaddr.address.as_ref().and_then(SockaddrLike::family) == Some(family) + { + return Some(ifaddr) } } None @@ -1332,7 +1286,7 @@ fn loopback_address(family: AddressFamily) -> Option( receive, &iovec, Some(&mut space), @@ -1422,8 +1376,8 @@ pub fn test_recv_ipv4pktinfo() { pub fn test_recvif() { use nix::net::if_::*; use nix::sys::socket::sockopt::{Ipv4RecvIf, Ipv4RecvDstAddr}; - use nix::sys::socket::{bind, SockFlag, SockType}; - use nix::sys::socket::{getsockname, setsockopt, socket, SockAddr}; + use nix::sys::socket::{bind, SockaddrIn, SockFlag, SockType}; + use nix::sys::socket::{getsockname, setsockopt, socket}; use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; use nix::sys::uio::IoVec; @@ -1440,7 +1394,7 @@ pub fn test_recvif() { None, ).expect("receive socket failed"); bind(receive, &lo).expect("bind failed"); - let sa = getsockname(receive).expect("getsockname failed"); + let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); setsockopt(receive, Ipv4RecvIf, &true).expect("setsockopt IP_RECVIF failed"); setsockopt(receive, Ipv4RecvDstAddr, &true).expect("setsockopt IP_RECVDSTADDR failed"); @@ -1461,7 +1415,7 @@ pub fn test_recvif() { let mut buf = [0u8; 8]; let iovec = [IoVec::from_mut_slice(&mut buf)]; let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr); - let msg = recvmsg( + let msg = recvmsg::<()>( receive, &iovec, Some(&mut space), @@ -1490,11 +1444,11 @@ pub fn test_recvif() { }, ControlMessageOwned::Ipv4RecvDstAddr(addr) => { rx_recvdstaddr = true; - if let SockAddr::Inet(InetAddr::V4(a)) = lo { - assert_eq!(a.sin_addr.s_addr, + if let Some(sin) = lo.as_sockaddr_in() { + assert_eq!(sin.as_ref().sin_addr.s_addr, addr.s_addr, "unexpected destination address (expected {}, got {})", - a.sin_addr.s_addr, + sin.as_ref().sin_addr.s_addr, addr.s_addr); } else { panic!("unexpected Sockaddr"); @@ -1535,7 +1489,7 @@ pub fn test_recvif() { pub fn test_recv_ipv6pktinfo() { use nix::net::if_::*; use nix::sys::socket::sockopt::Ipv6RecvPacketInfo; - use nix::sys::socket::{bind, SockFlag, SockType}; + use nix::sys::socket::{bind, SockaddrIn6, SockFlag, SockType}; use nix::sys::socket::{getsockname, setsockopt, socket}; use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; use nix::sys::uio::IoVec; @@ -1553,7 +1507,7 @@ pub fn test_recv_ipv6pktinfo() { None, ).expect("receive socket failed"); bind(receive, &lo).expect("bind failed"); - let sa = getsockname(receive).expect("getsockname failed"); + let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed"); setsockopt(receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed"); { @@ -1573,7 +1527,7 @@ pub fn test_recv_ipv6pktinfo() { let mut buf = [0u8; 8]; let iovec = [IoVec::from_mut_slice(&mut buf)]; let mut space = cmsg_space!(libc::in6_pktinfo); - let msg = recvmsg( + let msg = recvmsg::<()>( receive, &iovec, Some(&mut space), @@ -1611,7 +1565,7 @@ pub fn test_recv_ipv6pktinfo() { pub fn test_vsock() { use nix::errno::Errno; use nix::sys::socket::{AddressFamily, socket, bind, connect, listen, - SockAddr, SockType, SockFlag}; + SockType, SockFlag, VsockAddr}; use nix::unistd::{close}; use std::thread; @@ -1622,12 +1576,12 @@ pub fn test_vsock() { .expect("socket failed"); // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error. - let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_HYPERVISOR, port); - assert_eq!(bind(s1, &sockaddr).err(), + let sockaddr_hv = VsockAddr::new(libc::VMADDR_CID_HYPERVISOR, port); + assert_eq!(bind(s1, &sockaddr_hv).err(), Some(Errno::EADDRNOTAVAIL)); - let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port); - assert_eq!(bind(s1, &sockaddr), Ok(())); + let sockaddr_any = VsockAddr::new(libc::VMADDR_CID_ANY, port); + assert_eq!(bind(s1, &sockaddr_any), Ok(())); listen(s1, 10).expect("listen failed"); let thr = thread::spawn(move || { @@ -1637,11 +1591,11 @@ pub fn test_vsock() { SockFlag::empty(), None) .expect("socket failed"); - let sockaddr = SockAddr::new_vsock(cid, port); + let sockaddr_host = VsockAddr::new(cid, port); // The current implementation does not support loopback devices, so, // for now, we expect a failure on the connect. - assert_ne!(connect(s2, &sockaddr), Ok(())); + assert_ne!(connect(s2, &sockaddr_host), Ok(())); close(s2).unwrap(); }); @@ -1669,9 +1623,9 @@ fn test_recvmsg_timestampns() { SockFlag::empty(), None).unwrap(); setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); - let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); - bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); - let address = getsockname(in_socket).unwrap(); + let localhost = SockaddrIn::new(127, 0, 0, 1, 0); + bind(in_socket, &localhost).unwrap(); + let address: SockaddrIn = getsockname(in_socket).unwrap(); // Get initial time let time0 = SystemTime::now(); // Send the message @@ -1683,7 +1637,7 @@ fn test_recvmsg_timestampns() { let mut buffer = vec![0u8; message.len()]; let mut cmsgspace = nix::cmsg_space!(TimeSpec); let iov = [IoVec::from_mut_slice(&mut buffer)]; - let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap(); + let r = recvmsg::<()>(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap(); let rtime = match r.cmsgs().next() { Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, Some(_) => panic!("Unexpected control message"), @@ -1720,9 +1674,9 @@ fn test_recvmmsg_timestampns() { SockFlag::empty(), None).unwrap(); setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); - let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); - bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); - let address = getsockname(in_socket).unwrap(); + let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); + bind(in_socket, &localhost).unwrap(); + let address: SockaddrIn = getsockname(in_socket).unwrap(); // Get initial time let time0 = SystemTime::now(); // Send the message @@ -1740,7 +1694,7 @@ fn test_recvmmsg_timestampns() { cmsg_buffer: Some(&mut cmsgspace), }, ]; - let r = recvmmsg(in_socket, &mut data, flags, None).unwrap(); + let r: Vec> = recvmmsg(in_socket, &mut data, flags, None).unwrap(); let rtime = match r[0].cmsgs().next() { Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, Some(_) => panic!("Unexpected control message"), @@ -1783,10 +1737,10 @@ fn test_recvmsg_rxq_ovfl() { SockFlag::empty(), None).unwrap(); - let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); - bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); + let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); + bind(in_socket, &localhost).unwrap(); - let address = getsockname(in_socket).unwrap(); + let address: SockaddrIn = getsockname(in_socket).unwrap(); connect(out_socket, &address).unwrap(); // Set SO_RXQ_OVFL flag. @@ -1815,7 +1769,7 @@ fn test_recvmsg_rxq_ovfl() { let iov = [IoVec::from_mut_slice(&mut buffer)]; - match recvmsg( + match recvmsg::<()>( in_socket, &iov, Some(&mut cmsgspace), @@ -1847,7 +1801,7 @@ fn test_recvmsg_rxq_ovfl() { ))] mod linux_errqueue { use nix::sys::socket::*; - use super::{FromStr, SocketAddr}; + use super::FromStr; // Send a UDP datagram to a bogus destination address and observe an ICMP error (v4). // @@ -1953,12 +1907,8 @@ mod linux_errqueue { use nix::sys::uio::IoVec; const MESSAGE_CONTENTS: &str = "ABCDEF"; - - let sock_addr = { - let std_sa = SocketAddr::from_str(sa).unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - SockAddr::new_inet(inet_addr) - }; + let std_sa = std::net::SocketAddr::from_str(sa).unwrap(); + let sock_addr = SockaddrStorage::from(std_sa); let sock = socket(af, SockType::Datagram, SockFlag::SOCK_CLOEXEC, None).unwrap(); setsockopt(sock, opt, &true).unwrap(); if let Err(e) = sendto(sock, MESSAGE_CONTENTS.as_bytes(), &sock_addr, MsgFlags::empty()) { @@ -2006,16 +1956,14 @@ mod linux_errqueue { pub fn test_txtime() { use nix::sys::socket::{ bind, recvmsg, sendmsg, setsockopt, socket, sockopt, ControlMessage, - MsgFlags, SockFlag, SockType, + MsgFlags, SockaddrIn, SockFlag, SockType, }; use nix::sys::time::TimeValLike; use nix::time::{ClockId, clock_gettime}; require_kernel_version!(test_txtime, ">= 5.8"); - let std_sa = SocketAddr::from_str("127.0.0.1:6802").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let sock_addr = SockaddrIn::from_str("127.0.0.1:6802").unwrap(); let ssock = socket( AddressFamily::Inet, @@ -2052,5 +2000,5 @@ pub fn test_txtime() { let mut rbuf = [0u8; 2048]; let iov2 = [nix::sys::uio::IoVec::from_mut_slice(&mut rbuf)]; - recvmsg(rsock, &iov2, None, MsgFlags::empty()).unwrap(); + recvmsg::<()>(rsock, &iov2, None, MsgFlags::empty()).unwrap(); } diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 59b97c8b7a..df01e9ee11 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -72,14 +72,13 @@ fn test_so_buf() { #[test] fn test_so_tcp_maxseg() { - use std::net::SocketAddr; + use std::net::SocketAddrV4; use std::str::FromStr; - use nix::sys::socket::{accept, bind, connect, listen, InetAddr, SockAddr}; + use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn}; use nix::unistd::{close, write}; - let std_sa = SocketAddr::from_str("127.0.0.1:4001").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); let rsock = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp) .unwrap(); From fbeabf3730e42ae062a3ddeaa4b28134fdb8e0f6 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 21 Mar 2022 21:39:25 -0600 Subject: [PATCH 075/358] Deprecate IpAddr, Ipv4Addr, and Ipv6Addr Because they're redundant with types in the standard library. Fixes #1681 --- CHANGELOG.md | 3 ++ src/sys/socket/addr.rs | 73 ++++++++++++++++++++++++++++++++++++----- src/sys/socket/mod.rs | 21 +++++++++--- test/sys/test_socket.rs | 6 ++-- 4 files changed, 87 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 737148af47..f52b5cdcf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Deprecated `InetAddr` and `SockAddr` in favor of `SockaddrIn`, `SockaddrIn6`, and `SockaddrStorage`. (#[1684](https://github.com/nix-rust/nix/pull/1684)) +- Deprecated `IpAddr`, `Ipv4Addr`, and `Ipv6Addr` in favor of their equivalents + from the standard library. + (#[1685](https://github.com/nix-rust/nix/pull/1685)) ### Fixed diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 9d22beea58..faaa7211ab 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -32,6 +32,26 @@ pub use self::datalink::LinkAddr; #[cfg(any(target_os = "android", target_os = "linux"))] pub use self::vsock::VsockAddr; +/// Convert a std::net::Ipv4Addr into the libc form. +#[cfg(feature = "net")] +pub(crate) fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { + let octets = addr.octets(); + libc::in_addr { + s_addr: u32::to_be(((octets[0] as u32) << 24) | + ((octets[1] as u32) << 16) | + ((octets[2] as u32) << 8) | + (octets[3] as u32)) + } +} + +/// Convert a std::net::Ipv6Addr into the libc form. +#[cfg(feature = "net")] +pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr { + libc::in6_addr { + s6_addr: addr.octets() + } +} + /// These constants specify the protocol family to be used /// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) /// @@ -497,14 +517,20 @@ impl fmt::Display for InetAddr { * ===== IpAddr ===== * */ -#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 +#[allow(missing_docs)] // Since they're all deprecated anyway +#[allow(deprecated)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[deprecated( + since = "0.24.0", + note = "Use std::net::IpAddr instead" +)] pub enum IpAddr { V4(Ipv4Addr), V6(Ipv6Addr), } -#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 +#[allow(deprecated)] +#[allow(missing_docs)] // Since they're all deprecated anyway impl IpAddr { /// Create a new IpAddr that contains an IPv4 address. /// @@ -537,6 +563,7 @@ impl IpAddr { } } +#[allow(deprecated)] impl fmt::Display for IpAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -552,12 +579,17 @@ impl fmt::Display for IpAddr { * */ -#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 +#[deprecated( + since = "0.24.0", + note = "Use std::net::Ipv4Addr instead" +)] +#[allow(missing_docs)] // Since they're all deprecated anyway #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct Ipv4Addr(pub libc::in_addr); -#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 +#[allow(deprecated)] +#[allow(missing_docs)] // Since they're all deprecated anyway impl Ipv4Addr { #[allow(clippy::identity_op)] // More readable this way pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { @@ -591,6 +623,7 @@ impl Ipv4Addr { } } +#[allow(deprecated)] impl fmt::Display for Ipv4Addr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let octets = self.octets(); @@ -604,7 +637,11 @@ impl fmt::Display for Ipv4Addr { * */ -#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 +#[deprecated( + since = "0.24.0", + note = "Use std::net::Ipv6Addr instead" +)] +#[allow(missing_docs)] // Since they're all deprecated anyway #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct Ipv6Addr(pub libc::in6_addr); @@ -625,7 +662,8 @@ macro_rules! to_u16_array { } } -#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 +#[allow(deprecated)] +#[allow(missing_docs)] // Since they're all deprecated anyway impl Ipv6Addr { #[allow(clippy::many_single_char_names)] #[allow(clippy::too_many_arguments)] @@ -649,6 +687,7 @@ impl Ipv6Addr { } } +#[allow(deprecated)] impl fmt::Display for Ipv6Addr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { self.to_std().fmt(fmt) @@ -1172,7 +1211,7 @@ impl From for SockaddrIn { sin_len: mem::size_of::() as u8, sin_family: AddressFamily::Inet as sa_family_t, sin_port: addr.port().to_be(), // network byte order - sin_addr: Ipv4Addr::from_std(addr.ip()).0, + sin_addr: ipv4addr_to_libc(*addr.ip()), .. unsafe { mem::zeroed() } }) } @@ -1266,7 +1305,7 @@ impl From for SockaddrIn6 { sin6_len: mem::size_of::() as u8, sin6_family: AddressFamily::Inet6 as sa_family_t, sin6_port: addr.port().to_be(), // network byte order - sin6_addr: Ipv6Addr::from_std(addr.ip()).0, + sin6_addr: ipv6addr_to_libc(addr.ip()), sin6_flowinfo: addr.flowinfo(), // host byte order sin6_scope_id: addr.scope_id(), // host byte order .. unsafe { mem::zeroed() } @@ -2545,6 +2584,24 @@ pub mod vsock { mod tests { use super::*; + mod types { + use super::*; + + #[test] + fn test_ipv4addr_to_libc() { + let s = std::net::Ipv4Addr::new(1, 2, 3, 4); + let l = ipv4addr_to_libc(s); + assert_eq!(l.s_addr, u32::to_be(0x01020304)); + } + + #[test] + fn test_ipv6addr_to_libc() { + let s = std::net::Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8); + let l = ipv6addr_to_libc(&s); + assert_eq!(l.s6_addr, [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8]); + } + } + mod link { #[cfg(any(target_os = "ios", target_os = "macos", diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index f5004b4541..8dac6eda32 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -8,6 +8,8 @@ use libc::{self, c_void, c_int, iovec, socklen_t, size_t, use std::convert::TryInto; use std::{mem, ptr, slice}; use std::os::unix::io::RawFd; +#[cfg(feature = "net")] +use std::net; #[cfg(target_os = "linux")] #[cfg(feature = "uio")] use crate::sys::time::TimeSpec; @@ -93,6 +95,9 @@ pub use libc::{sockaddr_in, sockaddr_in6}; #[doc(hidden)] pub use libc::{c_uint, CMSG_SPACE}; +#[cfg(feature = "net")] +use crate::sys::socket::addr::{ipv4addr_to_libc, ipv6addr_to_libc}; + /// These constants are used to specify the communication semantics /// when creating a socket with [`socket()`](fn.socket.html) #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -496,10 +501,16 @@ impl IpMembershipRequest { /// Instantiate a new `IpMembershipRequest` /// /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface. - pub fn new(group: Ipv4Addr, interface: Option) -> Self { + pub fn new(group: net::Ipv4Addr, interface: Option) + -> Self + { + let imr_addr = match interface { + None => net::Ipv4Addr::UNSPECIFIED, + Some(addr) => addr + }; IpMembershipRequest(libc::ip_mreq { - imr_multiaddr: group.0, - imr_interface: interface.unwrap_or_else(Ipv4Addr::any).0, + imr_multiaddr: ipv4addr_to_libc(group), + imr_interface: ipv4addr_to_libc(imr_addr) }) } } @@ -513,9 +524,9 @@ pub struct Ipv6MembershipRequest(libc::ipv6_mreq); impl Ipv6MembershipRequest { /// Instantiate a new `Ipv6MembershipRequest` - pub const fn new(group: Ipv6Addr) -> Self { + pub const fn new(group: net::Ipv6Addr) -> Self { Ipv6MembershipRequest(libc::ipv6_mreq { - ipv6mr_multiaddr: group.0, + ipv6mr_multiaddr: ipv6addr_to_libc(&group), ipv6mr_interface: 0, }) } diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index e03edc3b40..c18442fd04 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1833,7 +1833,7 @@ mod linux_errqueue { if let Some(origin) = err_addr { // Validate that our network error originated from 127.0.0.1:0. assert_eq!(origin.sin_family, AddressFamily::Inet as _); - assert_eq!(Ipv4Addr(origin.sin_addr), Ipv4Addr::new(127, 0, 0, 1)); + assert_eq!(origin.sin_addr.s_addr, u32::from_be(0x7f000001)); assert_eq!(origin.sin_port, 0); } else { panic!("Expected some error origin"); @@ -1877,8 +1877,8 @@ mod linux_errqueue { // Validate that our network error originated from localhost:0. assert_eq!(origin.sin6_family, AddressFamily::Inet6 as _); assert_eq!( - Ipv6Addr(origin.sin6_addr), - Ipv6Addr::from_std(&"::1".parse().unwrap()), + origin.sin6_addr.s6_addr, + std::net::Ipv6Addr::LOCALHOST.octets() ); assert_eq!(origin.sin6_port, 0); } else { From 350423ca02403892081b1db4d7cc4267d8209587 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 22 Mar 2022 21:02:02 -0600 Subject: [PATCH 076/358] [skip ci] better docs for SockaddrLike::from_raw Fixes #1680 --- src/sys/socket/addr.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 9d22beea58..f5452d2717 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -975,10 +975,22 @@ pub trait SockaddrLike: private::SockaddrLikePriv { /// Some C APIs from provide `len`, and others do not. If it's provided it /// will be validated. If not, it will be guessed based on the family. /// + /// # Arguments + /// + /// - `addr`: raw pointer to something that can be cast to a + /// `libc::sockaddr`. For example, `libc::sockaddr_in`, + /// `libc::sockaddr_in6`, etc. + /// - `len`: For fixed-width types like `sockaddr_in`, it will be + /// validated if present and ignored if not. For variable-width + /// types it is required and must be the total length of valid + /// data. For example, if `addr` points to a + /// named `sockaddr_un`, then `len` must be the length of the + /// structure up to but not including the trailing NUL. + /// /// # Safety /// /// `addr` must be valid for the specific type of sockaddr. `len`, if - /// present, must be the length of valid data in `addr`. + /// present, must not exceed the length of valid data in `addr`. unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) -> Option where Self: Sized; From 4ae4cfd0588fbe93e1cc6501bcb98893ebdf26f3 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Wed, 23 Mar 2022 05:28:29 +0000 Subject: [PATCH 077/358] Make `uname` always safe This fixes several issues with the current `uname` bindings: - Do not ignore `uname` errors; at least on glibc `uname` can fail, so now it returns a `Result` instead of assuming that the call will always succeed. - Do not assume `uname` will initialize every member of `utsname`; not every implementation initializes every field, so internally the struct is now zero-initialized. - Do not blindly assume strings returned by `uname` will always be valid UTF-8; `UtsName`'s accessors will now return `&OsStr`s instead of `&str`s. --- CHANGELOG.md | 2 ++ src/features.rs | 22 +++++++++--------- src/sys/utsname.rs | 56 ++++++++++++++++++++++++---------------------- test/common/mod.rs | 14 ++++++------ 4 files changed, 50 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f52b5cdcf4..af84248e33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Deprecated `IpAddr`, `Ipv4Addr`, and `Ipv6Addr` in favor of their equivalents from the standard library. (#[1685](https://github.com/nix-rust/nix/pull/1685)) +- `uname` now returns a `Result` instead of blindly assuming the call never fails. +- Getters on the `UtsName` struct now return a `&OsStr` instead of `&str`. ### Fixed diff --git a/src/features.rs b/src/features.rs index ed80fd714b..6108098610 100644 --- a/src/features.rs +++ b/src/features.rs @@ -3,7 +3,9 @@ pub use self::os::*; #[cfg(any(target_os = "linux", target_os = "android"))] mod os { + use std::os::unix::ffi::OsStrExt; use crate::sys::utsname::uname; + use crate::Result; // Features: // * atomic cloexec on socket: 2.6.27 @@ -22,15 +24,15 @@ mod os { *dst += (b - b'0') as usize; } - fn parse_kernel_version() -> usize { - let u = uname(); + fn parse_kernel_version() -> Result { + let u = uname()?; let mut curr: usize = 0; let mut major: usize = 0; let mut minor: usize = 0; let mut patch: usize = 0; - for b in u.release().bytes() { + for &b in u.release().as_bytes() { if curr >= 3 { break; } @@ -50,7 +52,7 @@ mod os { } } - if major >= 3 { + Ok(if major >= 3 { VERS_3 } else if major >= 2 { if minor >= 7 { @@ -68,29 +70,29 @@ mod os { } } else { VERS_UNKNOWN - } + }) } - fn kernel_version() -> usize { + fn kernel_version() -> Result { static mut KERNEL_VERS: usize = 0; unsafe { if KERNEL_VERS == 0 { - KERNEL_VERS = parse_kernel_version(); + KERNEL_VERS = parse_kernel_version()?; } - KERNEL_VERS + Ok(KERNEL_VERS) } } /// Check if the OS supports atomic close-on-exec for sockets pub fn socket_atomic_cloexec() -> bool { - kernel_version() >= VERS_2_6_27 + kernel_version().map(|version| version >= VERS_2_6_27).unwrap_or(false) } #[test] pub fn test_parsing_kernel_version() { - assert!(kernel_version() > 0); + assert!(kernel_version().unwrap() > 0); } } diff --git a/src/sys/utsname.rs b/src/sys/utsname.rs index 98edee0428..5bd3a539ae 100644 --- a/src/sys/utsname.rs +++ b/src/sys/utsname.rs @@ -1,8 +1,9 @@ //! Get system identification use std::mem; -use libc::{self, c_char}; -use std::ffi::CStr; -use std::str::from_utf8_unchecked; +use std::os::unix::ffi::OsStrExt; +use std::ffi::OsStr; +use libc::c_char; +use crate::{Errno, Result}; /// Describes the running system. Return type of [`uname`]. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -10,47 +11,48 @@ use std::str::from_utf8_unchecked; 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) + /// Name of the operating system implementation. + pub fn sysname(&self) -> &OsStr { + cast_and_trim(&self.0.sysname) } /// Network name of this machine. - pub fn nodename(&self) -> &str { - to_str(&(&self.0.nodename as *const c_char ) as *const *const c_char) + pub fn nodename(&self) -> &OsStr { + cast_and_trim(&self.0.nodename) } /// 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) + pub fn release(&self) -> &OsStr { + cast_and_trim(&self.0.release) } /// 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) + pub fn version(&self) -> &OsStr { + cast_and_trim(&self.0.version) } /// Machine hardware platform. - pub fn machine(&self) -> &str { - to_str(&(&self.0.machine as *const c_char ) as *const *const c_char) + pub fn machine(&self) -> &OsStr { + cast_and_trim(&self.0.machine) } } /// Get system identification -pub fn uname() -> UtsName { +pub fn uname() -> Result { unsafe { - let mut ret = mem::MaybeUninit::uninit(); - libc::uname(ret.as_mut_ptr()); - UtsName(ret.assume_init()) + let mut ret = mem::MaybeUninit::zeroed(); + Errno::result(libc::uname(ret.as_mut_ptr()))?; + Ok(UtsName(ret.assume_init())) } } -#[inline] -fn to_str<'a>(s: *const *const c_char) -> &'a str { - unsafe { - let res = CStr::from_ptr(*s).to_bytes(); - from_utf8_unchecked(res) - } +fn cast_and_trim(slice: &[c_char]) -> &OsStr { + let length = slice.iter().position(|&byte| byte == 0).unwrap_or(slice.len()); + let bytes = unsafe { + std::slice::from_raw_parts(slice.as_ptr().cast(), length) + }; + + OsStr::from_bytes(bytes) } #[cfg(test)] @@ -58,18 +60,18 @@ mod test { #[cfg(target_os = "linux")] #[test] pub fn test_uname_linux() { - assert_eq!(super::uname().sysname(), "Linux"); + assert_eq!(super::uname().unwrap().sysname(), "Linux"); } #[cfg(any(target_os = "macos", target_os = "ios"))] #[test] pub fn test_uname_darwin() { - assert_eq!(super::uname().sysname(), "Darwin"); + assert_eq!(super::uname().unwrap().sysname(), "Darwin"); } #[cfg(target_os = "freebsd")] #[test] pub fn test_uname_freebsd() { - assert_eq!(super::uname().sysname(), "FreeBSD"); + assert_eq!(super::uname().unwrap().sysname(), "FreeBSD"); } } diff --git a/test/common/mod.rs b/test/common/mod.rs index 84a0b4fa30..544a1ae3f0 100644 --- a/test/common/mod.rs +++ b/test/common/mod.rs @@ -111,15 +111,15 @@ cfg_if! { let version_requirement = VersionReq::parse($version_requirement) .expect("Bad match_version provided"); - let uname = nix::sys::utsname::uname(); - println!("{}", uname.sysname()); - println!("{}", uname.nodename()); - println!("{}", uname.release()); - println!("{}", uname.version()); - println!("{}", uname.machine()); + let uname = nix::sys::utsname::uname().unwrap(); + println!("{}", uname.sysname().to_str().unwrap()); + println!("{}", uname.nodename().to_str().unwrap()); + println!("{}", uname.release().to_str().unwrap()); + println!("{}", uname.version().to_str().unwrap()); + println!("{}", uname.machine().to_str().unwrap()); // Fix stuff that the semver parser can't handle - let fixed_release = &uname.release().to_string() + let fixed_release = &uname.release().to_str().unwrap().to_string() // Fedora 33 reports version as 4.18.el8_2.x86_64 or // 5.18.200-fc33.x86_64. Remove the underscore. .replace("_", "-") From 6a1f5452ae1ddfc16cccd08c6319efcce3256116 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 25 Mar 2022 17:02:30 -0600 Subject: [PATCH 078/358] [skip ci] edit CHANGELOG formatting prior to 0.24.0 release --- CHANGELOG.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af84248e33..f8377ca44f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,13 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added fine-grained features flags. Most Nix functionality can now be + conditionally enabled. By default, all features are enabled. + (#[1611](https://github.com/nix-rust/nix/pull/1611)) - Added `fexecve` on DragonFly. (#[1577](https://github.com/nix-rust/nix/pull/1577)) - `sys::uio::IoVec` is now `Send` and `Sync` (#[1582](https://github.com/nix-rust/nix/pull/1582)) -- Added fine-grained features flags. Most Nix functionality can now be - conditionally enabled. By default, all features are enabled. - (#[1611](https://github.com/nix-rust/nix/pull/1611)) - Added `EPOLLEXCLUSIVE` on Android. (#[1567](https://github.com/nix-rust/nix/pull/1567)) - Added `fdatasync` for FreeBSD, Fuchsia, NetBSD, and OpenBSD. @@ -21,7 +21,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1537](https://github.com/nix-rust/nix/pull/1537)) - Added `posix_fallocate` on DragonFly. (#[1621](https://github.com/nix-rust/nix/pull/1621)) -- Added the `SO_TIMESTAMPING` support +- Added `SO_TIMESTAMPING` support (#[1547](https://github.com/nix-rust/nix/pull/1547)) - Added getter methods to `MqAttr` struct (#[1619](https://github.com/nix-rust/nix/pull/1619)) @@ -71,6 +71,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Removed the the `PATH_MAX` restriction from APIs accepting paths. Paths will now be allocated on the heap if they are too long. In addition, large instruction count improvements (~30x) were made to path handling. + (#[1656](https://github.com/nix-rust/nix/pull/1656)) - Changed `getrlimit` and `setrlimit` to use `rlim_t` directly instead of `Option`. (#[1668](https://github.com/nix-rust/nix/pull/1668)) @@ -80,8 +81,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Deprecated `IpAddr`, `Ipv4Addr`, and `Ipv6Addr` in favor of their equivalents from the standard library. (#[1685](https://github.com/nix-rust/nix/pull/1685)) -- `uname` now returns a `Result` instead of blindly assuming the call never fails. -- Getters on the `UtsName` struct now return a `&OsStr` instead of `&str`. +- `uname` now returns a `Result` instead of just a `UtsName` and + ignoring failures from libc. And getters on the `UtsName` struct now return + an `&OsStr` instead of `&str`. + (#[1672](https://github.com/nix-rust/nix/pull/1672)) ### Fixed From 333d03be5df6c0c52435ea92d73c4c5689e847e8 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 25 Mar 2022 18:09:37 -0600 Subject: [PATCH 079/358] Use the nightly toolchain for Redox The latest redox-syscall crate requires at least Rust 1.59.0, but they don't define an MSRV policy. And the version given in the rust-toolchain file in the Redox repository doesn't work. So until they clarify their MSRV, use nightly. https://gitlab.redox-os.org/redox-os/syscall/-/commit/30f29c32952343412bb6c36c9fda136d26e9431f --- .cirrus.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 4fd93a36b7..cc5f216da5 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -262,10 +262,8 @@ task: name: Redox x86_64 env: TARGET: x86_64-unknown-redox - # Redox requires a nightly compiler. - # If stuff breaks, change nightly to the date at - # https://gitlab.redox-os.org/redox-os/redox/-/blob/master/rust-toolchain - TOOLCHAIN: nightly-2021-06-15 + # Redox's MSRV policy is unclear. Until they define it, use nightly. + TOOLCHAIN: nightly setup_script: - rustup target add $TARGET - rustup toolchain install $TOOLCHAIN --profile minimal --target $TARGET From 42f671b1e6cd4f9e27d57eed075ae385aae785f0 Mon Sep 17 00:00:00 2001 From: Felix Obenhuber Date: Fri, 25 Mar 2022 09:33:54 +0100 Subject: [PATCH 080/358] Enable statfs magic constants for target_os = "android" The statfs magic constants of file systems types are available on target_os android and the cfg guard is updated accordingly. Sync the list of constant with the constants declared in libc. Fixes #1689 --- CHANGELOG.md | 3 + src/sys/statfs.rs | 140 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 106 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8377ca44f..4c1f90ebff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added fine-grained features flags. Most Nix functionality can now be conditionally enabled. By default, all features are enabled. (#[1611](https://github.com/nix-rust/nix/pull/1611)) +- Added statfs FS type magic constants for `target_os = "android"` + and synced constants with libc v0.2.121. + (#[1690](https://github.com/nix-rust/nix/pull/1690)) - Added `fexecve` on DragonFly. (#[1577](https://github.com/nix-rust/nix/pull/1577)) - `sys::uio::IoVec` is now `Send` and `Sync` diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 98f7e5dd45..5a7ac11aff 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -49,96 +49,162 @@ 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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const AFS_SUPER_MAGIC: FsType = FsType(libc::AFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const AUTOFS_SUPER_MAGIC: FsType = FsType(libc::AUTOFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const BPF_FS_MAGIC: FsType = FsType(libc::BPF_FS_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const BTRFS_SUPER_MAGIC: FsType = FsType(libc::BTRFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const DEBUGFS_MAGIC: FsType = FsType(libc::DEBUGFS_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const DEVPTS_SUPER_MAGIC: FsType = FsType(libc::DEVPTS_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const ECRYPTFS_SUPER_MAGIC: FsType = FsType(libc::ECRYPTFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[allow(missing_docs)] pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC as fs_type_t); -#[cfg(all(target_os = "linux", not(any(target_env = "musl", target_env = "uclibc"))))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const F2FS_SUPER_MAGIC: FsType = FsType(libc::F2FS_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[allow(missing_docs)] pub const FUSE_SUPER_MAGIC: FsType = FsType(libc::FUSE_SUPER_MAGIC as fs_type_t); -#[cfg(all(target_os = "linux", not(target_env = "musl")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const FUTEXFS_SUPER_MAGIC: FsType = FsType(libc::FUTEXFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const HOSTFS_SUPER_MAGIC: FsType = FsType(libc::HOSTFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +pub const MINIX3_SUPER_MAGIC: FsType = FsType(libc::MINIX3_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const NILFS_SUPER_MAGIC: FsType = FsType(libc::NILFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const OCFS2_SUPER_MAGIC: FsType = FsType(libc::OCFS2_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const QNX6_SUPER_MAGIC: FsType = FsType(libc::QNX6_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const RDTGROUP_SUPER_MAGIC: FsType = FsType(libc::RDTGROUP_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const SECURITYFS_MAGIC: FsType = FsType(libc::SECURITYFS_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const SELINUX_MAGIC: FsType = FsType(libc::SELINUX_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const SMACK_MAGIC: FsType = FsType(libc::SMACK_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const SYSFS_MAGIC: FsType = FsType(libc::SYSFS_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +pub const TRACEFS_MAGIC: FsType = FsType(libc::TRACEFS_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[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")))] +pub const UDF_SUPER_MAGIC: FsType = FsType(libc::UDF_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] #[allow(missing_docs)] -pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t); +pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t); +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[allow(missing_docs)] +pub const XENFS_SUPER_MAGIC: FsType = FsType(libc::XENFS_SUPER_MAGIC as fs_type_t); impl Statfs { From a4b5dfc059b11e7d463710bfcafa216eee770413 Mon Sep 17 00:00:00 2001 From: Junho Choi Date: Tue, 5 Apr 2022 15:06:13 -0700 Subject: [PATCH 081/358] Add IP_DONTFRAG and IPV6_DONTFRAG SockOpts IP_DONTFRAG: iOS, macOS IPV6_DONTFRAG: android, iOS, linux and macOS Test: `cargo test --test test dontfrag_opts` Some CI tests running ENOPROTOOPT are disabled (qemu-based). --- CHANGELOG.md | 3 +++ src/sys/socket/sockopt.rs | 13 +++++++++++++ test/sys/test_sockopt.rs | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c1f90ebff..4e3e2974c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1670](https://github.com/nix-rust/nix/pull/1670)) - Added `waitid`. (#[1584](https://github.com/nix-rust/nix/pull/1584)) +- Added `Ipv6DontFrag` for android, iOS, linux and macOS. +- Added `IpDontFrag` for iOS, macOS. + (#[1692](https://github.com/nix-rust/nix/pull/1692)) ### Changed diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index c600391c64..e80b09e771 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -615,6 +615,19 @@ sockopt_impl!( sockopt_impl!( /// Set the unicast hop limit for the socket. Ipv6Ttl, Both, libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS, libc::c_int); +#[cfg(any(target_os = "ios", target_os = "macos"))] +sockopt_impl!( + /// Set "don't fragment packet" flag on the IP packet. + IpDontFrag, Both, libc::IPPROTO_IP, libc::IP_DONTFRAG, bool); +#[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", +))] +sockopt_impl!( + /// Set "don't fragment packet" flag on the IPv6 packet. + Ipv6DontFrag, Both, libc::IPPROTO_IPV6, libc::IPV6_DONTFRAG, bool); #[allow(missing_docs)] // Not documented by Linux! diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index df01e9ee11..4f75e17846 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -196,3 +196,42 @@ fn test_ttl_opts() { setsockopt(fd6, sockopt::Ipv6Ttl, &1) .expect("setting ipv6ttl on an inet6 socket should succeed"); } + +#[test] +#[cfg(any(target_os = "ios", target_os = "macos"))] +fn test_dontfrag_opts() { + let fd4 = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp).unwrap(); + setsockopt(fd4, sockopt::IpDontFrag, &true) + .expect("setting IP_DONTFRAG on an inet stream socket should succeed"); + setsockopt(fd4, sockopt::IpDontFrag, &false) + .expect("unsetting IP_DONTFRAG on an inet stream socket should succeed"); + let fd4d = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap(); + setsockopt(fd4d, sockopt::IpDontFrag, &true) + .expect("setting IP_DONTFRAG on an inet datagram socket should succeed"); + setsockopt(fd4d, sockopt::IpDontFrag, &false) + .expect("unsetting IP_DONTFRAG on an inet datagram socket should succeed"); +} + +#[test] +#[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + ) +)] +// Disable the test under emulation because it fails in Cirrus-CI. Lack +// of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] +fn test_v6dontfrag_opts() { + let fd6 = socket(AddressFamily::Inet6, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp).unwrap(); + setsockopt(fd6, sockopt::Ipv6DontFrag, &true) + .expect("setting IPV6_DONTFRAG on an inet6 stream socket should succeed"); + setsockopt(fd6, sockopt::Ipv6DontFrag, &false) + .expect("unsetting IPV6_DONTFRAG on an inet6 stream socket should succeed"); + let fd6d = socket(AddressFamily::Inet6, SockType::Datagram, SockFlag::empty(), None).unwrap(); + setsockopt(fd6d, sockopt::Ipv6DontFrag, &true) + .expect("setting IPV6_DONTFRAG on an inet6 datagram socket should succeed"); + setsockopt(fd6d, sockopt::Ipv6DontFrag, &false) + .expect("unsetting IPV6_DONTFRAG on an inet6 datagram socket should succeed"); +} From 0b58f2977252739629b5175043d705f7fc76ea8d Mon Sep 17 00:00:00 2001 From: not_a_seagull Date: Sun, 23 Jan 2022 11:43:25 -0800 Subject: [PATCH 082/358] Replace the IoVec type with IoSlice and IoSliceMut --- CHANGELOG.md | 2 + src/fcntl.rs | 2 +- src/mount/bsd.rs | 111 +++++++++++++------------- src/sys/sendfile.rs | 16 ++-- src/sys/socket/mod.rs | 44 +++++------ src/sys/uio.rs | 163 ++++++++++++++++++++++---------------- test/sys/test_socket.rs | 171 +++++++++++++++++++++------------------- test/sys/test_uio.rs | 24 +++--- test/test_fcntl.rs | 7 +- 9 files changed, 292 insertions(+), 248 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8377ca44f..4261670afb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -85,6 +85,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ignoring failures from libc. And getters on the `UtsName` struct now return an `&OsStr` instead of `&str`. (#[1672](https://github.com/nix-rust/nix/pull/1672)) +- Replaced `IoVec` with `IoSlice` and `IoSliceMut`, and replaced `IoVec::from_slice` with + `IoSlice::new`. (#[1643](https://github.com/nix-rust/nix/pull/1643)) ### Fixed diff --git a/src/fcntl.rs b/src/fcntl.rs index 6c713608ee..fa64c8eaed 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -629,7 +629,7 @@ pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Resu #[cfg(any(target_os = "linux", target_os = "android"))] pub fn vmsplice( fd: RawFd, - iov: &[crate::sys::uio::IoVec<&[u8]>], + iov: &[std::io::IoSlice<'_>], flags: SpliceFFlags ) -> Result { diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs index ba0c1a2883..b4d611ee39 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd.rs @@ -3,7 +3,6 @@ use crate::{ Errno, NixPath, Result, - sys::uio::IoVec }; use libc::{c_char, c_int, c_uint, c_void}; use std::{ @@ -11,7 +10,7 @@ use std::{ ffi::{CString, CStr}, fmt, io, - ptr + marker::PhantomData, }; @@ -198,13 +197,45 @@ pub type NmountResult = std::result::Result<(), NmountError>; #[cfg_attr(docsrs, doc(cfg(all())))] #[derive(Debug, Default)] pub struct Nmount<'a>{ - iov: Vec>, + // n.b. notgull: In reality, this is a list that contains + // both mutable and immutable pointers. + // Be careful using this. + iov: Vec, is_owned: Vec, + marker: PhantomData<&'a ()>, } #[cfg(target_os = "freebsd")] #[cfg_attr(docsrs, doc(cfg(all())))] impl<'a> Nmount<'a> { + /// Helper function to push a slice onto the `iov` array. + fn push_slice(&mut self, val: &'a [u8], is_owned: bool) { + self.iov.push(libc::iovec { + iov_base: val.as_ptr() as *mut _, + iov_len: val.len(), + }); + self.is_owned.push(is_owned); + } + + /// Helper function to push a pointer and its length onto the `iov` array. + fn push_pointer_and_length(&mut self, val: *const u8, len: usize, is_owned: bool) { + self.iov.push(libc::iovec { + iov_base: val as *mut _, + iov_len: len, + }); + self.is_owned.push(is_owned); + } + + /// Helper function to push a `nix` path as owned. + fn push_nix_path(&mut self, val: &P) { + val.with_nix_path(|s| { + let len = s.to_bytes_with_nul().len(); + let ptr = s.to_owned().into_raw() as *const u8; + + self.push_pointer_and_length(ptr, len, true); + }).unwrap(); + } + /// Add an opaque mount option. /// /// Some file systems take binary-valued mount options. They can be set @@ -239,10 +270,8 @@ impl<'a> Nmount<'a> { len: usize ) -> &mut Self { - self.iov.push(IoVec::from_slice(name.to_bytes_with_nul())); - self.is_owned.push(false); - self.iov.push(IoVec::from_raw_parts(val, len)); - self.is_owned.push(false); + self.push_slice(name.to_bytes_with_nul(), false); + self.push_pointer_and_length(val.cast(), len, false); self } @@ -258,10 +287,8 @@ impl<'a> Nmount<'a> { /// .null_opt(&read_only); /// ``` pub fn null_opt(&mut self, name: &'a CStr) -> &mut Self { - self.iov.push(IoVec::from_slice(name.to_bytes_with_nul())); - self.is_owned.push(false); - self.iov.push(IoVec::from_raw_parts(ptr::null_mut(), 0)); - self.is_owned.push(false); + self.push_slice(name.to_bytes_with_nul(), false); + self.push_slice(&[], false); self } @@ -283,17 +310,8 @@ impl<'a> Nmount<'a> { /// ``` pub fn null_opt_owned(&mut self, name: &P) -> &mut Self { - name.with_nix_path(|s| { - let len = s.to_bytes_with_nul().len(); - self.iov.push(IoVec::from_raw_parts( - // Must free it later - s.to_owned().into_raw() as *mut c_void, - len - )); - self.is_owned.push(true); - }).unwrap(); - self.iov.push(IoVec::from_raw_parts(ptr::null_mut(), 0)); - self.is_owned.push(false); + self.push_nix_path(name); + self.push_slice(&[], false); self } @@ -315,10 +333,8 @@ impl<'a> Nmount<'a> { val: &'a CStr ) -> &mut Self { - self.iov.push(IoVec::from_slice(name.to_bytes_with_nul())); - self.is_owned.push(false); - self.iov.push(IoVec::from_slice(val.to_bytes_with_nul())); - self.is_owned.push(false); + self.push_slice(name.to_bytes_with_nul(), false); + self.push_slice(val.to_bytes_with_nul(), false); self } @@ -341,24 +357,8 @@ impl<'a> Nmount<'a> { where P1: ?Sized + NixPath, P2: ?Sized + NixPath { - name.with_nix_path(|s| { - let len = s.to_bytes_with_nul().len(); - self.iov.push(IoVec::from_raw_parts( - // Must free it later - s.to_owned().into_raw() as *mut c_void, - len - )); - self.is_owned.push(true); - }).unwrap(); - val.with_nix_path(|s| { - let len = s.to_bytes_with_nul().len(); - self.iov.push(IoVec::from_raw_parts( - // Must free it later - s.to_owned().into_raw() as *mut c_void, - len - )); - self.is_owned.push(true); - }).unwrap(); + self.push_nix_path(name); + self.push_nix_path(val); self } @@ -369,18 +369,19 @@ impl<'a> Nmount<'a> { /// Actually mount the file system. pub fn nmount(&mut self, flags: MntFlags) -> NmountResult { - // nmount can return extra error information via a "errmsg" return - // argument. const ERRMSG_NAME: &[u8] = b"errmsg\0"; let mut errmsg = vec![0u8; 255]; - self.iov.push(IoVec::from_raw_parts( - ERRMSG_NAME.as_ptr() as *mut c_void, - ERRMSG_NAME.len() - )); - self.iov.push(IoVec::from_raw_parts( - errmsg.as_mut_ptr() as *mut c_void, - errmsg.len() - )); + + // nmount can return extra error information via a "errmsg" return + // argument. + self.push_slice(ERRMSG_NAME, false); + + // SAFETY: we are pushing a mutable iovec here, so we can't use + // the above method + self.iov.push(libc::iovec { + iov_base: errmsg.as_mut_ptr() as *mut c_void, + iov_len: errmsg.len(), + }); let niov = self.iov.len() as c_uint; let iovp = self.iov.as_mut_ptr() as *mut libc::iovec; @@ -412,7 +413,7 @@ impl<'a> Drop for Nmount<'a> { // Free the owned string. Safe because we recorded ownership, // and Nmount does not implement Clone. unsafe { - drop(CString::from_raw(iov.0.iov_base as *mut c_char)); + drop(CString::from_raw(iov.iov_base as *mut c_char)); } } } diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs index 5ec0b52679..2ebcdf4889 100644 --- a/src/sys/sendfile.rs +++ b/src/sys/sendfile.rs @@ -68,13 +68,13 @@ cfg_if! { target_os = "freebsd", target_os = "ios", target_os = "macos"))] { - use crate::sys::uio::IoVec; + use std::io::IoSlice; - #[derive(Clone, Debug, Eq, Hash, PartialEq)] + #[derive(Clone, Debug)] struct SendfileHeaderTrailer<'a>( libc::sf_hdtr, - Option>>, - Option>>, + Option>>, + Option>>, ); impl<'a> SendfileHeaderTrailer<'a> { @@ -82,10 +82,10 @@ cfg_if! { headers: Option<&'a [&'a [u8]]>, trailers: Option<&'a [&'a [u8]]> ) -> SendfileHeaderTrailer<'a> { - let header_iovecs: Option>> = - headers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect()); - let trailer_iovecs: Option>> = - trailers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect()); + let header_iovecs: Option>> = + headers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); + let trailer_iovecs: Option>> = + trailers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect()); SendfileHeaderTrailer( libc::sf_hdtr { headers: { diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 8dac6eda32..c661389200 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -14,10 +14,8 @@ use std::net; #[cfg(feature = "uio")] use crate::sys::time::TimeSpec; #[cfg(feature = "uio")] -use crate::sys::{ - time::TimeVal, - uio::IoVec -}; +use crate::sys::time::TimeVal; +use std::io::{IoSlice, IoSliceMut}; #[deny(missing_docs)] mod addr; @@ -657,8 +655,8 @@ pub enum ControlMessageOwned { /// ``` /// # #[macro_use] extern crate nix; /// # use nix::sys::socket::*; - /// # use nix::sys::uio::IoVec; /// # use nix::sys::time::*; + /// # use std::io::{IoSlice, IoSliceMut}; /// # use std::time::*; /// # use std::str::FromStr; /// # fn main() { @@ -676,15 +674,15 @@ pub enum ControlMessageOwned { /// // Get initial time /// let time0 = SystemTime::now(); /// // Send the message - /// let iov = [IoVec::from_slice(message)]; + /// let iov = [IoSlice::new(message)]; /// let flags = MsgFlags::empty(); /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); /// assert_eq!(message.len(), l); /// // Receive the message /// let mut buffer = vec![0u8; message.len()]; /// let mut cmsgspace = cmsg_space!(TimeVal); - /// let iov = [IoVec::from_mut_slice(&mut buffer)]; - /// let r = recvmsg::(in_socket, &iov, Some(&mut cmsgspace), flags) + /// let mut iov = [IoSliceMut::new(&mut buffer)]; + /// let r = recvmsg::(in_socket, &mut iov, Some(&mut cmsgspace), flags) /// .unwrap(); /// let rtime = match r.cmsgs().next() { /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime, @@ -1367,13 +1365,13 @@ impl<'a> ControlMessage<'a> { /// ``` /// # use nix::sys::socket::*; /// # use nix::unistd::pipe; -/// # use nix::sys::uio::IoVec; +/// # use std::io::IoSlice; /// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, /// SockFlag::empty()) /// .unwrap(); /// let (r, w) = pipe().unwrap(); /// -/// let iov = [IoVec::from_slice(b"hello")]; +/// let iov = [IoSlice::new(b"hello")]; /// let fds = [r]; /// let cmsg = ControlMessage::ScmRights(&fds); /// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); @@ -1382,19 +1380,19 @@ impl<'a> ControlMessage<'a> { /// ``` /// # use nix::sys::socket::*; /// # use nix::unistd::pipe; -/// # use nix::sys::uio::IoVec; +/// # use std::io::IoSlice; /// # use std::str::FromStr; /// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap(); /// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), /// None).unwrap(); /// let (r, w) = pipe().unwrap(); /// -/// let iov = [IoVec::from_slice(b"hello")]; +/// let iov = [IoSlice::new(b"hello")]; /// let fds = [r]; /// let cmsg = ControlMessage::ScmRights(&fds); /// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); /// ``` -pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], +pub fn sendmsg(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage], flags: MsgFlags, addr: Option<&S>) -> Result where S: SockaddrLike { @@ -1420,7 +1418,7 @@ pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], #[derive(Debug)] pub struct SendMmsgData<'a, I, C, S> where - I: AsRef<[IoVec<&'a [u8]>]>, + I: AsRef<[IoSlice<'a>]>, C: AsRef<[ControlMessage<'a>]>, S: SockaddrLike + 'a { @@ -1459,7 +1457,7 @@ pub fn sendmmsg<'a, I, C, S>( flags: MsgFlags ) -> Result> where - I: AsRef<[IoVec<&'a [u8]>]> + 'a, + I: AsRef<[IoSlice<'a>]> + 'a, C: AsRef<[ControlMessage<'a>]> + 'a, S: SockaddrLike + 'a { @@ -1510,7 +1508,7 @@ pub fn sendmmsg<'a, I, C, S>( #[derive(Debug)] pub struct RecvMmsgData<'a, I> where - I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, + I: AsRef<[IoSliceMut<'a>]> + 'a, { pub iov: I, pub cmsg_buffer: Option<&'a mut Vec>, @@ -1557,7 +1555,7 @@ pub fn recvmmsg<'a, I, S>( timeout: Option ) -> Result>> where - I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, + I: AsRef<[IoSliceMut<'a>]> + 'a, S: Copy + SockaddrLike + 'a { let iter = data.into_iter(); @@ -1653,14 +1651,14 @@ unsafe fn read_mhdr<'a, 'b, S>( } } -unsafe fn pack_mhdr_to_receive<'a, I, S>( +unsafe fn pack_mhdr_to_receive<'outer, 'inner, I, S>( iov: I, cmsg_buffer: &mut Option<&mut Vec>, address: *mut S, ) -> (usize, msghdr) where - I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, - S: SockaddrLike + 'a + I: AsRef<[IoSliceMut<'inner>]> + 'outer, + S: SockaddrLike + 'outer { let (msg_control, msg_controllen) = cmsg_buffer.as_mut() .map(|v| (v.as_mut_ptr(), v.capacity())) @@ -1691,7 +1689,7 @@ fn pack_mhdr_to_send<'a, I, C, S>( addr: Option<&S> ) -> msghdr where - I: AsRef<[IoVec<&'a [u8]>]>, + I: AsRef<[IoSlice<'a>]>, C: AsRef<[ControlMessage<'a>]>, S: SockaddrLike + 'a { @@ -1751,7 +1749,7 @@ fn pack_mhdr_to_send<'a, I, C, S>( /// /// # References /// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) -pub fn recvmsg<'a, S>(fd: RawFd, iov: &[IoVec<&mut [u8]>], +pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>], mut cmsg_buffer: Option<&'a mut Vec>, flags: MsgFlags) -> Result> where S: SockaddrLike + 'a @@ -1759,7 +1757,7 @@ pub fn recvmsg<'a, S>(fd: RawFd, iov: &[IoVec<&mut [u8]>], let mut address = mem::MaybeUninit::uninit(); let (msg_controllen, mut mhdr) = unsafe { - pack_mhdr_to_receive(&iov, &mut cmsg_buffer, address.as_mut_ptr()) + pack_mhdr_to_receive::<_, S>(iov, &mut cmsg_buffer, address.as_mut_ptr()) }; let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 4229830050..ba6c64ef26 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -3,13 +3,21 @@ use crate::Result; use crate::errno::Errno; use libc::{self, c_int, c_void, size_t, off_t}; +use std::io::{IoSlice, IoSliceMut}; 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 { +pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result { + // SAFETY: to quote the documentation for `IoSlice`: + // + // [IoSlice] is semantically a wrapper around a &[u8], but is + // guaranteed to be ABI compatible with the iovec type on Unix + // platforms. + // + // Because it is ABI compatible, a pointer cast here is valid 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) @@ -18,7 +26,8 @@ pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result { /// 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 { +pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result { + // SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec let res = unsafe { libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; Errno::result(res).map(|r| r as usize) @@ -32,10 +41,13 @@ pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result { /// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], +pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result { + #[cfg(target_env = "uclibc")] let offset = offset as libc::off64_t; // uclibc doesn't use off_t + + // SAFETY: same as in writev() let res = unsafe { libc::pwritev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset) }; @@ -52,10 +64,12 @@ pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>], /// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>], +pub fn preadv(fd: RawFd, iov: &mut [IoSliceMut<'_>], offset: off_t) -> Result { #[cfg(target_env = "uclibc")] let offset = offset as libc::off64_t; // uclibc doesn't use off_t + + // SAFETY: same as in readv() let res = unsafe { libc::preadv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset) }; @@ -92,9 +106,9 @@ pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result{ /// A slice of memory in a remote process, starting at address `base` /// and consisting of `len` bytes. /// -/// This is the same underlying C structure as [`IoVec`](struct.IoVec.html), +/// This is the same underlying C structure as `IoSlice`, /// except that it refers to memory in some other process, and is -/// therefore not represented in Rust by an actual slice as `IoVec` is. It +/// therefore not represented in Rust by an actual slice as `IoSlice` is. It /// is used with [`process_vm_readv`](fn.process_vm_readv.html) /// and [`process_vm_writev`](fn.process_vm_writev.html). #[cfg(any(target_os = "linux", target_os = "android"))] @@ -108,13 +122,82 @@ pub struct RemoteIoVec { pub len: 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. +#[deprecated( + since = "0.24.0", + note = "`IoVec` is no longer used in the public interface, use `IoSlice` or `IoSliceMut` instead" +)] +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct IoVec(pub(crate) libc::iovec, PhantomData); + +#[allow(deprecated)] +impl IoVec { + /// View the `IoVec` as a Rust slice. + #[deprecated( + since = "0.24.0", + note = "Use the `Deref` impl of `IoSlice` or `IoSliceMut` instead" + )] + #[inline] + pub fn as_slice(&self) -> &[u8] { + use std::slice; + + unsafe { + slice::from_raw_parts( + self.0.iov_base as *const u8, + self.0.iov_len as usize) + } + } +} + +#[allow(deprecated)] +impl<'a> IoVec<&'a [u8]> { + /// Create an `IoVec` from a Rust slice. + #[deprecated( + since = "0.24.0", + note = "Use `IoSlice::new` instead" + )] + pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> { + IoVec(libc::iovec { + iov_base: buf.as_ptr() as *mut c_void, + iov_len: buf.len() as size_t, + }, PhantomData) + } +} + +#[allow(deprecated)] +impl<'a> IoVec<&'a mut [u8]> { + /// Create an `IoVec` from a mutable Rust slice. + #[deprecated( + since = "0.24.0", + note = "Use `IoSliceMut::new` instead" + )] + 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, + iov_len: buf.len() as size_t, + }, PhantomData) + } +} + +// The only reason IoVec isn't automatically Send+Sync is because libc::iovec +// contains raw pointers. +#[allow(deprecated)] +unsafe impl Send for IoVec where T: Send {} +#[allow(deprecated)] +unsafe impl Sync for IoVec where T: Sync {} + feature! { #![feature = "process"] /// Write data directly to another process's virtual memory /// (see [`process_vm_writev`(2)]). /// -/// `local_iov` is a list of [`IoVec`]s containing the data to be written, +/// `local_iov` is a list of [`IoSlice`]s containing the data to be written, /// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the /// data should be written in the target process. On success, returns the /// number of bytes written, which will always be a whole @@ -129,12 +212,12 @@ feature! { /// /// [`process_vm_writev`(2)]: https://man7.org/linux/man-pages/man2/process_vm_writev.2.html /// [ptrace]: ../ptrace/index.html -/// [`IoVec`]: struct.IoVec.html +/// [`IoSlice`]: https://doc.rust-lang.org/std/io/struct.IoSlice.html /// [`RemoteIoVec`]: struct.RemoteIoVec.html #[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] pub fn process_vm_writev( pid: crate::unistd::Pid, - local_iov: &[IoVec<&[u8]>], + local_iov: &[IoSlice<'_>], remote_iov: &[RemoteIoVec]) -> Result { let res = unsafe { @@ -149,7 +232,7 @@ pub fn process_vm_writev( /// Read data directly from another process's virtual memory /// (see [`process_vm_readv`(2)]). /// -/// `local_iov` is a list of [`IoVec`]s containing the buffer to copy +/// `local_iov` is a list of [`IoSliceMut`]s containing the buffer to copy /// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying /// where the source data is in the target process. On success, /// returns the number of bytes written, which will always be a whole @@ -164,12 +247,12 @@ pub fn process_vm_writev( /// /// [`process_vm_readv`(2)]: https://man7.org/linux/man-pages/man2/process_vm_readv.2.html /// [`ptrace`]: ../ptrace/index.html -/// [`IoVec`]: struct.IoVec.html +/// [`IoSliceMut`]: https://doc.rust-lang.org/std/io/struct.IoSliceMut.html /// [`RemoteIoVec`]: struct.RemoteIoVec.html #[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] pub fn process_vm_readv( pid: crate::unistd::Pid, - local_iov: &[IoVec<&mut [u8]>], + local_iov: &mut [IoSliceMut<'_>], remote_iov: &[RemoteIoVec]) -> Result { let res = unsafe { @@ -181,59 +264,3 @@ 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; - - unsafe { - slice::from_raw_parts( - self.0.iov_base as *const u8, - self.0.iov_len as usize) - } - } -} - -impl<'a> IoVec<&'a [u8]> { - #[cfg(all(feature = "mount", target_os = "freebsd"))] - pub(crate) fn from_raw_parts(base: *mut c_void, len: usize) -> Self { - IoVec(libc::iovec { - iov_base: base, - iov_len: len - }, 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, - iov_len: buf.len() as size_t, - }, PhantomData) - } -} - -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, - iov_len: buf.len() as size_t, - }, PhantomData) - } -} - -// The only reason IoVec isn't automatically Send+Sync is because libc::iovec -// contains raw pointers. -unsafe impl Send for IoVec where T: Send {} -unsafe impl Sync for IoVec where T: Sync {} diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index c18442fd04..2aac795851 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -72,7 +72,7 @@ pub fn test_timestamping() { recvmsg, sendmsg, setsockopt, socket, sockopt::Timestamping, ControlMessageOwned, MsgFlags, SockaddrIn, SockFlag, SockType, TimestampingFlag, }; - use nix::sys::uio::IoVec; + use std::io::{IoSlice, IoSliceMut}; let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); @@ -98,11 +98,12 @@ pub fn test_timestamping() { let sbuf = [0u8; 2048]; let mut rbuf = [0u8; 2048]; let flags = MsgFlags::empty(); - let iov1 = [IoVec::from_slice(&sbuf)]; - let iov2 = [IoVec::from_mut_slice(&mut rbuf)]; + let iov1 = [IoSlice::new(&sbuf)]; + let mut iov2 = [IoSliceMut::new(&mut rbuf)]; + let mut cmsg = cmsg_space!(nix::sys::socket::Timestamps); sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); - let recv = recvmsg::<()>(rsock, &iov2, Some(&mut cmsg), flags).unwrap(); + let recv = recvmsg::<()>(rsock, &mut iov2, Some(&mut cmsg), flags).unwrap(); let mut ts = None; for c in recv.cmsgs() { @@ -327,8 +328,8 @@ mod recvfrom { #[cfg(target_os = "linux")] mod udp_offload { use super::*; - use nix::sys::uio::IoVec; use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment}; + use std::io::IoSlice; #[test] // Disable the test under emulation because it fails in Cirrus-CI. Lack @@ -363,7 +364,7 @@ mod recvfrom { let mut num_packets_received: i32 = 0; sendrecv(rsock, ssock, move |s, m, flags| { - let iov = [IoVec::from_slice(m)]; + let iov = [IoSlice::new(m)]; let cmsg = ControlMessage::UdpGsoSegments(&segment_size); sendmsg(s, &iov, &[cmsg], flags, Some(&sock_addr)) }, { @@ -411,7 +412,7 @@ mod recvfrom { ))] #[test] pub fn udp_sendmmsg() { - use nix::sys::uio::IoVec; + use std::io::IoSlice; let std_sa = SocketAddrV4::from_str("127.0.0.1:6793").unwrap(); let std_sa2 = SocketAddrV4::from_str("127.0.0.1:6794").unwrap(); @@ -432,7 +433,7 @@ mod recvfrom { ).expect("send socket failed"); let from = sendrecv(rsock, ssock, move |s, m, flags| { - let iov = [IoVec::from_slice(m)]; + let iov = [IoSlice::new(m)]; let mut msgs = vec![ SendMmsgData { iov: &iov, @@ -475,7 +476,7 @@ mod recvfrom { ))] #[test] pub fn udp_recvmmsg() { - use nix::sys::uio::IoVec; + use std::io::IoSliceMut; use nix::sys::socket::{MsgFlags, recvmmsg}; const NUM_MESSAGES_SENT: usize = 2; @@ -508,7 +509,7 @@ mod recvfrom { // Buffers to receive exactly `NUM_MESSAGES_SENT` messages let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT]; let iovs: Vec<_> = receive_buffers.iter_mut().map(|buf| { - [IoVec::from_mut_slice(&mut buf[..])] + [IoSliceMut::new(&mut buf[..])] }).collect(); for iov in &iovs { @@ -541,8 +542,8 @@ mod recvfrom { ))] #[test] pub fn udp_recvmmsg_dontwait_short_read() { - use nix::sys::uio::IoVec; use nix::sys::socket::{MsgFlags, recvmmsg}; + use std::io::IoSliceMut; const NUM_MESSAGES_SENT: usize = 2; const DATA: [u8; 4] = [1,2,3,4]; @@ -579,7 +580,7 @@ mod recvfrom { // kernel buffers when using `MSG_DONTWAIT`. let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2]; let iovs: Vec<_> = receive_buffers.iter_mut().map(|buf| { - [IoVec::from_mut_slice(&mut buf[..])] + [IoSliceMut::new(&mut buf[..])] }).collect(); for iov in &iovs { @@ -608,12 +609,14 @@ mod recvfrom { pub fn test_recvmsg_ebadf() { use nix::errno::Errno; use nix::sys::socket::{MsgFlags, recvmsg}; - use nix::sys::uio::IoVec; + use std::io::IoSliceMut; let mut buf = [0u8; 5]; - let iov = [IoVec::from_mut_slice(&mut buf[..])]; + let mut iov = [IoSliceMut::new(&mut buf[..])]; + let fd = -1; // Bad file descriptor - let r = recvmsg::<()>(fd, &iov, None, MsgFlags::empty()); + let r = recvmsg::<()>(fd, &mut iov, None, MsgFlags::empty()); + assert_eq!(r.err().unwrap(), Errno::EBADF); } @@ -622,11 +625,11 @@ pub fn test_recvmsg_ebadf() { #[cfg_attr(qemu, ignore)] #[test] pub fn test_scm_rights() { - use nix::sys::uio::IoVec; use nix::unistd::{pipe, read, write, close}; use nix::sys::socket::{socketpair, sendmsg, recvmsg, AddressFamily, SockType, SockFlag, ControlMessage, ControlMessageOwned, MsgFlags}; + use std::io::{IoSlice, IoSliceMut}; let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) .unwrap(); @@ -634,7 +637,7 @@ pub fn test_scm_rights() { let mut received_r: Option = None; { - let iov = [IoVec::from_slice(b"hello")]; + let iov = [IoSlice::new(b"hello")]; let fds = [r]; let cmsg = ControlMessage::ScmRights(&fds); assert_eq!(sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); @@ -644,9 +647,10 @@ pub fn test_scm_rights() { { let mut buf = [0u8; 5]; - let iov = [IoVec::from_mut_slice(&mut buf[..])]; + + let mut iov = [IoSliceMut::new(&mut buf[..])]; let mut cmsgspace = cmsg_space!([RawFd; 1]); - let msg = recvmsg::<()>(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>(fd2, &mut iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); for cmsg in msg.cmsgs() { if let ControlMessageOwned::ScmRights(fd) = cmsg { @@ -677,12 +681,12 @@ pub fn test_scm_rights() { #[cfg_attr(qemu, ignore)] #[test] pub fn test_af_alg_cipher() { - use nix::sys::uio::IoVec; use nix::unistd::read; use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt, AddressFamily, SockType, SockFlag, AlgAddr, ControlMessage, MsgFlags}; use nix::sys::socket::sockopt::AlgSetKey; + use std::io::IoSlice; skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352"); // Travis's seccomp profile blocks AF_ALG @@ -713,7 +717,7 @@ pub fn test_af_alg_cipher() { let session_socket = accept(sock).expect("accept failed"); let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), ControlMessage::AlgSetIv(iv.as_slice())]; - let iov = IoVec::from_slice(&payload); + let iov = IoSlice::new(&payload); sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); // allocate buffer for encrypted data @@ -721,7 +725,7 @@ pub fn test_af_alg_cipher() { let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt"); assert_eq!(num_bytes, payload_len); - let iov = IoVec::from_slice(&encrypted); + let iov = IoSlice::new(&encrypted); let iv = vec![1u8; iv_len]; @@ -744,12 +748,12 @@ pub fn test_af_alg_cipher() { pub fn test_af_alg_aead() { use libc::{ALG_OP_DECRYPT, ALG_OP_ENCRYPT}; use nix::fcntl::{fcntl, FcntlArg, OFlag}; - use nix::sys::uio::IoVec; use nix::unistd::{read, close}; use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt, AddressFamily, SockType, SockFlag, AlgAddr, ControlMessage, MsgFlags}; use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize}; + use std::io::IoSlice; skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352"); // Travis's seccomp profile blocks AF_ALG @@ -794,7 +798,8 @@ pub fn test_af_alg_aead() { ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT), ControlMessage::AlgSetIv(iv.as_slice()), ControlMessage::AlgSetAeadAssoclen(&assoc_size)]; - let iov = IoVec::from_slice(&payload); + + let iov = IoSlice::new(&payload); sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); // allocate buffer for encrypted data @@ -807,7 +812,7 @@ pub fn test_af_alg_aead() { encrypted[i as usize] = 10; } - let iov = IoVec::from_slice(&encrypted); + let iov = IoSlice::new(&encrypted); let iv = vec![1u8; iv_len]; @@ -846,10 +851,10 @@ pub fn test_af_alg_aead() { #[test] pub fn test_sendmsg_ipv4packetinfo() { use cfg_if::cfg_if; - use nix::sys::uio::IoVec; use nix::sys::socket::{socket, sendmsg, bind, AddressFamily, SockType, SockFlag, SockaddrIn, ControlMessage, MsgFlags}; + use std::io::IoSlice; let sock = socket(AddressFamily::Inet, SockType::Datagram, @@ -862,7 +867,7 @@ pub fn test_sendmsg_ipv4packetinfo() { bind(sock, &sock_addr).expect("bind failed"); let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoVec::from_slice(&slice)]; + let iov = [IoSlice::new(&slice)]; cfg_if! { if #[cfg(target_os = "netbsd")] { @@ -900,10 +905,10 @@ pub fn test_sendmsg_ipv4packetinfo() { #[test] pub fn test_sendmsg_ipv6packetinfo() { use nix::errno::Errno; - use nix::sys::uio::IoVec; use nix::sys::socket::{socket, sendmsg, bind, AddressFamily, SockType, SockFlag, SockaddrIn6, ControlMessage, MsgFlags}; + use std::io::IoSlice; let sock = socket(AddressFamily::Inet6, SockType::Datagram, @@ -920,7 +925,7 @@ pub fn test_sendmsg_ipv6packetinfo() { } let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoVec::from_slice(&slice)]; + let iov = [IoSlice::new(&slice)]; let pi = libc::in6_pktinfo { ipi6_ifindex: 0, /* Unspecified interface */ @@ -944,16 +949,17 @@ fn test_scm_rights_single_cmsg_multiple_fds() { use std::thread; use nix::sys::socket::{ControlMessage, ControlMessageOwned, MsgFlags, sendmsg, recvmsg}; - use nix::sys::uio::IoVec; + use std::io::{IoSlice, IoSliceMut}; let (send, receive) = UnixDatagram::pair().unwrap(); let thread = thread::spawn(move || { let mut buf = [0u8; 8]; - let iovec = [IoVec::from_mut_slice(&mut buf)]; + let mut iovec = [IoSliceMut::new(&mut buf)]; + let mut space = cmsg_space!([RawFd; 2]); let msg = recvmsg::<()>( receive.as_raw_fd(), - &iovec, + &mut iovec, Some(&mut space), MsgFlags::empty() ).unwrap(); @@ -971,11 +977,11 @@ fn test_scm_rights_single_cmsg_multiple_fds() { assert!(cmsgs.next().is_none(), "unexpected control msg"); assert_eq!(msg.bytes, 8); - assert_eq!(iovec[0].as_slice(), [1u8, 2, 3, 4, 5, 6, 7, 8]); + assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); }); let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoVec::from_slice(&slice)]; + let iov = [IoSlice::new(&slice)]; let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout let cmsg = [ControlMessage::ScmRights(&fds)]; sendmsg::<()>(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None).unwrap(); @@ -988,25 +994,26 @@ fn test_scm_rights_single_cmsg_multiple_fds() { // raw `sendmsg`. #[test] pub fn test_sendmsg_empty_cmsgs() { - use nix::sys::uio::IoVec; use nix::unistd::close; use nix::sys::socket::{socketpair, sendmsg, recvmsg, AddressFamily, SockType, SockFlag, MsgFlags}; + use std::io::{IoSlice, IoSliceMut}; let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) .unwrap(); { - let iov = [IoVec::from_slice(b"hello")]; + let iov = [IoSlice::new(b"hello")]; assert_eq!(sendmsg::<()>(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5); close(fd1).unwrap(); } { let mut buf = [0u8; 5]; - let iov = [IoVec::from_mut_slice(&mut buf[..])]; + let mut iov = [IoSliceMut::new(&mut buf[..])]; + let mut cmsgspace = cmsg_space!([RawFd; 1]); - let msg = recvmsg::<()>(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>(fd2, &mut iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); for _ in msg.cmsgs() { panic!("unexpected cmsg"); @@ -1025,7 +1032,6 @@ pub fn test_sendmsg_empty_cmsgs() { ))] #[test] fn test_scm_credentials() { - use nix::sys::uio::IoVec; use nix::unistd::{close, getpid, getuid, getgid}; use nix::sys::socket::{socketpair, sendmsg, recvmsg, AddressFamily, SockType, SockFlag, @@ -1033,6 +1039,7 @@ fn test_scm_credentials() { UnixCredentials}; #[cfg(any(target_os = "android", target_os = "linux"))] use nix::sys::socket::{setsockopt, sockopt::PassCred}; + use std::io::{IoSlice, IoSliceMut}; let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) .unwrap(); @@ -1040,7 +1047,7 @@ fn test_scm_credentials() { setsockopt(recv, PassCred, &true).unwrap(); { - let iov = [IoVec::from_slice(b"hello")]; + let iov = [IoSlice::new(b"hello")]; #[cfg(any(target_os = "android", target_os = "linux"))] let cred = UnixCredentials::new(); #[cfg(any(target_os = "android", target_os = "linux"))] @@ -1053,9 +1060,10 @@ fn test_scm_credentials() { { let mut buf = [0u8; 5]; - let iov = [IoVec::from_mut_slice(&mut buf[..])]; + let mut iov = [IoSliceMut::new(&mut buf[..])]; + let mut cmsgspace = cmsg_space!(UnixCredentials); - let msg = recvmsg::<()>(recv, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>(recv, &mut iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); let mut received_cred = None; for cmsg in msg.cmsgs() { @@ -1106,12 +1114,12 @@ fn test_too_large_cmsgspace() { #[cfg(any(target_os = "android", target_os = "linux"))] fn test_impl_scm_credentials_and_rights(mut space: Vec) { use libc::ucred; - use nix::sys::uio::IoVec; use nix::unistd::{pipe, write, close, getpid, getuid, getgid}; use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt, SockType, SockFlag, ControlMessage, ControlMessageOwned, MsgFlags}; use nix::sys::socket::sockopt::PassCred; + use std::io::{IoSlice, IoSliceMut}; let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) .unwrap(); @@ -1121,7 +1129,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { let mut received_r: Option = None; { - let iov = [IoVec::from_slice(b"hello")]; + let iov = [IoSlice::new(b"hello")]; let cred = ucred { pid: getpid().as_raw(), uid: getuid().as_raw(), @@ -1139,8 +1147,8 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { { let mut buf = [0u8; 5]; - let iov = [IoVec::from_mut_slice(&mut buf[..])]; - let msg = recvmsg::<()>(recv, &iov, Some(&mut space), MsgFlags::empty()).unwrap(); + let mut iov = [IoSliceMut::new(&mut buf[..])]; + let msg = recvmsg::<()>(recv, &mut iov, Some(&mut space), MsgFlags::empty()).unwrap(); let mut received_cred = None; assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs"); @@ -1289,8 +1297,8 @@ pub fn test_recv_ipv4pktinfo() { use nix::sys::socket::{bind, SockaddrIn, SockFlag, SockType}; use nix::sys::socket::{getsockname, setsockopt, socket}; use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; - use nix::sys::uio::IoVec; use nix::net::if_::*; + use std::io::{IoSlice, IoSliceMut}; let lo_ifaddr = loopback_address(AddressFamily::Inet); let (lo_name, lo) = match lo_ifaddr { @@ -1310,7 +1318,7 @@ pub fn test_recv_ipv4pktinfo() { { let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoVec::from_slice(&slice)]; + let iov = [IoSlice::new(&slice)]; let send = socket( AddressFamily::Inet, @@ -1323,11 +1331,12 @@ pub fn test_recv_ipv4pktinfo() { { let mut buf = [0u8; 8]; - let iovec = [IoVec::from_mut_slice(&mut buf)]; + let mut iovec = [IoSliceMut::new(&mut buf)]; + let mut space = cmsg_space!(libc::in_pktinfo); let msg = recvmsg::<()>( receive, - &iovec, + &mut iovec, Some(&mut space), MsgFlags::empty(), ).expect("recvmsg failed"); @@ -1350,7 +1359,7 @@ pub fn test_recv_ipv4pktinfo() { assert!(cmsgs.next().is_none(), "unexpected additional control msg"); assert_eq!(msg.bytes, 8); assert_eq!( - iovec[0].as_slice(), + *iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8] ); } @@ -1379,7 +1388,7 @@ pub fn test_recvif() { use nix::sys::socket::{bind, SockaddrIn, SockFlag, SockType}; use nix::sys::socket::{getsockname, setsockopt, socket}; use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; - use nix::sys::uio::IoVec; + use std::io::{IoSlice, IoSliceMut}; let lo_ifaddr = loopback_address(AddressFamily::Inet); let (lo_name, lo) = match lo_ifaddr { @@ -1400,7 +1409,7 @@ pub fn test_recvif() { { let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoVec::from_slice(&slice)]; + let iov = [IoSlice::new(&slice)]; let send = socket( AddressFamily::Inet, @@ -1413,11 +1422,11 @@ pub fn test_recvif() { { let mut buf = [0u8; 8]; - let iovec = [IoVec::from_mut_slice(&mut buf)]; + let mut iovec = [IoSliceMut::new(&mut buf)]; let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr); let msg = recvmsg::<()>( receive, - &iovec, + &mut iovec, Some(&mut space), MsgFlags::empty(), ).expect("recvmsg failed"); @@ -1461,7 +1470,7 @@ pub fn test_recvif() { assert!(rx_recvdstaddr); assert_eq!(msg.bytes, 8); assert_eq!( - iovec[0].as_slice(), + *iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8] ); } @@ -1492,7 +1501,7 @@ pub fn test_recv_ipv6pktinfo() { use nix::sys::socket::{bind, SockaddrIn6, SockFlag, SockType}; use nix::sys::socket::{getsockname, setsockopt, socket}; use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; - use nix::sys::uio::IoVec; + use std::io::{IoSlice, IoSliceMut}; let lo_ifaddr = loopback_address(AddressFamily::Inet6); let (lo_name, lo) = match lo_ifaddr { @@ -1512,7 +1521,7 @@ pub fn test_recv_ipv6pktinfo() { { let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let iov = [IoVec::from_slice(&slice)]; + let iov = [IoSlice::new(&slice)]; let send = socket( AddressFamily::Inet6, @@ -1525,11 +1534,12 @@ pub fn test_recv_ipv6pktinfo() { { let mut buf = [0u8; 8]; - let iovec = [IoVec::from_mut_slice(&mut buf)]; + let mut iovec = [IoSliceMut::new(&mut buf)]; + let mut space = cmsg_space!(libc::in6_pktinfo); let msg = recvmsg::<()>( receive, - &iovec, + &mut iovec, Some(&mut space), MsgFlags::empty(), ).expect("recvmsg failed"); @@ -1553,7 +1563,7 @@ pub fn test_recv_ipv6pktinfo() { assert!(cmsgs.next().is_none(), "unexpected additional control msg"); assert_eq!(msg.bytes, 8); assert_eq!( - iovec[0].as_slice(), + *iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8] ); } @@ -1611,7 +1621,7 @@ pub fn test_vsock() { #[test] fn test_recvmsg_timestampns() { use nix::sys::socket::*; - use nix::sys::uio::IoVec; + use std::io::{IoSlice, IoSliceMut}; use nix::sys::time::*; use std::time::*; @@ -1629,15 +1639,16 @@ fn test_recvmsg_timestampns() { // Get initial time let time0 = SystemTime::now(); // Send the message - let iov = [IoVec::from_slice(message)]; + let iov = [IoSlice::new(message)]; let flags = MsgFlags::empty(); let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); assert_eq!(message.len(), l); // Receive the message let mut buffer = vec![0u8; message.len()]; let mut cmsgspace = nix::cmsg_space!(TimeSpec); - let iov = [IoVec::from_mut_slice(&mut buffer)]; - let r = recvmsg::<()>(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap(); + + let mut iov = [IoSliceMut::new(&mut buffer)]; + let r = recvmsg::<()>(in_socket, &mut iov, Some(&mut cmsgspace), flags).unwrap(); let rtime = match r.cmsgs().next() { Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, Some(_) => panic!("Unexpected control message"), @@ -1662,7 +1673,7 @@ fn test_recvmsg_timestampns() { #[test] fn test_recvmmsg_timestampns() { use nix::sys::socket::*; - use nix::sys::uio::IoVec; + use std::io::{IoSlice, IoSliceMut}; use nix::sys::time::*; use std::time::*; @@ -1680,14 +1691,14 @@ fn test_recvmmsg_timestampns() { // Get initial time let time0 = SystemTime::now(); // Send the message - let iov = [IoVec::from_slice(message)]; + let iov = [IoSlice::new(message)]; let flags = MsgFlags::empty(); let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); assert_eq!(message.len(), l); // Receive the message let mut buffer = vec![0u8; message.len()]; let mut cmsgspace = nix::cmsg_space!(TimeSpec); - let iov = [IoVec::from_mut_slice(&mut buffer)]; + let iov = [IoSliceMut::new(&mut buffer)]; let mut data = vec![ RecvMmsgData { iov, @@ -1720,7 +1731,7 @@ fn test_recvmmsg_timestampns() { fn test_recvmsg_rxq_ovfl() { use nix::Error; use nix::sys::socket::*; - use nix::sys::uio::IoVec; + use std::io::{IoSlice, IoSliceMut}; use nix::sys::socket::sockopt::{RxqOvfl, RcvBuf}; let message = [0u8; 2048]; @@ -1752,7 +1763,7 @@ fn test_recvmsg_rxq_ovfl() { let mut drop_counter = 0; for _ in 0..2 { - let iov = [IoVec::from_slice(&message)]; + let iov = [IoSlice::new(&message)]; let flags = MsgFlags::empty(); // Send the 3 messages (the receiver buffer can only hold 2 messages) @@ -1767,11 +1778,11 @@ fn test_recvmsg_rxq_ovfl() { let mut buffer = vec![0u8; message.len()]; let mut cmsgspace = nix::cmsg_space!(u32); - let iov = [IoVec::from_mut_slice(&mut buffer)]; + let mut iov = [IoSliceMut::new(&mut buffer)]; match recvmsg::<()>( in_socket, - &iov, + &mut iov, Some(&mut cmsgspace), MsgFlags::MSG_DONTWAIT) { Ok(r) => { @@ -1904,7 +1915,7 @@ mod linux_errqueue { TESTF: FnOnce(&ControlMessageOwned) -> libc::sock_extended_err, { use nix::errno::Errno; - use nix::sys::uio::IoVec; + use std::io::IoSliceMut; const MESSAGE_CONTENTS: &str = "ABCDEF"; let std_sa = std::net::SocketAddr::from_str(sa).unwrap(); @@ -1918,13 +1929,12 @@ mod linux_errqueue { } let mut buf = [0u8; 8]; - let iovec = [IoVec::from_mut_slice(&mut buf)]; + let mut iovec = [IoSliceMut::new(&mut buf)]; let mut cspace = cmsg_space!(libc::sock_extended_err, SA); - let msg = recvmsg(sock, &iovec, Some(&mut cspace), MsgFlags::MSG_ERRQUEUE).unwrap(); + let msg = recvmsg(sock, &mut iovec, Some(&mut cspace), MsgFlags::MSG_ERRQUEUE).unwrap(); // The sent message / destination associated with the error is returned: assert_eq!(msg.bytes, MESSAGE_CONTENTS.as_bytes().len()); - assert_eq!(&buf[..msg.bytes], MESSAGE_CONTENTS.as_bytes()); // recvmsg(2): "The original destination address of the datagram that caused the error is // supplied via msg_name;" however, this is not literally true. E.g., an earlier version // of this test used 0.0.0.0 (::0) as the destination address, which was mutated into @@ -1945,6 +1955,9 @@ mod linux_errqueue { assert_eq!(ext_err.ee_code, ee_code); // ip(7): ee_info contains the discovered MTU for EMSGSIZE errors. assert_eq!(ext_err.ee_info, 0); + + let bytes = msg.bytes; + assert_eq!(&buf[..bytes], MESSAGE_CONTENTS.as_bytes()); } } @@ -1989,7 +2002,7 @@ pub fn test_txtime() { bind(rsock, &sock_addr).unwrap(); let sbuf = [0u8; 2048]; - let iov1 = [nix::sys::uio::IoVec::from_slice(&sbuf)]; + let iov1 = [std::io::IoSlice::new(&sbuf)]; let now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap(); let delay = std::time::Duration::from_secs(1).into(); @@ -1999,6 +2012,6 @@ pub fn test_txtime() { sendmsg(ssock, &iov1, &[cmsg], MsgFlags::empty(), Some(&sock_addr)).unwrap(); let mut rbuf = [0u8; 2048]; - let iov2 = [nix::sys::uio::IoVec::from_mut_slice(&mut rbuf)]; - recvmsg::<()>(rsock, &iov2, None, MsgFlags::empty()).unwrap(); + let mut iov2 = [std::io::IoSliceMut::new(&mut rbuf)]; + recvmsg::<()>(rsock, &mut iov2, None, MsgFlags::empty()).unwrap(); } diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index 5353c516e4..7dd12a21b0 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -4,8 +4,12 @@ use rand::{thread_rng, Rng}; use rand::distributions::Alphanumeric; use std::{cmp, iter}; use std::fs::{OpenOptions}; +use std::io::IoSlice; use std::os::unix::io::AsRawFd; +#[cfg(not(target_os = "redox"))] +use std::io::IoSliceMut; + #[cfg(not(target_os = "redox"))] use tempfile::tempfile; use tempfile::tempdir; @@ -29,7 +33,7 @@ fn test_writev() { let left = to_write.len() - consumed; let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64..cmp::min(256, left)) }; let b = &to_write[consumed..consumed+slice_len]; - iovecs.push(IoVec::from_slice(b)); + iovecs.push(IoSlice::new(b)); consumed += slice_len; } let pipe_res = pipe(); @@ -78,7 +82,7 @@ fn test_readv() { } let mut iovecs = Vec::with_capacity(storage.len()); for v in &mut storage { - iovecs.push(IoVec::from_mut_slice(&mut v[..])); + iovecs.push(IoSliceMut::new(&mut v[..])); } let pipe_res = pipe(); assert!(pipe_res.is_ok()); @@ -95,7 +99,7 @@ fn test_readv() { // Cccumulate data from iovecs let mut read_buf = Vec::with_capacity(to_write.len()); for iovec in &iovecs { - read_buf.extend(iovec.as_slice().iter().cloned()); + read_buf.extend(iovec.iter().cloned()); } // Check whether iovecs contain all written data assert_eq!(read_buf.len(), to_write.len()); @@ -149,9 +153,9 @@ fn test_pwritev() { let expected: Vec = [vec![0;100], to_write.clone()].concat(); let iovecs = [ - IoVec::from_slice(&to_write[0..17]), - IoVec::from_slice(&to_write[17..64]), - IoVec::from_slice(&to_write[64..128]), + IoSlice::new(&to_write[0..17]), + IoSlice::new(&to_write[17..64]), + IoSlice::new(&to_write[64..128]), ]; let tempdir = tempdir().unwrap(); @@ -194,9 +198,9 @@ fn test_preadv() { { // Borrow the buffers into IoVecs and preadv into them - let iovecs: Vec<_> = buffers.iter_mut().map( - |buf| IoVec::from_mut_slice(&mut buf[..])).collect(); - assert_eq!(Ok(100), preadv(file.as_raw_fd(), &iovecs, 100)); + let mut iovecs: Vec<_> = buffers.iter_mut().map( + |buf| IoSliceMut::new(&mut buf[..])).collect(); + assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100)); } let all = buffers.concat(); @@ -233,7 +237,7 @@ fn test_process_vm_readv() { let mut buf = vec![0u8; 5]; let ret = process_vm_readv(child, - &[IoVec::from_mut_slice(&mut buf)], + &mut [IoSliceMut::new(&mut buf)], &[remote_iov]); kill(child, SIGTERM).unwrap(); diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 95e224e2d4..ebfc43e25f 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -218,12 +218,11 @@ fn test_readlink() { #[cfg(any(target_os = "linux", target_os = "android"))] mod linux_android { use std::io::prelude::*; - use std::io::SeekFrom; + use std::io::{IoSlice, SeekFrom}; use std::os::unix::prelude::*; use libc::loff_t; use nix::fcntl::*; - use nix::sys::uio::IoVec; use nix::unistd::{close, pipe, read, write}; use tempfile::tempfile; @@ -323,8 +322,8 @@ mod linux_android { let buf1 = b"abcdef"; let buf2 = b"defghi"; let iovecs = vec![ - IoVec::from_slice(&buf1[0..3]), - IoVec::from_slice(&buf2[0..3]) + IoSlice::new(&buf1[0..3]), + IoSlice::new(&buf2[0..3]) ]; let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap(); From 145c240cfac980db0cce774b9a5f438afc94342a Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 9 Apr 2022 16:32:39 -0600 Subject: [PATCH 083/358] Use singular number for all feature names features => feature users => user Neither of these features have yet been included in a release, so it's ok to rename them. --- Cargo.toml | 8 ++++---- src/lib.rs | 6 +++--- src/sys/mod.rs | 2 +- src/unistd.rs | 24 ++++++++++++------------ 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1e2aad22cd..8842fc90e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,11 +36,11 @@ memoffset = { version = "0.6.3", optional = true } [features] default = [ - "acct", "aio", "dir", "env", "event", "features", "fs", + "acct", "aio", "dir", "env", "event", "feature", "fs", "hostname", "inotify", "ioctl", "kmod", "mman", "mount", "mqueue", "net", "personality", "poll", "process", "pthread", "ptrace", "quota", "reboot", "resource", "sched", "signal", "socket", "term", "time", - "ucontext", "uio", "users", "zerocopy", + "ucontext", "uio", "user", "zerocopy", ] acct = [] @@ -48,7 +48,7 @@ aio = [] dir = ["fs"] env = [] event = [] -features = [] +feature = [] fs = [] hostname = [] inotify = [] @@ -73,7 +73,7 @@ term = [] time = [] ucontext = ["signal"] uio = [] -users = ["features"] +user = ["feature"] zerocopy = ["fs", "uio"] [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index 172ca3a1d5..d4dcbc4ceb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ //! * `dir` - Stuff relating to directory iteration //! * `env` - Manipulate environment variables //! * `event` - Event-driven APIs, like `kqueue` and `epoll` -//! * `features` - Query characteristics of the OS at runtime +//! * `feature` - Query characteristics of the OS at runtime //! * `fs` - File system functionality //! * `hostname` - Get and set the system's hostname //! * `inotify` - Linux's `inotify` file system notification API @@ -37,7 +37,7 @@ //! * `time` - Query the operating system's clocks //! * `ucontext` - User thread context //! * `uio` - Vectored I/O -//! * `users` - Stuff relating to users and groups +//! * `user` - Stuff relating to users and groups //! * `zerocopy` - APIs like `sendfile` and `copy_file_range` #![crate_name = "nix"] #![cfg(unix)] @@ -75,7 +75,7 @@ feature! { #[allow(missing_docs)] pub mod errno; feature! { - #![feature = "features"] + #![feature = "feature"] #[deny(missing_docs)] pub mod features; diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 151d9e9d08..e5639f20ab 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -177,7 +177,7 @@ feature! { } feature! { - #![feature = "features"] + #![feature = "feature"] pub mod utsname; } diff --git a/src/unistd.rs b/src/unistd.rs index 272fb0cd9d..764b3dee43 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -45,7 +45,7 @@ pub use self::setres::*; pub use self::getres::*; feature! { -#![feature = "users"] +#![feature = "user"] /// User identifier /// @@ -591,7 +591,7 @@ pub fn symlinkat( // Double the buffer capacity up to limit. In case it already has // reached the limit, return Errno::ERANGE. -#[cfg(any(feature = "fs", feature = "users"))] +#[cfg(any(feature = "fs", feature = "user"))] fn reserve_double_buffer_size(buf: &mut Vec, limit: usize) -> Result<()> { use std::cmp::min; @@ -654,7 +654,7 @@ pub fn getcwd() -> Result { } feature! { -#![all(feature = "users", feature = "fs")] +#![all(feature = "user", feature = "fs")] /// Computes the raw UID and GID values to pass to a `*chown` call. // The cast is not unnecessary on all platforms. @@ -1348,7 +1348,7 @@ pub fn fdatasync(fd: RawFd) -> Result<()> { } feature! { -#![feature = "users"] +#![feature = "user"] /// Get a real user ID /// @@ -1432,7 +1432,7 @@ pub fn setgid(gid: Gid) -> Result<()> { } feature! { -#![all(feature = "fs", feature = "users")] +#![all(feature = "fs", feature = "user")] /// Set the user identity used for filesystem checks per-thread. /// On both success and failure, this call returns the previous filesystem user /// ID of the caller. @@ -1457,7 +1457,7 @@ pub fn setfsgid(gid: Gid) -> Gid { } feature! { -#![feature = "users"] +#![feature = "user"] /// Get the list of supplementary group IDs of the calling process. /// @@ -1868,7 +1868,7 @@ pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { } feature! { -#![all(feature = "fs", feature = "features")] +#![all(feature = "fs", feature = "feature")] /// Variable names for `pathconf` /// @@ -2064,7 +2064,7 @@ pub fn pathconf(path: &P, var: PathconfVar) -> Result(path: &P, amode: AccessFlags) -> Result<()> { } feature! { -#![feature = "users"] +#![feature = "user"] /// Representation of a User, based on `libc::passwd` /// @@ -3212,7 +3212,7 @@ pub fn ttyname(fd: RawFd) -> Result { } feature! { -#![all(feature = "socket", feature = "users")] +#![all(feature = "socket", feature = "user")] /// Get the effective user ID and group ID associated with a Unix domain socket. /// From 23f18dfc18929965c95e0bcbdb8731645f07e401 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 9 Apr 2022 17:03:57 -0600 Subject: [PATCH 084/358] Pin nightly compiler used in CI for uclibc Workaround for https://github.com/rust-lang/rust/issues/95866 --- .cirrus.yml | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index cc5f216da5..fdb65658f9 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -286,14 +286,29 @@ task: - name: OpenBSD x86_64 env: TARGET: x86_64-unknown-openbsd - - name: Linux armv7 uclibceabihf - env: - TARGET: armv7-unknown-linux-uclibceabihf setup_script: - rustup component add rust-src << : *BUILD before_cache_script: rm -rf $CARGO_HOME/registry/index +# uclibc needs its own task for now, due to Rust bug 95866 +# https://github.com/rust-lang/rust/issues/95866 +task: + name: Linux armv7 uclibceabihf + container: + image: rustlang/rust:nightly + env: + BUILD: check + ZFLAGS: -Zbuild-std + TARGET: armv7-unknown-linux-uclibceabihf + TOOLCHAIN: nightly-2022-04-01 + setup_script: + - rustup toolchain install $TOOLCHAIN --profile minimal + - rustup component add --toolchain $TOOLCHAIN rust-src + - rustup component add --toolchain $TOOLCHAIN clippy + << : *BUILD + before_cache_script: rm -rf $CARGO_HOME/registry/index + # Test that we can build with the lowest version of all dependencies. # "cargo test" doesn't work because some of our dev-dependencies, like # rand, can't build with their own minimal dependencies. From 7497b8a9e5ae410a93c4c26f70951291ef7bc071 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 14 Apr 2022 09:31:19 -0600 Subject: [PATCH 085/358] Update FreeBSD CI image to 12.3. 12.2 is EoL. --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index cc5f216da5..3f21c97d52 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -38,7 +38,7 @@ task: env: TARGET: x86_64-unknown-freebsd freebsd_instance: - image: freebsd-12-2-release-amd64 + image: freebsd-12-3-release-amd64 setup_script: - kldload mqueuefs - fetch https://sh.rustup.rs -o rustup.sh From c5927f3dab484eeadc1f5892e3bfd49159d9d329 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 18 Apr 2022 20:22:14 -0600 Subject: [PATCH 086/358] Revert "Pin nightly compiler used in CI for uclibc" This reverts commit 23f18dfc18929965c95e0bcbdb8731645f07e401. libc v0.2.124 fixes the problem. --- .cirrus.yml | 21 +++------------------ Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 358f66c6be..3f21c97d52 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -286,29 +286,14 @@ task: - name: OpenBSD x86_64 env: TARGET: x86_64-unknown-openbsd + - name: Linux armv7 uclibceabihf + env: + TARGET: armv7-unknown-linux-uclibceabihf setup_script: - rustup component add rust-src << : *BUILD before_cache_script: rm -rf $CARGO_HOME/registry/index -# uclibc needs its own task for now, due to Rust bug 95866 -# https://github.com/rust-lang/rust/issues/95866 -task: - name: Linux armv7 uclibceabihf - container: - image: rustlang/rust:nightly - env: - BUILD: check - ZFLAGS: -Zbuild-std - TARGET: armv7-unknown-linux-uclibceabihf - TOOLCHAIN: nightly-2022-04-01 - setup_script: - - rustup toolchain install $TOOLCHAIN --profile minimal - - rustup component add --toolchain $TOOLCHAIN rust-src - - rustup component add --toolchain $TOOLCHAIN clippy - << : *BUILD - before_cache_script: rm -rf $CARGO_HOME/registry/index - # Test that we can build with the lowest version of all dependencies. # "cargo test" doesn't work because some of our dev-dependencies, like # rand, can't build with their own minimal dependencies. diff --git a/Cargo.toml b/Cargo.toml index 8842fc90e7..305cc2110e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.121", features = [ "extra_traits" ] } +libc = { version = "0.2.124", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" From 7f5907c78d58b75a4a0771217bdb488b8f42ac95 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Wed, 20 Apr 2022 21:47:48 -0500 Subject: [PATCH 087/358] (cargo-release) version 0.24.0 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c4847c7da..c5a2678a15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). -## [Unreleased] - ReleaseDate +## [0.24.0] - 2022-04-21 ### Added - Added fine-grained features flags. Most Nix functionality can now be diff --git a/Cargo.toml b/Cargo.toml index 8842fc90e7..1d1d7f9cac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2018" -version = "0.23.1" +version = "0.24.0" rust-version = "1.46" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" From a06114a99d13f28182cef1877d1f24c0c26b0a1f Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Thu, 21 Apr 2022 16:05:06 -0500 Subject: [PATCH 088/358] Document pushing the release tag to GitHub --- RELEASE_PROCEDURE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_PROCEDURE.md b/RELEASE_PROCEDURE.md index fab41dd339..9c68f78b18 100644 --- a/RELEASE_PROCEDURE.md +++ b/RELEASE_PROCEDURE.md @@ -16,3 +16,4 @@ The release is prepared as follows: - Confirm that everything's ready for a release by running `cargo release ` - Create the release with `cargo release -x ` +- Push the created tag to GitHub. From db969c59e9a96ee27f9116c3e6dfa455545be764 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 22 Apr 2022 11:49:34 -0600 Subject: [PATCH 089/358] Fix UnixAddr::size on Linux and Android SockaddrLike::size() is meant to return the amount of space that can be used to store the sockaddr. But on Linux-based OSes, UnixAddr contains an extra field to store the address's length. This field is not part of the address, and should not contribute to the value of size(). This bug can't cause an out-of-bounds write, and every OS that we test on can tolerate the greater-than-expected length, but it might confuse applications that implement functions similar to getsockname in userland. --- CHANGELOG.md | 10 ++++++++++ src/sys/socket/addr.rs | 43 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5a2678a15..88f8df2a58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +## [Unreleased] - ReleaseDate +### Added +### Changed +### Fixed + +- Fixed `UnixAddr::size` on Linux-based OSes. + (#[1702](https://github.com/nix-rust/nix/pull/1702)) + +### Removed + ## [0.24.0] - 2022-04-21 ### Added diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index e2321cb7e8..52d60ac9ab 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -953,6 +953,10 @@ impl SockaddrLike for UnixAddr { ptr::copy(addr as *const u8, sup, su_len as usize); Some(Self::from_raw_parts(su, su_len as u8)) } + + fn size() -> libc::socklen_t where Self: Sized { + mem::size_of::() as libc::socklen_t + } } impl AsRef for UnixAddr { @@ -2615,11 +2619,12 @@ mod tests { } mod link { + use super::*; #[cfg(any(target_os = "ios", target_os = "macos", target_os = "illumos" ))] - use super::{*, super::super::socklen_t}; + use super::super::super::socklen_t; /// Don't panic when trying to display an empty datalink address #[cfg(any(target_os = "dragonfly", @@ -2701,6 +2706,24 @@ mod tests { assert_eq!(sock_addr.as_link_addr().unwrap().addr(), Some([24u8, 101, 144, 221, 76, 176])); } + + #[test] + fn size() { + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd"))] + let l = mem::size_of::(); + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux"))] + let l = mem::size_of::(); + assert_eq!( LinkAddr::size() as usize, l); + } } mod sockaddr_in { @@ -2713,6 +2736,12 @@ mod tests { let addr = SockaddrIn::from_str(s).unwrap(); assert_eq!(s, format!("{}", addr)); } + + #[test] + fn size() { + assert_eq!(mem::size_of::(), + SockaddrIn::size() as usize); + } } mod sockaddr_in6 { @@ -2725,10 +2754,15 @@ mod tests { let addr = SockaddrIn6::from_str(s).unwrap(); assert_eq!(s, format!("{}", addr)); } + + #[test] + fn size() { + assert_eq!(mem::size_of::(), + SockaddrIn6::size() as usize); + } } mod unixaddr { - #[cfg(any(target_os = "android", target_os = "linux"))] use super::*; #[cfg(any(target_os = "android", target_os = "linux"))] @@ -2742,5 +2776,10 @@ mod tests { assert_eq!(sun_path1, sun_path2); } + #[test] + fn size() { + assert_eq!(mem::size_of::(), + UnixAddr::size() as usize); + } } } From f1a1e2d7c5be99bb11b4d390cd0b6802a839f419 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Fri, 22 Apr 2022 18:46:23 -0500 Subject: [PATCH 090/358] (cargo-release) version 0.24.1 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88f8df2a58..b6639a1a7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). -## [Unreleased] - ReleaseDate +## [0.24.1] - 2022-04-22 ### Added ### Changed ### Fixed diff --git a/Cargo.toml b/Cargo.toml index 1d1d7f9cac..203a7b9799 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2018" -version = "0.24.0" +version = "0.24.1" rust-version = "1.46" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" From e543733a4cce1dab91155e7bea9510ca9895ecfd Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 24 Apr 2022 19:04:23 -0500 Subject: [PATCH 091/358] Upgrade sysctl to 0.4 Upgrade sysctl dev-dependency to 0.4 and handle its breaking API changes. --- Cargo.toml | 2 +- src/mount/bsd.rs | 5 +++-- test/common/mod.rs | 11 ++++++----- test/sys/test_lio_listio_resubmit.rs | 6 +++--- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 203a7b9799..a87bae5ce4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,7 +88,7 @@ semver = "1.0.0" caps = "0.5.1" [target.'cfg(target_os = "freebsd")'.dev-dependencies] -sysctl = "0.1" +sysctl = "0.4" [[test]] name = "test" diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs index b4d611ee39..109522f9fb 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd.rs @@ -168,8 +168,9 @@ pub type NmountResult = std::result::Result<(), NmountError>; /// To mount `target` onto `mountpoint` with `nullfs`: /// ``` /// # use nix::unistd::Uid; -/// # use ::sysctl::CtlValue; -/// # if !Uid::current().is_root() && CtlValue::Int(0) == ::sysctl::value("vfs.usermount").unwrap() { +/// # use ::sysctl::{CtlValue, Sysctl}; +/// # let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap(); +/// # if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap() { /// # return; /// # }; /// use nix::mount::{MntFlags, Nmount, unmount}; diff --git a/test/common/mod.rs b/test/common/mod.rs index 544a1ae3f0..caa39ab4d4 100644 --- a/test/common/mod.rs +++ b/test/common/mod.rs @@ -35,10 +35,11 @@ cfg_if! { #[cfg(target_os = "freebsd")] #[macro_export] macro_rules! require_mount { ($name:expr) => { - use ::sysctl::CtlValue; + use ::sysctl::{CtlValue, Sysctl}; use nix::unistd::Uid; - if !Uid::current().is_root() && CtlValue::Int(0) == ::sysctl::value("vfs.usermount").unwrap() + let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap(); + if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap() { skip!("{} requires the ability to mount file systems. Skipping test.", $name); } @@ -57,10 +58,10 @@ cfg_if! { #[cfg(target_os = "freebsd")] #[macro_export] macro_rules! skip_if_jailed { ($name:expr) => { - use ::sysctl::CtlValue; + use ::sysctl::{CtlValue, Sysctl}; - if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed") - .unwrap() + let ctl = ::sysctl::Ctl::new("security.jail.jailed").unwrap(); + if let CtlValue::Int(1) = ctl.value().unwrap() { skip!("{} cannot run in a jail. Skipping test.", $name); } diff --git a/test/sys/test_lio_listio_resubmit.rs b/test/sys/test_lio_listio_resubmit.rs index c9077891cb..2ed058c27c 100644 --- a/test/sys/test_lio_listio_resubmit.rs +++ b/test/sys/test_lio_listio_resubmit.rs @@ -11,7 +11,7 @@ use nix::sys::signal::SigevNotify; use nix::unistd::{SysconfVar, sysconf}; use std::os::unix::io::AsRawFd; use std::{thread, time}; -use sysctl::CtlValue; +use sysctl::{CtlValue, Sysctl}; use tempfile::tempfile; const BYTES_PER_OP: usize = 512; @@ -44,8 +44,8 @@ fn test_lio_listio_resubmit() { // Lookup system resource limits let alm = sysconf(SysconfVar::AIO_LISTIO_MAX) .expect("sysconf").unwrap() as usize; - let maqpp = if let CtlValue::Int(x) = sysctl::value( - "vfs.aio.max_aio_queue_per_proc").unwrap(){ + let ctl = sysctl::Ctl::new("vfs.aio.max_aio_queue_per_proc").unwrap(); + let maqpp = if let CtlValue::Int(x) = ctl.value().unwrap() { x as usize } else { panic!("unknown sysctl"); From fee16e27e113a6aaffd8dc0e53929f7792f872c8 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 24 Apr 2022 21:14:01 -0500 Subject: [PATCH 092/358] Upgrade dev-dependencies to the latest versions Don't change how the versions are specified (i.e. whether a patch version is listed). parking_lot cannot be upgraded due to 0.12.0 bumping the MSRV to 1.49. In many cases, nix was one of the only consumers of the current versions (i.e. we are late to upgrade). --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a87bae5ce4..936c0e4d77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,14 +78,14 @@ zerocopy = ["fs", "uio"] [dev-dependencies] assert-impl = "0.1" -lazy_static = "1.2" +lazy_static = "1.4" parking_lot = "0.11.2" rand = "0.8" -tempfile = "3.2.0" -semver = "1.0.0" +tempfile = "3.3.0" +semver = "1.0.7" [target.'cfg(any(target_os = "android", target_os = "linux"))'.dev-dependencies] -caps = "0.5.1" +caps = "0.5.3" [target.'cfg(target_os = "freebsd")'.dev-dependencies] sysctl = "0.4" From bf2fa038cd2a8ca91a582de7284c0bcaa9c332ac Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sat, 30 Apr 2022 18:12:39 -0500 Subject: [PATCH 093/358] Create new Unreleased changelog section --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6639a1a7a..8e79d37a57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +## [Unreleased] - ReleaseDate +### Added +### Changed +### Fixed +### Removed + ## [0.24.1] - 2022-04-22 ### Added ### Changed From 024c0d7ddefc5458911242d61a89f44b5a3b5a38 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Wed, 27 Apr 2022 18:27:03 -0700 Subject: [PATCH 094/358] Restore conversions from ip v4/6 Sockaddr types to std::net equivalents. Fixes #1710 --- CHANGELOG.md | 5 +++++ src/sys/socket/addr.rs | 22 ++++++++++++++++++++++ test/sys/test_socket.rs | 13 +++++++++++++ 3 files changed, 40 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e79d37a57..8e9baf9005 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added + +- impl From for std::net::SocketAddrV4 and + impl From for std::net::SocketAddrV6. + (#[1711](https://github.com/nix-rust/nix/pull/1711)) + ### Changed ### Fixed ### Removed diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 52d60ac9ab..5cd4678c3c 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1233,6 +1233,16 @@ impl From for SockaddrIn { } } +#[cfg(feature = "net")] +impl From for net::SocketAddrV4 { + fn from(addr: SockaddrIn) -> Self { + net::SocketAddrV4::new( + net::Ipv4Addr::from(addr.0.sin_addr.s_addr.to_ne_bytes()), + u16::from_be(addr.0.sin_port) + ) + } +} + #[cfg(feature = "net")] impl std::str::FromStr for SockaddrIn { type Err = net::AddrParseError; @@ -1329,6 +1339,18 @@ impl From for SockaddrIn6 { } } +#[cfg(feature = "net")] +impl From for net::SocketAddrV6 { + fn from(addr: SockaddrIn6) -> Self { + net::SocketAddrV6::new( + net::Ipv6Addr::from(addr.0.sin6_addr.s6_addr), + u16::from_be(addr.0.sin6_port), + u32::from_be(addr.0.sin6_flowinfo), + u32::from_be(addr.0.sin6_scope_id) + ) + } +} + #[cfg(feature = "net")] impl std::str::FromStr for SockaddrIn6 { type Err = net::AddrParseError; diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 2aac795851..c742960ae8 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -257,6 +257,19 @@ pub fn test_socketpair() { assert_eq!(&buf[..], b"hello"); } +#[test] +pub fn test_std_conversions() { + use nix::sys::socket::*; + + let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); + assert_eq!(std_sa, sock_addr.into()); + + let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap(); + let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa); + assert_eq!(std_sa, sock_addr.into()); +} + mod recvfrom { use nix::Result; use nix::sys::socket::*; From ad7d45a0bfa65c021fbcf7b4595988fffdca85a8 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Fri, 6 May 2022 22:07:05 -0500 Subject: [PATCH 095/358] Log compiler version in Cirrus CI --- .cirrus.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cirrus.yml b/.cirrus.yml index 358f66c6be..1b1b8b302e 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -16,6 +16,8 @@ env: build: &BUILD build_script: - . $HOME/.cargo/env || true + - $TOOL +$TOOLCHAIN -Vv + - rustc +$TOOLCHAIN -Vv - $TOOL +$TOOLCHAIN $BUILD $ZFLAGS --target $TARGET --all-targets - $TOOL +$TOOLCHAIN doc $ZFLAGS --no-deps --target $TARGET - $TOOL +$TOOLCHAIN clippy $ZFLAGS --target $TARGET -- -D warnings From b4fb5eec7db8443610b785983c5b94f6c4b632b7 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 7 May 2022 08:12:12 -0600 Subject: [PATCH 096/358] Future-proof the kevent ABI FreeBSD 12 changes struct kevent. For now, libc always binds to the 11-compat ABI. But that will change some day. Adjust Nix's code to build with either struct definition. --- src/sys/event.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/sys/event.rs b/src/sys/event.rs index 9262accf2c..0d0d23a48f 100644 --- a/src/sys/event.rs +++ b/src/sys/event.rs @@ -7,6 +7,7 @@ use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t}; #[cfg(target_os = "netbsd")] use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t}; use std::convert::TryInto; +use std::mem; use std::os::unix::io::RawFd; use std::ptr; @@ -21,13 +22,8 @@ pub struct KEvent { target_os = "ios", target_os = "macos", target_os = "openbsd"))] type type_of_udata = *mut libc::c_void; -#[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos"))] -type type_of_data = intptr_t; #[cfg(any(target_os = "netbsd"))] type type_of_udata = intptr_t; -#[cfg(any(target_os = "netbsd", target_os = "openbsd"))] -type type_of_data = i64; #[cfg(target_os = "netbsd")] type type_of_event_filter = u32; @@ -217,6 +213,7 @@ unsafe impl Send for KEvent { } impl KEvent { + #[allow(clippy::needless_update)] // Not needless on all platforms. pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag, fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent { KEvent { kevent: libc::kevent { @@ -224,8 +221,10 @@ impl KEvent { filter: filter as type_of_event_filter, flags: flags.bits(), fflags: fflags.bits(), - data: data as type_of_data, - udata: udata as type_of_udata + // data can be either i64 or intptr_t, depending on platform + data: data as _, + udata: udata as type_of_udata, + .. unsafe { mem::zeroed() } } } } @@ -328,7 +327,7 @@ fn test_struct_kevent() { assert_eq!(libc::EVFILT_READ, filter); assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits()); assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits()); - assert_eq!(0x1337, actual.data() as type_of_data); + assert_eq!(0x1337, actual.data()); assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata); assert_eq!(mem::size_of::(), mem::size_of::()); } From 23f1787d3b6c2e71f7afa398dac9050f69306e48 Mon Sep 17 00:00:00 2001 From: Jakub Jirutka Date: Sat, 7 May 2022 19:18:05 +0200 Subject: [PATCH 097/358] Define FsType constants for musl These constants are provided by Linux (linux/magic.h), not libc. See rust-lang/libc#2639. --- src/sys/statfs.rs | 104 +++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 5a7ac11aff..e8c06e4e3f 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -49,160 +49,160 @@ 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(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const AFS_SUPER_MAGIC: FsType = FsType(libc::AFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const AUTOFS_SUPER_MAGIC: FsType = FsType(libc::AUTOFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const BPF_FS_MAGIC: FsType = FsType(libc::BPF_FS_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const BTRFS_SUPER_MAGIC: FsType = FsType(libc::BTRFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const DEBUGFS_MAGIC: FsType = FsType(libc::DEBUGFS_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const DEVPTS_SUPER_MAGIC: FsType = FsType(libc::DEVPTS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const ECRYPTFS_SUPER_MAGIC: FsType = FsType(libc::ECRYPTFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const F2FS_SUPER_MAGIC: FsType = FsType(libc::F2FS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const FUSE_SUPER_MAGIC: FsType = FsType(libc::FUSE_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const FUTEXFS_SUPER_MAGIC: FsType = FsType(libc::FUTEXFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const HOSTFS_SUPER_MAGIC: FsType = FsType(libc::HOSTFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const MINIX3_SUPER_MAGIC: FsType = FsType(libc::MINIX3_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const NILFS_SUPER_MAGIC: FsType = FsType(libc::NILFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const OCFS2_SUPER_MAGIC: FsType = FsType(libc::OCFS2_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const OVERLAYFS_SUPER_MAGIC: FsType = FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const QNX6_SUPER_MAGIC: FsType = FsType(libc::QNX6_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const RDTGROUP_SUPER_MAGIC: FsType = FsType(libc::RDTGROUP_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const SECURITYFS_MAGIC: FsType = FsType(libc::SECURITYFS_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const SELINUX_MAGIC: FsType = FsType(libc::SELINUX_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const SMACK_MAGIC: FsType = FsType(libc::SMACK_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const SYSFS_MAGIC: FsType = FsType(libc::SYSFS_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const TRACEFS_MAGIC: FsType = FsType(libc::TRACEFS_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const UDF_SUPER_MAGIC: FsType = FsType(libc::UDF_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t); -#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const XENFS_SUPER_MAGIC: FsType = FsType(libc::XENFS_SUPER_MAGIC as fs_type_t); From 7dff51fbfc23aa9026557e9c47006723264ebc16 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 13 May 2022 19:02:58 -0600 Subject: [PATCH 098/358] Fix "unused_macro_rules" warnings with the latest nightly compiler. It just so happens that Redox, OpenBSD, Dragonfly, and uclibc don't use some of the rules for two internal macros. --- src/macros.rs | 3 +++ src/sys/socket/sockopt.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/macros.rs b/src/macros.rs index c357a0636c..018534fa67 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -94,6 +94,9 @@ macro_rules! libc_bitflags { /// } /// } /// ``` +// Some targets don't use all rules. +#[allow(unknown_lints)] +#[allow(unused_macro_rules)] macro_rules! libc_enum { // Exit rule. (@make_enum diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index e80b09e771..14fea808fc 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -129,6 +129,9 @@ macro_rules! getsockopt_impl { /// * `$ty:ty`: type of the value that will be get/set. /// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`. /// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`. +// Some targets don't use all rules. +#[allow(unknown_lints)] +#[allow(unused_macro_rules)] macro_rules! sockopt_impl { ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => { sockopt_impl!($(#[$attr])* From 0c07a9e4690fc4b2d8ceb90ac463c79e50d70947 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 30 Apr 2022 14:10:28 -0600 Subject: [PATCH 099/358] Rewrite the aio module The existing AIO implementation has some problems: 1) The in_progress field is checked at runtime, not compile time. 2) The mutable field is checked at runtime, not compile time. 3) A downstream lio_listio user must store extra state to track whether the whole operation is partially, completely, or not at all submitted. 4) Nix does heap allocation itself, rather than allowing the caller to choose it. This can result in double (or triple, or quadruple) boxing. 5) There's no easy way to use lio_listio to submit multiple operations with a single syscall, but poll each individually. 6) The lio_listio usage is far from transparent and zero-cost. 7) No aio_readv or aio_writev support. 8) priority has type c_int; should be i32 9) aio_return should return a usize instead of an isize, since it only uses negative values to indicate errors, which Rust represents via the Result type. This rewrite solves several problems: 1) Unsolved. I don't think it can be solved without something like C++'s guaranteed type elision. It might require changing the signature of Future::poll too. 2) Solved. 3) Solved, by the new in_progress method and by removing the complicated lio_listio resubmit code. 4) Solved. 5) Solved. 6) Solved, by removing the lio_listo resubmit code. It can be reimplemented downstream if necessary. Or even in Nix, but it doesn't fit Nix's theme of zero-cost abstractions. 7) Solved. 8) Solved. 9) Solved. The rewrite includes functions that don't work on FreeBSD, so add CI testing for FreeBSD 14 too. By default only enable tests that will pass on FreeBSD 12.3. But run a CI job on FreeBSD 14 and set a flag that will enable such tests. --- .cirrus.yml | 13 +- CHANGELOG.md | 16 + Cargo.toml | 9 +- bors.toml | 3 +- src/fcntl.rs | 8 +- src/sys/aio.rs | 1841 ++++++++++++++------------ test/sys/test_aio.rs | 1086 +++++++-------- test/sys/test_aio_drop.rs | 13 +- test/sys/test_lio_listio_resubmit.rs | 106 -- 9 files changed, 1570 insertions(+), 1525 deletions(-) delete mode 100644 test/sys/test_lio_listio_resubmit.rs diff --git a/.cirrus.yml b/.cirrus.yml index 1045f4f5b7..231cc38fb3 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -36,11 +36,18 @@ test: &TEST # 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-12-3-release-amd64 + matrix: + - name: FreeBSD 12 amd64 & i686 + freebsd_instance: + image: freebsd-12-3-release-amd64 + - name: FreeBSD 14 amd64 & i686 + freebsd_instance: + image_family: freebsd-14-0-snap + # Enable tests that would fail on FreeBSD 12 + RUSTFLAGS: --cfg fbsd14 -D warnings + RUSTDOCFLAGS: --cfg fbsd14 setup_script: - kldload mqueuefs - fetch https://sh.rustup.rs -o rustup.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e9baf9005..de4d22e2c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,14 +6,30 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added `aio_writev` and `aio_readv`. + (#[1713](https://github.com/nix-rust/nix/pull/1713)) + - impl From for std::net::SocketAddrV4 and impl From for std::net::SocketAddrV6. (#[1711](https://github.com/nix-rust/nix/pull/1711)) ### Changed + +- Rewrote the aio module. The new module: + * Does more type checking at compile time rather than runtime. + * Gives the caller control over whether and when to `Box` an aio operation. + * Changes the type of the `priority` arguments to `i32`. + * Changes the return type of `aio_return` to `usize`. + (#[1713](https://github.com/nix-rust/nix/pull/1713)) + ### Fixed ### Removed +- Removed support for resubmitting partially complete `lio_listio` operations. + It was too complicated, and didn't fit Nix's theme of zero-cost abstractions. + Instead, it can be reimplemented downstream. + (#[1713](https://github.com/nix-rust/nix/pull/1713)) + ## [0.24.1] - 2022-04-22 ### Added ### Changed diff --git a/Cargo.toml b/Cargo.toml index 628759ea31..ebd9182a53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,9 +27,10 @@ targets = [ ] [dependencies] -libc = { version = "0.2.124", features = [ "extra_traits" ] } +libc = { git = "http://github.com/rust-lang/libc.git", rev = "cd99f681181c310abfba742aef11115d2eff03dc", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" +pin-utils = { version = "0.1.0", optional = true } [target.'cfg(not(target_os = "redox"))'.dependencies] memoffset = { version = "0.6.3", optional = true } @@ -44,7 +45,7 @@ default = [ ] acct = [] -aio = [] +aio = ["pin-utils"] dir = ["fs"] env = [] event = [] @@ -102,10 +103,6 @@ path = "test/sys/test_aio_drop.rs" name = "test-clearenv" path = "test/test_clearenv.rs" -[[test]] -name = "test-lio-listio-resubmit" -path = "test/sys/test_lio_listio_resubmit.rs" - [[test]] name = "test-mount" path = "test/test_mount.rs" diff --git a/bors.toml b/bors.toml index b22877a767..b020ca389e 100644 --- a/bors.toml +++ b/bors.toml @@ -5,7 +5,8 @@ status = [ "Android i686", "Android x86_64", "DragonFly BSD x86_64", - "FreeBSD amd64 & i686", + "FreeBSD 12 amd64 & i686", + "FreeBSD 14 amd64 & i686", "Fuchsia x86_64", "Linux MIPS", "Linux MIPS64 el", diff --git a/src/fcntl.rs b/src/fcntl.rs index fa64c8eaed..5272c80955 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -742,8 +742,8 @@ impl SpacectlRange { /// /// # Example /// -// no_run because it fails to link until FreeBSD 14.0 -/// ```no_run +#[cfg_attr(fbsd14, doc = " ```")] +#[cfg_attr(not(fbsd14), doc = " ```no_run")] /// # use std::io::Write; /// # use std::os::unix::fs::FileExt; /// # use std::os::unix::io::AsRawFd; @@ -788,8 +788,8 @@ pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result { /// /// # Example /// -// no_run because it fails to link until FreeBSD 14.0 -/// ```no_run +#[cfg_attr(fbsd14, doc = " ```")] +#[cfg_attr(not(fbsd14), doc = " ```no_run")] /// # use std::io::Write; /// # use std::os::unix::fs::FileExt; /// # use std::os::unix::io::AsRawFd; diff --git a/src/sys/aio.rs b/src/sys/aio.rs index 4780cdee33..6ff88469b9 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -2,9 +2,12 @@ //! POSIX Asynchronous I/O //! //! The POSIX AIO interface is used for asynchronous I/O on files and disk-like -//! devices. It supports [`read`](struct.AioCb.html#method.read), -//! [`write`](struct.AioCb.html#method.write), and -//! [`fsync`](struct.AioCb.html#method.fsync) operations. Completion +//! devices. It supports [`read`](struct.AioRead.html#method.new), +//! [`write`](struct.AioWrite.html#method.new), +//! [`fsync`](struct.AioFsync.html#method.new), +//! [`readv`](struct.AioReadv.html#method.new), and +//! [`writev`](struct.AioWritev.html#method.new), operations, subject to +//! platform support. Completion //! notifications can optionally be delivered via //! [signals](../signal/enum.SigevNotify.html#variant.SigevSignal), via the //! [`aio_suspend`](fn.aio_suspend.html) function, or via polling. Some @@ -17,23 +20,30 @@ //! that they will be executed atomically. //! //! Outstanding operations may be cancelled with -//! [`cancel`](struct.AioCb.html#method.cancel) or +//! [`cancel`](trait.Aio.html#method.cancel) or //! [`aio_cancel_all`](fn.aio_cancel_all.html), though the operating system may //! not support this for all filesystems and devices. +#[cfg(target_os = "freebsd")] +use std::io::{IoSlice, IoSliceMut}; +use std::{ + convert::TryFrom, + fmt::{self, Debug}, + marker::{PhantomData, PhantomPinned}, + mem, + os::unix::io::RawFd, + pin::Pin, + ptr, + thread, +}; -use crate::Result; -use crate::errno::Errno; -use std::os::unix::io::RawFd; -use libc::{c_void, off_t, size_t}; -use std::fmt; -use std::fmt::Debug; -use std::marker::PhantomData; -use std::mem; -use std::pin::Pin; -use std::ptr::{null, null_mut}; -use crate::sys::signal::*; -use std::thread; -use crate::sys::time::TimeSpec; +use libc::{c_void, off_t}; +use pin_utils::unsafe_pinned; + +use crate::{ + errno::Errno, + sys::{signal::*, time::TimeSpec}, + Result, +}; libc_enum! { /// Mode for `AioCb::fsync`. Controls whether only data or both data and @@ -52,22 +62,7 @@ libc_enum! { #[cfg_attr(docsrs, doc(cfg(all())))] O_DSYNC } -} - -libc_enum! { - /// When used with [`lio_listio`](fn.lio_listio.html), determines whether a - /// given `aiocb` should be used for a read operation, a write operation, or - /// ignored. Has no effect for any other aio functions. - #[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, - } + impl TryFrom } libc_enum! { @@ -103,354 +98,133 @@ struct LibcAiocb(libc::aiocb); unsafe impl Send for LibcAiocb {} unsafe impl Sync for LibcAiocb {} -/// AIO Control Block. -/// -/// The basic structure used by all aio functions. Each `AioCb` represents one -/// I/O request. -pub struct AioCb<'a> { - aiocb: LibcAiocb, - /// Tracks whether the buffer pointed to by `libc::aiocb.aio_buf` is mutable - mutable: bool, +/// Base class for all AIO operations. Should only be used directly when +/// checking for completion. +// We could create some kind of AsPinnedMut trait, and implement it for all aio +// ops, allowing the crate's users to get pinned references to `AioCb`. That +// could save some code for things like polling methods. But IMHO it would +// provide polymorphism at the wrong level. Instead, the best place for +// polymorphism is at the level of `Futures`. +#[repr(C)] +struct AioCb { + aiocb: LibcAiocb, /// Could this `AioCb` potentially have any in-kernel state? + // It would be really nice to perform the in-progress check entirely at + // compile time. But I can't figure out how, because: + // * Future::poll takes a `Pin<&mut self>` rather than `self`, and + // * Rust's lack of an equivalent of C++'s Guaranteed Copy Elision means + // that there's no way to write an AioCb constructor that neither boxes + // the object itself, nor moves it during return. in_progress: bool, - _buffer: std::marker::PhantomData<&'a [u8]>, - _pin: std::marker::PhantomPinned } -impl<'a> AioCb<'a> { - /// Returns the underlying file descriptor associated with the `AioCb` - pub fn fd(&self) -> RawFd { - self.aiocb.0.aio_fildes - } +impl AioCb { + pin_utils::unsafe_unpinned!(aiocb: LibcAiocb); - /// Constructs a new `AioCb` with no associated buffer. - /// - /// The resulting `AioCb` structure is suitable for use with `AioCb::fsync`. - /// - /// # Parameters - /// - /// * `fd`: File descriptor. Required for all aio functions. - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio`. - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - /// - /// # Examples - /// - /// Create an `AioCb` from a raw file descriptor and use it for an - /// [`fsync`](#method.fsync) operation. - /// - /// ``` - /// # use nix::errno::Errno; - /// # use nix::Error; - /// # use nix::sys::aio::*; - /// # use nix::sys::signal::SigevNotify::SigevNone; - /// # use std::{thread, time}; - /// # use std::os::unix::io::AsRawFd; - /// # use tempfile::tempfile; - /// let f = tempfile().unwrap(); - /// let mut aiocb = AioCb::from_fd( f.as_raw_fd(), 0, SigevNone); - /// aiocb.fsync(AioFsyncMode::O_SYNC).expect("aio_fsync failed early"); - /// while (aiocb.error() == Err(Errno::EINPROGRESS)) { - /// thread::sleep(time::Duration::from_millis(10)); - /// } - /// aiocb.aio_return().expect("aio_fsync failed late"); - /// ``` - pub fn from_fd(fd: RawFd, prio: libc::c_int, - sigev_notify: SigevNotify) -> Pin>> { - let mut a = AioCb::common_init(fd, prio, sigev_notify); - a.0.aio_offset = 0; - a.0.aio_nbytes = 0; - a.0.aio_buf = null_mut(); - - Box::pin(AioCb { - aiocb: a, - mutable: false, - in_progress: false, - _buffer: PhantomData, - _pin: std::marker::PhantomPinned - }) + fn aio_return(mut self: Pin<&mut Self>) -> Result { + self.in_progress = false; + unsafe { + let p: *mut libc::aiocb = &mut self.aiocb.0; + Errno::result(libc::aio_return(p)) + } + .map(|r| r as usize) } - // Private helper - #[cfg(not(any(target_os = "ios", target_os = "macos")))] - fn from_mut_slice_unpinned(fd: RawFd, offs: off_t, buf: &'a mut [u8], - prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> AioCb<'a> - { - let mut a = AioCb::common_init(fd, prio, sigev_notify); - a.0.aio_offset = offs; - a.0.aio_nbytes = buf.len() as size_t; - a.0.aio_buf = buf.as_ptr() as *mut c_void; - a.0.aio_lio_opcode = opcode as libc::c_int; + fn cancel(mut self: Pin<&mut Self>) -> Result { + let r = unsafe { + libc::aio_cancel(self.aiocb.0.aio_fildes, &mut self.aiocb.0) + }; + match r { + libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), + libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), + libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), + -1 => Err(Errno::last()), + _ => panic!("unknown aio_cancel return value"), + } + } + fn common_init(fd: RawFd, prio: i32, sigev_notify: SigevNotify) -> Self { + // Use mem::zeroed instead of explicitly zeroing each field, because the + // number and name of reserved fields is OS-dependent. On some OSes, + // some reserved fields are used the kernel for state, and must be + // explicitly zeroed when allocated. + let mut a = unsafe { mem::zeroed::() }; + a.aio_fildes = fd; + a.aio_reqprio = prio; + a.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); AioCb { - aiocb: a, - mutable: true, + aiocb: LibcAiocb(a), in_progress: false, - _buffer: PhantomData, - _pin: std::marker::PhantomPinned } } - /// Constructs a new `AioCb` from a mutable slice. - /// - /// The resulting `AioCb` will be suitable for both read and write - /// operations, but only if the borrow checker can guarantee that the slice - /// will outlive the `AioCb`. That will usually be the case if the `AioCb` - /// is stack-allocated. - /// - /// # Parameters - /// - /// * `fd`: File descriptor. Required for all aio functions. - /// * `offs`: File offset - /// * `buf`: A memory buffer - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio` - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - /// * `opcode`: This field is only used for `lio_listio`. It - /// determines which operation to use for this individual - /// aiocb - /// - /// # Examples - /// - /// Create an `AioCb` from a mutable slice and read into it. - /// - /// ``` - /// # use nix::errno::Errno; - /// # use nix::Error; - /// # use nix::sys::aio::*; - /// # use nix::sys::signal::SigevNotify; - /// # use std::{thread, time}; - /// # use std::io::Write; - /// # use std::os::unix::io::AsRawFd; - /// # use tempfile::tempfile; - /// const INITIAL: &[u8] = b"abcdef123456"; - /// const LEN: usize = 4; - /// let mut rbuf = vec![0; LEN]; - /// let mut f = tempfile().unwrap(); - /// f.write_all(INITIAL).unwrap(); - /// { - /// let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(), - /// 2, //offset - /// &mut rbuf, - /// 0, //priority - /// SigevNotify::SigevNone, - /// LioOpcode::LIO_NOP); - /// aiocb.read().unwrap(); - /// while (aiocb.error() == Err(Errno::EINPROGRESS)) { - /// thread::sleep(time::Duration::from_millis(10)); - /// } - /// assert_eq!(aiocb.aio_return().unwrap() as usize, LEN); - /// } - /// assert_eq!(rbuf, b"cdef"); - /// ``` - pub fn from_mut_slice(fd: RawFd, offs: off_t, buf: &'a mut [u8], - prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> Pin>> { - let mut a = AioCb::common_init(fd, prio, sigev_notify); - a.0.aio_offset = offs; - a.0.aio_nbytes = buf.len() as size_t; - a.0.aio_buf = buf.as_ptr() as *mut c_void; - a.0.aio_lio_opcode = opcode as libc::c_int; - - Box::pin(AioCb { - aiocb: a, - mutable: true, - in_progress: false, - _buffer: PhantomData, - _pin: std::marker::PhantomPinned - }) + fn error(self: Pin<&mut Self>) -> Result<()> { + let r = unsafe { libc::aio_error(&self.aiocb().0) }; + match r { + 0 => Ok(()), + num if num > 0 => Err(Errno::from_i32(num)), + -1 => Err(Errno::last()), + num => panic!("unknown aio_error return value {:?}", num), + } } - /// Constructs a new `AioCb` from a mutable raw pointer - /// - /// Unlike `from_mut_slice`, this method returns a structure suitable for - /// placement on the heap. It may be used for both reads and writes. Due - /// to its unsafety, this method is not recommended. It is most useful when - /// heap allocation is required. - /// - /// # Parameters - /// - /// * `fd`: File descriptor. Required for all aio functions. - /// * `offs`: File offset - /// * `buf`: Pointer to the memory buffer - /// * `len`: Length of the buffer pointed to by `buf` - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio` - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - /// * `opcode`: This field is only used for `lio_listio`. It - /// determines which operation to use for this individual - /// aiocb - /// - /// # Safety - /// - /// The caller must ensure that the storage pointed to by `buf` outlives the - /// `AioCb`. The lifetime checker can't help here. - pub unsafe fn from_mut_ptr(fd: RawFd, offs: off_t, - buf: *mut c_void, len: usize, - prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> Pin>> { - let mut a = AioCb::common_init(fd, prio, sigev_notify); - a.0.aio_offset = offs; - a.0.aio_nbytes = len; - a.0.aio_buf = buf; - a.0.aio_lio_opcode = opcode as libc::c_int; - - Box::pin(AioCb { - aiocb: a, - mutable: true, - in_progress: false, - _buffer: PhantomData, - _pin: std::marker::PhantomPinned, - }) + fn in_progress(&self) -> bool { + self.in_progress } - /// Constructs a new `AioCb` from a raw pointer. - /// - /// Unlike `from_slice`, this method returns a structure suitable for - /// placement on the heap. Due to its unsafety, this method is not - /// recommended. It is most useful when heap allocation is required. - /// - /// # Parameters - /// - /// * `fd`: File descriptor. Required for all aio functions. - /// * `offs`: File offset - /// * `buf`: Pointer to the memory buffer - /// * `len`: Length of the buffer pointed to by `buf` - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio` - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - /// * `opcode`: This field is only used for `lio_listio`. It - /// determines which operation to use for this individual - /// aiocb - /// - /// # Safety - /// - /// The caller must ensure that the storage pointed to by `buf` outlives the - /// `AioCb`. The lifetime checker can't help here. - pub unsafe fn from_ptr(fd: RawFd, offs: off_t, - buf: *const c_void, len: usize, - prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> Pin>> { - let mut a = AioCb::common_init(fd, prio, sigev_notify); - a.0.aio_offset = offs; - a.0.aio_nbytes = len; - // casting a const ptr to a mutable ptr here is ok, because we set the - // AioCb's mutable field to false - a.0.aio_buf = buf as *mut c_void; - a.0.aio_lio_opcode = opcode as libc::c_int; - - Box::pin(AioCb { - aiocb: a, - mutable: false, - in_progress: false, - _buffer: PhantomData, - _pin: std::marker::PhantomPinned - }) + fn set_in_progress(mut self: Pin<&mut Self>) { + self.as_mut().in_progress = true; } - // Private helper - fn from_slice_unpinned(fd: RawFd, offs: off_t, buf: &'a [u8], - prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> AioCb - { - let mut a = AioCb::common_init(fd, prio, sigev_notify); - a.0.aio_offset = offs; - a.0.aio_nbytes = buf.len() as size_t; - // casting an immutable buffer to a mutable pointer looks unsafe, - // but technically its only unsafe to dereference it, not to create - // it. - a.0.aio_buf = buf.as_ptr() as *mut c_void; - assert!(opcode != LioOpcode::LIO_READ, "Can't read into an immutable buffer"); - a.0.aio_lio_opcode = opcode as libc::c_int; - - AioCb { - aiocb: a, - mutable: false, - in_progress: false, - _buffer: PhantomData, - _pin: std::marker::PhantomPinned - } + /// Update the notification settings for an existing AIO operation that has + /// not yet been submitted. + // Takes a normal reference rather than a pinned one because this method is + // normally called before the object needs to be pinned, that is, before + // it's been submitted to the kernel. + fn set_sigev_notify(&mut self, sigev_notify: SigevNotify) { + assert!( + !self.in_progress, + "Can't change notification settings for an in-progress operation" + ); + self.aiocb.0.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); } +} - /// Like [`AioCb::from_mut_slice`], but works on constant slices rather than - /// mutable slices. - /// - /// An `AioCb` created this way cannot be used with `read`, and its - /// `LioOpcode` cannot be set to `LIO_READ`. This method is useful when - /// writing a const buffer with `AioCb::write`, since `from_mut_slice` can't - /// work with const buffers. - /// - /// # Examples - /// - /// Construct an `AioCb` from a slice and use it for writing. - /// - /// ``` - /// # use nix::errno::Errno; - /// # use nix::Error; - /// # use nix::sys::aio::*; - /// # use nix::sys::signal::SigevNotify; - /// # use std::{thread, time}; - /// # use std::os::unix::io::AsRawFd; - /// # use tempfile::tempfile; - /// const WBUF: &[u8] = b"abcdef123456"; - /// let mut f = tempfile().unwrap(); - /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(), - /// 2, //offset - /// WBUF, - /// 0, //priority - /// SigevNotify::SigevNone, - /// LioOpcode::LIO_NOP); - /// aiocb.write().unwrap(); - /// while (aiocb.error() == Err(Errno::EINPROGRESS)) { - /// thread::sleep(time::Duration::from_millis(10)); - /// } - /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len()); - /// ``` - // Note: another solution to the problem of writing const buffers would be - // to genericize AioCb for both &mut [u8] and &[u8] buffers. AioCb::read - // could take the former and AioCb::write could take the latter. However, - // then lio_listio wouldn't work, because that function needs a slice of - // AioCb, and they must all be of the same type. - pub fn from_slice(fd: RawFd, offs: off_t, buf: &'a [u8], - prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> Pin> - { - Box::pin(AioCb::from_slice_unpinned(fd, offs, buf, prio, sigev_notify, - opcode)) +impl Debug for AioCb { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("AioCb") + .field("aiocb", &self.aiocb.0) + .field("in_progress", &self.in_progress) + .finish() } +} - fn common_init(fd: RawFd, prio: libc::c_int, - sigev_notify: SigevNotify) -> LibcAiocb { - // Use mem::zeroed instead of explicitly zeroing each field, because the - // number and name of reserved fields is OS-dependent. On some OSes, - // some reserved fields are used the kernel for state, and must be - // explicitly zeroed when allocated. - let mut a = unsafe { mem::zeroed::()}; - a.aio_fildes = fd; - a.aio_reqprio = prio; - a.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); - LibcAiocb(a) +impl Drop for AioCb { + /// If the `AioCb` has no remaining state in the kernel, just drop it. + /// Otherwise, dropping constitutes a resource leak, which is an error + fn drop(&mut self) { + assert!( + thread::panicking() || !self.in_progress, + "Dropped an in-progress AioCb" + ); } +} - /// Update the notification settings for an existing `aiocb` - pub fn set_sigev_notify(self: &mut Pin>, - sigev_notify: SigevNotify) - { - // Safe because we don't move any of the data - let selfp = unsafe { - self.as_mut().get_unchecked_mut() - }; - selfp.aiocb.0.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); - } +/// Methods common to all AIO operations +pub trait Aio { + /// The return type of [`Aio::aio_return`]. + type Output; + + /// Retrieve return status of an asynchronous operation. + /// + /// Should only be called once for each operation, after [`Aio::error`] + /// indicates that it has completed. The result is the same as for the + /// synchronous `read(2)`, `write(2)`, of `fsync(2)` functions. + /// + /// # References + /// + /// [aio_return](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html) + fn aio_return(self: Pin<&mut Self>) -> Result; /// Cancels an outstanding AIO request. /// @@ -477,51 +251,26 @@ impl<'a> AioCb<'a> { /// # use tempfile::tempfile; /// let wbuf = b"CDEF"; /// let mut f = tempfile().unwrap(); - /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(), + /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), /// 2, //offset /// &wbuf[..], /// 0, //priority - /// SigevNotify::SigevNone, - /// LioOpcode::LIO_NOP); - /// aiocb.write().unwrap(); - /// let cs = aiocb.cancel().unwrap(); + /// SigevNotify::SigevNone)); + /// aiocb.as_mut().submit().unwrap(); + /// let cs = aiocb.as_mut().cancel().unwrap(); /// if cs == AioCancelStat::AioNotCanceled { - /// while (aiocb.error() == Err(Errno::EINPROGRESS)) { + /// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { /// thread::sleep(time::Duration::from_millis(10)); /// } /// } /// // Must call `aio_return`, but ignore the result - /// let _ = aiocb.aio_return(); + /// let _ = aiocb.as_mut().aio_return(); /// ``` /// /// # References /// /// [aio_cancel](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) - pub fn cancel(self: &mut Pin>) -> Result { - let r = unsafe { - let selfp = self.as_mut().get_unchecked_mut(); - libc::aio_cancel(selfp.aiocb.0.aio_fildes, &mut selfp.aiocb.0) - }; - match r { - libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), - libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), - libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), - -1 => Err(Errno::last()), - _ => panic!("unknown aio_cancel return value") - } - } - - fn error_unpinned(&mut self) -> Result<()> { - let r = unsafe { - libc::aio_error(&mut self.aiocb.0 as *mut libc::aiocb) - }; - match r { - 0 => Ok(()), - num if num > 0 => Err(Errno::from_i32(num)), - -1 => Err(Errno::last()), - num => panic!("unknown aio_error return value {:?}", num) - } - } + fn cancel(self: Pin<&mut Self>) -> Result; /// Retrieve error status of an asynchronous operation. /// @@ -543,155 +292,222 @@ impl<'a> AioCb<'a> { /// # use tempfile::tempfile; /// const WBUF: &[u8] = b"abcdef123456"; /// let mut f = tempfile().unwrap(); - /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(), + /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), /// 2, //offset /// WBUF, /// 0, //priority - /// SigevNotify::SigevNone, - /// LioOpcode::LIO_NOP); - /// aiocb.write().unwrap(); - /// while (aiocb.error() == Err(Errno::EINPROGRESS)) { + /// SigevNotify::SigevNone)); + /// aiocb.as_mut().submit().unwrap(); + /// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { /// thread::sleep(time::Duration::from_millis(10)); /// } - /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len()); + /// assert_eq!(aiocb.as_mut().aio_return().unwrap(), WBUF.len()); /// ``` /// /// # References /// /// [aio_error](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_error.html) - pub fn error(self: &mut Pin>) -> Result<()> { - // Safe because error_unpinned doesn't move the data - let selfp = unsafe { - self.as_mut().get_unchecked_mut() - }; - selfp.error_unpinned() - } + fn error(self: Pin<&mut Self>) -> Result<()>; - /// An asynchronous version of `fsync(2)`. + /// Returns the underlying file descriptor associated with the operation. + fn fd(&self) -> RawFd; + + /// Does this operation currently have any in-kernel state? /// - /// # References + /// Dropping an operation that does have in-kernel state constitutes a + /// resource leak. /// - /// [aio_fsync](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html) - pub fn fsync(self: &mut Pin>, mode: AioFsyncMode) -> Result<()> { - // Safe because we don't move the libc::aiocb - unsafe { - let selfp = self.as_mut().get_unchecked_mut(); - Errno::result({ - let p: *mut libc::aiocb = &mut selfp.aiocb.0; - libc::aio_fsync(mode as libc::c_int, p) - }).map(|_| { - selfp.in_progress = true; - }) - } - } - - /// Returns the `aiocb`'s `LioOpcode` field + /// # Examples /// - /// If the value cannot be represented as an `LioOpcode`, returns `None` - /// instead. - pub fn lio_opcode(&self) -> Option { - match self.aiocb.0.aio_lio_opcode { - libc::LIO_READ => Some(LioOpcode::LIO_READ), - libc::LIO_WRITE => Some(LioOpcode::LIO_WRITE), - libc::LIO_NOP => Some(LioOpcode::LIO_NOP), - _ => None - } - } + /// ``` + /// # use nix::errno::Errno; + /// # use nix::Error; + /// # use nix::sys::aio::*; + /// # use nix::sys::signal::SigevNotify::SigevNone; + /// # use std::{thread, time}; + /// # use std::os::unix::io::AsRawFd; + /// # use tempfile::tempfile; + /// let f = tempfile().unwrap(); + /// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC, + /// 0, SigevNone)); + /// assert!(!aiof.as_mut().in_progress()); + /// aiof.as_mut().submit().expect("aio_fsync failed early"); + /// assert!(aiof.as_mut().in_progress()); + /// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) { + /// thread::sleep(time::Duration::from_millis(10)); + /// } + /// aiof.as_mut().aio_return().expect("aio_fsync failed late"); + /// assert!(!aiof.as_mut().in_progress()); + /// ``` + fn in_progress(&self) -> bool; - /// Returns the requested length of the aio operation in bytes - /// - /// This method returns the *requested* length of the operation. To get the - /// number of bytes actually read or written by a completed operation, use - /// `aio_return` instead. - pub fn nbytes(&self) -> usize { - self.aiocb.0.aio_nbytes - } + /// Returns the priority of the `AioCb` + fn priority(&self) -> i32; - /// Returns the file offset stored in the `AioCb` - pub fn offset(&self) -> off_t { - self.aiocb.0.aio_offset - } + /// Update the notification settings for an existing AIO operation that has + /// not yet been submitted. + fn set_sigev_notify(&mut self, sev: SigevNotify); - /// Returns the priority of the `AioCb` - pub fn priority(&self) -> libc::c_int { - self.aiocb.0.aio_reqprio - } + /// Returns the `SigEvent` that will be used for notification. + fn sigevent(&self) -> SigEvent; - /// Asynchronously reads from a file descriptor into a buffer + /// Actually start the I/O operation. /// - /// # References - /// - /// [aio_read](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html) - pub fn read(self: &mut Pin>) -> Result<()> { - assert!(self.mutable, "Can't read into an immutable buffer"); - // Safe because we don't move anything - let selfp = unsafe { - self.as_mut().get_unchecked_mut() - }; - Errno::result({ - let p: *mut libc::aiocb = &mut selfp.aiocb.0; - unsafe { libc::aio_read(p) } - }).map(|_| { - selfp.in_progress = true; - }) - } + /// After calling this method and until [`Aio::aio_return`] returns `Ok`, + /// the structure may not be moved in memory. + fn submit(self: Pin<&mut Self>) -> Result<()>; +} - /// Returns the `SigEvent` stored in the `AioCb` - pub fn sigevent(&self) -> SigEvent { - SigEvent::from(&self.aiocb.0.aio_sigevent) - } +macro_rules! aio_methods { + () => { + fn cancel(self: Pin<&mut Self>) -> Result { + self.aiocb().cancel() + } - fn aio_return_unpinned(&mut self) -> Result { - unsafe { - let p: *mut libc::aiocb = &mut self.aiocb.0; - self.in_progress = false; - Errno::result(libc::aio_return(p)) + fn error(self: Pin<&mut Self>) -> Result<()> { + self.aiocb().error() } - } - /// Retrieve return status of an asynchronous operation. - /// - /// Should only be called once for each `AioCb`, after `AioCb::error` - /// indicates that it has completed. The result is the same as for the - /// synchronous `read(2)`, `write(2)`, of `fsync(2)` functions. - /// - /// # References - /// - /// [aio_return](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html) - // Note: this should be just `return`, but that's a reserved word - pub fn aio_return(self: &mut Pin>) -> Result { - // Safe because aio_return_unpinned does not move the data - let selfp = unsafe { - self.as_mut().get_unchecked_mut() - }; - selfp.aio_return_unpinned() - } + fn fd(&self) -> RawFd { + self.aiocb.aiocb.0.aio_fildes + } - /// Asynchronously writes from a buffer to a file descriptor - /// - /// # References - /// - /// [aio_write](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html) - pub fn write(self: &mut Pin>) -> Result<()> { - // Safe because we don't move anything - let selfp = unsafe { - self.as_mut().get_unchecked_mut() - }; - Errno::result({ - let p: *mut libc::aiocb = &mut selfp.aiocb.0; - unsafe{ libc::aio_write(p) } - }).map(|_| { - selfp.in_progress = true; - }) - } -} + fn in_progress(&self) -> bool { + self.aiocb.in_progress() + } -/// Cancels outstanding AIO requests for a given file descriptor. + fn priority(&self) -> i32 { + self.aiocb.aiocb.0.aio_reqprio + } + + fn set_sigev_notify(&mut self, sev: SigevNotify) { + self.aiocb.set_sigev_notify(sev) + } + + fn sigevent(&self) -> SigEvent { + SigEvent::from(&self.aiocb.aiocb.0.aio_sigevent) + } + }; + ($func:ident) => { + aio_methods!(); + + fn aio_return(self: Pin<&mut Self>) -> Result<::Output> { + self.aiocb().aio_return() + } + + fn submit(mut self: Pin<&mut Self>) -> Result<()> { + let p: *mut libc::aiocb = &mut self.as_mut().aiocb().aiocb.0; + Errno::result({ unsafe { libc::$func(p) } }).map(|_| { + self.aiocb().set_in_progress(); + }) + } + }; +} + +/// An asynchronous version of `fsync(2)`. +/// +/// # References +/// +/// [aio_fsync](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html) +/// # Examples +/// +/// ``` +/// # use nix::errno::Errno; +/// # use nix::Error; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify::SigevNone; +/// # use std::{thread, time}; +/// # use std::os::unix::io::AsRawFd; +/// # use tempfile::tempfile; +/// let f = tempfile().unwrap(); +/// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC, +/// 0, SigevNone)); +/// aiof.as_mut().submit().expect("aio_fsync failed early"); +/// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// aiof.as_mut().aio_return().expect("aio_fsync failed late"); +/// ``` +#[derive(Debug)] +#[repr(transparent)] +pub struct AioFsync { + aiocb: AioCb, + _pin: PhantomPinned, +} + +impl AioFsync { + unsafe_pinned!(aiocb: AioCb); + + /// Returns the operation's fsync mode: data and metadata or data only? + pub fn mode(&self) -> AioFsyncMode { + AioFsyncMode::try_from(self.aiocb.aiocb.0.aio_lio_opcode).unwrap() + } + + /// Create a new `AioFsync`. + /// + /// # Arguments + /// + /// * `fd`: File descriptor to sync. + /// * `mode`: Whether to sync file metadata too, or just data. + /// * `prio`: If POSIX Prioritized IO is supported, then the + /// operation will be prioritized at the process's + /// priority level minus `prio`. + /// * `sigev_notify`: Determines how you will be notified of event + /// completion. + pub fn new( + fd: RawFd, + mode: AioFsyncMode, + prio: i32, + sigev_notify: SigevNotify, + ) -> Self { + let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); + // To save some memory, store mode in an unused field of the AioCb. + // True it isn't very much memory, but downstream creates will likely + // create an enum containing this and other AioCb variants and pack + // those enums into data structures like Vec, so it adds up. + aiocb.aiocb.0.aio_lio_opcode = mode as libc::c_int; + AioFsync { + aiocb, + _pin: PhantomPinned, + } + } +} + +impl Aio for AioFsync { + type Output = (); + + aio_methods!(); + + fn aio_return(self: Pin<&mut Self>) -> Result<()> { + self.aiocb().aio_return().map(drop) + } + + fn submit(mut self: Pin<&mut Self>) -> Result<()> { + let aiocb = &mut self.as_mut().aiocb().aiocb.0; + let mode = mem::replace(&mut aiocb.aio_lio_opcode, 0); + let p: *mut libc::aiocb = aiocb; + Errno::result(unsafe { libc::aio_fsync(mode, p) }).map(|_| { + self.aiocb().set_in_progress(); + }) + } +} + +// AioFsync does not need AsMut, since it can't be used with lio_listio + +impl AsRef for AioFsync { + fn as_ref(&self) -> &libc::aiocb { + &self.aiocb.aiocb.0 + } +} + +/// Asynchronously reads from a file descriptor into a buffer +/// +/// # References +/// +/// [aio_read](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html) /// /// # Examples /// -/// Issue an aio operation, then cancel all outstanding operations on that file -/// descriptor. /// /// ``` /// # use nix::errno::Errno; @@ -702,428 +518,727 @@ impl<'a> AioCb<'a> { /// # use std::io::Write; /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; -/// let wbuf = b"CDEF"; +/// const INITIAL: &[u8] = b"abcdef123456"; +/// const LEN: usize = 4; +/// let mut rbuf = vec![0; LEN]; /// let mut f = tempfile().unwrap(); -/// let mut aiocb = AioCb::from_slice( f.as_raw_fd(), -/// 2, //offset -/// &wbuf[..], -/// 0, //priority -/// SigevNotify::SigevNone, -/// LioOpcode::LIO_NOP); -/// aiocb.write().unwrap(); -/// let cs = aio_cancel_all(f.as_raw_fd()).unwrap(); -/// if cs == AioCancelStat::AioNotCanceled { -/// while (aiocb.error() == Err(Errno::EINPROGRESS)) { +/// f.write_all(INITIAL).unwrap(); +/// { +/// let mut aior = Box::pin( +/// AioRead::new( +/// f.as_raw_fd(), +/// 2, //offset +/// &mut rbuf, +/// 0, //priority +/// SigevNotify::SigevNone +/// ) +/// ); +/// aior.as_mut().submit().unwrap(); +/// while (aior.as_mut().error() == Err(Errno::EINPROGRESS)) { /// thread::sleep(time::Duration::from_millis(10)); /// } +/// assert_eq!(aior.as_mut().aio_return().unwrap(), LEN); /// } -/// // Must call `aio_return`, but ignore the result -/// let _ = aiocb.aio_return(); +/// assert_eq!(rbuf, b"cdef"); /// ``` -/// -/// # References -/// -/// [`aio_cancel`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) -pub fn aio_cancel_all(fd: RawFd) -> Result { - match unsafe { libc::aio_cancel(fd, null_mut()) } { - libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), - libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), - libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), - -1 => Err(Errno::last()), - _ => panic!("unknown aio_cancel return value") +#[derive(Debug)] +#[repr(transparent)] +pub struct AioRead<'a> { + aiocb: AioCb, + _data: PhantomData<&'a [u8]>, + _pin: PhantomPinned, +} + +impl<'a> AioRead<'a> { + unsafe_pinned!(aiocb: AioCb); + + /// Returns the requested length of the aio operation in bytes + /// + /// This method returns the *requested* length of the operation. To get the + /// number of bytes actually read or written by a completed operation, use + /// `aio_return` instead. + pub fn nbytes(&self) -> usize { + self.aiocb.aiocb.0.aio_nbytes + } + + /// Create a new `AioRead`, placing the data in a mutable slice. + /// + /// # Arguments + /// + /// * `fd`: File descriptor to read from + /// * `offs`: File offset + /// * `buf`: A memory buffer. It must outlive the `AioRead`. + /// * `prio`: If POSIX Prioritized IO is supported, then the + /// operation will be prioritized at the process's + /// priority level minus `prio` + /// * `sigev_notify`: Determines how you will be notified of event + /// completion. + pub fn new( + fd: RawFd, + offs: off_t, + buf: &'a mut [u8], + prio: i32, + sigev_notify: SigevNotify, + ) -> Self { + let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); + aiocb.aiocb.0.aio_nbytes = buf.len(); + aiocb.aiocb.0.aio_buf = buf.as_mut_ptr() as *mut c_void; + aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READ; + aiocb.aiocb.0.aio_offset = offs; + AioRead { + aiocb, + _data: PhantomData, + _pin: PhantomPinned, + } + } + + /// Returns the file offset of the operation. + pub fn offset(&self) -> off_t { + self.aiocb.aiocb.0.aio_offset } } -/// Suspends the calling process until at least one of the specified `AioCb`s -/// has completed, a signal is delivered, or the timeout has passed. +impl<'a> Aio for AioRead<'a> { + type Output = usize; + + aio_methods!(aio_read); +} + +impl<'a> AsMut for AioRead<'a> { + fn as_mut(&mut self) -> &mut libc::aiocb { + &mut self.aiocb.aiocb.0 + } +} + +impl<'a> AsRef for AioRead<'a> { + fn as_ref(&self) -> &libc::aiocb { + &self.aiocb.aiocb.0 + } +} + +/// Asynchronously reads from a file descriptor into a scatter/gather list of buffers. /// -/// If `timeout` is `None`, `aio_suspend` will block indefinitely. +/// # References +/// +/// [aio_readv](https://www.freebsd.org/cgi/man.cgi?query=aio_readv) /// /// # Examples /// -/// Use `aio_suspend` to block until an aio operation completes. /// -/// ``` +#[cfg_attr(fbsd14, doc = " ```")] +#[cfg_attr(not(fbsd14), doc = " ```no_run")] +/// # use nix::errno::Errno; +/// # use nix::Error; /// # use nix::sys::aio::*; /// # use nix::sys::signal::SigevNotify; +/// # use std::{thread, time}; +/// # use std::io::{IoSliceMut, Write}; /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; -/// const WBUF: &[u8] = b"abcdef123456"; +/// const INITIAL: &[u8] = b"abcdef123456"; +/// let mut rbuf0 = vec![0; 4]; +/// let mut rbuf1 = vec![0; 2]; +/// let expected_len = rbuf0.len() + rbuf1.len(); +/// let mut rbufs = [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)]; /// let mut f = tempfile().unwrap(); -/// let mut aiocb = AioCb::from_slice( f.as_raw_fd(), -/// 2, //offset -/// WBUF, -/// 0, //priority -/// SigevNotify::SigevNone, -/// LioOpcode::LIO_NOP); -/// aiocb.write().unwrap(); -/// aio_suspend(&[aiocb.as_ref()], None).expect("aio_suspend failed"); -/// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len()); +/// f.write_all(INITIAL).unwrap(); +/// { +/// let mut aior = Box::pin( +/// AioReadv::new( +/// f.as_raw_fd(), +/// 2, //offset +/// &mut rbufs, +/// 0, //priority +/// SigevNotify::SigevNone +/// ) +/// ); +/// aior.as_mut().submit().unwrap(); +/// while (aior.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// assert_eq!(aior.as_mut().aio_return().unwrap(), expected_len); +/// } +/// assert_eq!(rbuf0, b"cdef"); +/// assert_eq!(rbuf1, b"12"); /// ``` -/// # References -/// -/// [`aio_suspend`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html) -pub fn aio_suspend(list: &[Pin<&AioCb>], timeout: Option) -> Result<()> { - let plist = list as *const [Pin<&AioCb>] as *const [*const libc::aiocb]; - let p = plist as *const *const libc::aiocb; - let timep = match timeout { - None => null::(), - Some(x) => x.as_ref() as *const libc::timespec - }; - Errno::result(unsafe { - libc::aio_suspend(p, list.len() as i32, timep) - }).map(drop) +#[cfg(target_os = "freebsd")] +#[derive(Debug)] +#[repr(transparent)] +pub struct AioReadv<'a> { + aiocb: AioCb, + _data: PhantomData<&'a [&'a [u8]]>, + _pin: PhantomPinned, } -impl<'a> Debug for AioCb<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("AioCb") - .field("aiocb", &self.aiocb.0) - .field("mutable", &self.mutable) - .field("in_progress", &self.in_progress) - .finish() +#[cfg(target_os = "freebsd")] +impl<'a> AioReadv<'a> { + unsafe_pinned!(aiocb: AioCb); + + /// Returns the number of buffers the operation will read into. + pub fn iovlen(&self) -> usize { + self.aiocb.aiocb.0.aio_nbytes } -} -impl<'a> Drop for AioCb<'a> { - /// If the `AioCb` has no remaining state in the kernel, just drop it. - /// Otherwise, dropping constitutes a resource leak, which is an error - fn drop(&mut self) { - assert!(thread::panicking() || !self.in_progress, - "Dropped an in-progress AioCb"); + /// Create a new `AioReadv`, placing the data in a list of mutable slices. + /// + /// # Arguments + /// + /// * `fd`: File descriptor to read from + /// * `offs`: File offset + /// * `bufs`: A scatter/gather list of memory buffers. They must + /// outlive the `AioReadv`. + /// * `prio`: If POSIX Prioritized IO is supported, then the + /// operation will be prioritized at the process's + /// priority level minus `prio` + /// * `sigev_notify`: Determines how you will be notified of event + /// completion. + pub fn new( + fd: RawFd, + offs: off_t, + bufs: &mut [IoSliceMut<'a>], + prio: i32, + sigev_notify: SigevNotify, + ) -> Self { + let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); + // In vectored mode, aio_nbytes stores the length of the iovec array, + // not the byte count. + aiocb.aiocb.0.aio_nbytes = bufs.len(); + aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr() as *mut c_void; + aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READV; + aiocb.aiocb.0.aio_offset = offs; + AioReadv { + aiocb, + _data: PhantomData, + _pin: PhantomPinned, + } + } + + /// Returns the file offset of the operation. + pub fn offset(&self) -> off_t { + self.aiocb.aiocb.0.aio_offset } } -/// LIO Control Block. -/// -/// The basic structure used to issue multiple AIO operations simultaneously. -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -#[cfg_attr(docsrs, doc(cfg(all())))] -pub struct LioCb<'a> { - /// A collection of [`AioCb`]s. All of these will be issued simultaneously - /// by the [`listio`] method. - /// - /// [`AioCb`]: struct.AioCb.html - /// [`listio`]: #method.listio - // Their locations in memory must be fixed once they are passed to the - // kernel. So this field must be non-public so the user can't swap. - aiocbs: Box<[AioCb<'a>]>, +#[cfg(target_os = "freebsd")] +impl<'a> Aio for AioReadv<'a> { + type Output = usize; - /// The actual list passed to `libc::lio_listio`. - /// - /// It must live for as long as any of the operations are still being - /// processesed, because the aio subsystem uses its address as a unique - /// identifier. - list: Vec<*mut libc::aiocb>, - - /// A partial set of results. This field will get populated by - /// `listio_resubmit` when an `LioCb` is resubmitted after an error - results: Vec>> + aio_methods!(aio_readv); } -/// LioCb can't automatically impl Send and Sync just because of the raw -/// pointers in list. But that's stupid. There's no reason that raw pointers -/// should automatically be non-Send -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -unsafe impl<'a> Send for LioCb<'a> {} -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -unsafe impl<'a> Sync for LioCb<'a> {} - -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -#[cfg_attr(docsrs, doc(cfg(all())))] -impl<'a> LioCb<'a> { - /// Are no [`AioCb`]s contained? - pub fn is_empty(&self) -> bool { - self.aiocbs.is_empty() +#[cfg(target_os = "freebsd")] +impl<'a> AsMut for AioReadv<'a> { + fn as_mut(&mut self) -> &mut libc::aiocb { + &mut self.aiocb.aiocb.0 } +} - /// Return the number of individual [`AioCb`]s contained. - pub fn len(&self) -> usize { - self.aiocbs.len() +#[cfg(target_os = "freebsd")] +impl<'a> AsRef for AioReadv<'a> { + fn as_ref(&self) -> &libc::aiocb { + &self.aiocb.aiocb.0 } +} - /// Submits multiple asynchronous I/O requests with a single system call. - /// - /// They are not guaranteed to complete atomically, and the order in which - /// the requests are carried out is not specified. Reads, writes, and - /// fsyncs may be freely mixed. - /// - /// This function is useful for reducing the context-switch overhead of - /// submitting many AIO operations. It can also be used with - /// `LioMode::LIO_WAIT` to block on the result of several independent - /// operations. Used that way, it is often useful in programs that - /// otherwise make little use of AIO. - /// - /// # Examples - /// - /// Use `listio` to submit an aio operation and wait for its completion. In - /// this case, there is no need to use [`aio_suspend`] to wait or - /// [`AioCb::error`] to poll. - /// - /// ``` - /// # use nix::sys::aio::*; - /// # use nix::sys::signal::SigevNotify; - /// # use std::os::unix::io::AsRawFd; - /// # use tempfile::tempfile; - /// const WBUF: &[u8] = b"abcdef123456"; - /// let mut f = tempfile().unwrap(); - /// let mut liocb = LioCbBuilder::with_capacity(1) - /// .emplace_slice( - /// f.as_raw_fd(), - /// 2, //offset - /// WBUF, - /// 0, //priority - /// SigevNotify::SigevNone, - /// LioOpcode::LIO_WRITE - /// ).finish(); - /// liocb.listio(LioMode::LIO_WAIT, - /// SigevNotify::SigevNone).unwrap(); - /// assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); - /// ``` - /// - /// # References - /// - /// [`lio_listio`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html) +/// Asynchronously writes from a buffer to a file descriptor +/// +/// # References +/// +/// [aio_write](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html) +/// +/// # Examples +/// +/// ``` +/// # use nix::errno::Errno; +/// # use nix::Error; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use std::{thread, time}; +/// # use std::os::unix::io::AsRawFd; +/// # use tempfile::tempfile; +/// const WBUF: &[u8] = b"abcdef123456"; +/// let mut f = tempfile().unwrap(); +/// let mut aiow = Box::pin( +/// AioWrite::new( +/// f.as_raw_fd(), +/// 2, //offset +/// WBUF, +/// 0, //priority +/// SigevNotify::SigevNone +/// ) +/// ); +/// aiow.as_mut().submit().unwrap(); +/// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); +/// ``` +#[derive(Debug)] +#[repr(transparent)] +pub struct AioWrite<'a> { + aiocb: AioCb, + _data: PhantomData<&'a [u8]>, + _pin: PhantomPinned, +} + +impl<'a> AioWrite<'a> { + unsafe_pinned!(aiocb: AioCb); + + /// Returns the requested length of the aio operation in bytes /// - /// [`aio_suspend`]: fn.aio_suspend.html - /// [`AioCb::error`]: struct.AioCb.html#method.error - pub fn listio(&mut self, mode: LioMode, - sigev_notify: SigevNotify) -> Result<()> { - let sigev = SigEvent::new(sigev_notify); - let sigevp = &mut sigev.sigevent() as *mut libc::sigevent; - self.list.clear(); - for a in &mut self.aiocbs.iter_mut() { - a.in_progress = true; - self.list.push(a as *mut AioCb<'a> - as *mut libc::aiocb); - } - let p = self.list.as_ptr(); - Errno::result(unsafe { - libc::lio_listio(mode as i32, p, self.list.len() as i32, sigevp) - }).map(drop) + /// This method returns the *requested* length of the operation. To get the + /// number of bytes actually read or written by a completed operation, use + /// `aio_return` instead. + pub fn nbytes(&self) -> usize { + self.aiocb.aiocb.0.aio_nbytes } - /// Resubmits any incomplete operations with [`lio_listio`]. - /// - /// Sometimes, due to system resource limitations, an `lio_listio` call will - /// return `EIO`, or `EAGAIN`. Or, if a signal is received, it may return - /// `EINTR`. In any of these cases, only a subset of its constituent - /// operations will actually have been initiated. `listio_resubmit` will - /// resubmit any operations that are still uninitiated. - /// - /// After calling `listio_resubmit`, results should be collected by - /// [`LioCb::aio_return`]. - /// - /// # Examples - /// ```no_run - /// # use nix::Error; - /// # use nix::errno::Errno; - /// # use nix::sys::aio::*; - /// # use nix::sys::signal::SigevNotify; - /// # use std::os::unix::io::AsRawFd; - /// # use std::{thread, time}; - /// # use tempfile::tempfile; - /// const WBUF: &[u8] = b"abcdef123456"; - /// let mut f = tempfile().unwrap(); - /// let mut liocb = LioCbBuilder::with_capacity(1) - /// .emplace_slice( - /// f.as_raw_fd(), - /// 2, //offset - /// WBUF, - /// 0, //priority - /// SigevNotify::SigevNone, - /// LioOpcode::LIO_WRITE - /// ).finish(); - /// let mut err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone); - /// while err == Err(Errno::EIO) || - /// err == Err(Errno::EAGAIN) { - /// thread::sleep(time::Duration::from_millis(10)); - /// err = liocb.listio_resubmit(LioMode::LIO_WAIT, SigevNotify::SigevNone); - /// } - /// assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); - /// ``` - /// - /// # References + /// Construct a new `AioWrite`. /// - /// [`lio_listio`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html) + /// # Arguments /// - /// [`lio_listio`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html - /// [`LioCb::aio_return`]: struct.LioCb.html#method.aio_return - // Note: the addresses of any EINPROGRESS or EOK aiocbs _must_ not be - // changed by this method, because the kernel relies on their addresses - // being stable. - // Note: aiocbs that are Ok(()) must be finalized by aio_return, or else the - // sigev_notify will immediately refire. - pub fn listio_resubmit(&mut self, mode:LioMode, - sigev_notify: SigevNotify) -> Result<()> { - let sigev = SigEvent::new(sigev_notify); - let sigevp = &mut sigev.sigevent() as *mut libc::sigevent; - self.list.clear(); - - while self.results.len() < self.aiocbs.len() { - self.results.push(None); - } - - for (i, a) in self.aiocbs.iter_mut().enumerate() { - if self.results[i].is_some() { - // Already collected final status for this operation - continue; - } - match a.error_unpinned() { - Ok(()) => { - // aiocb is complete; collect its status and don't resubmit - self.results[i] = Some(a.aio_return_unpinned()); - }, - Err(Errno::EAGAIN) => { - self.list.push(a as *mut AioCb<'a> as *mut libc::aiocb); - }, - Err(Errno::EINPROGRESS) => { - // aiocb is was successfully queued; no need to do anything - }, - Err(Errno::EINVAL) => panic!( - "AioCb was never submitted, or already finalized"), - _ => unreachable!() - } + /// * `fd`: File descriptor to write to + /// * `offs`: File offset + /// * `buf`: A memory buffer. It must outlive the `AioWrite`. + /// * `prio`: If POSIX Prioritized IO is supported, then the + /// operation will be prioritized at the process's + /// priority level minus `prio` + /// * `sigev_notify`: Determines how you will be notified of event + /// completion. + pub fn new( + fd: RawFd, + offs: off_t, + buf: &'a [u8], + prio: i32, + sigev_notify: SigevNotify, + ) -> Self { + let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); + aiocb.aiocb.0.aio_nbytes = buf.len(); + // casting an immutable buffer to a mutable pointer looks unsafe, + // but technically its only unsafe to dereference it, not to create + // it. Type Safety guarantees that we'll never pass aiocb to + // aio_read or aio_readv. + aiocb.aiocb.0.aio_buf = buf.as_ptr() as *mut c_void; + aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITE; + aiocb.aiocb.0.aio_offset = offs; + AioWrite { + aiocb, + _data: PhantomData, + _pin: PhantomPinned, } - let p = self.list.as_ptr(); - Errno::result(unsafe { - libc::lio_listio(mode as i32, p, self.list.len() as i32, sigevp) - }).map(drop) } - /// Collect final status for an individual `AioCb` submitted as part of an - /// `LioCb`. - /// - /// This is just like [`AioCb::aio_return`], except it takes into account - /// operations that were restarted by [`LioCb::listio_resubmit`] - /// - /// [`AioCb::aio_return`]: struct.AioCb.html#method.aio_return - /// [`LioCb::listio_resubmit`]: #method.listio_resubmit - pub fn aio_return(&mut self, i: usize) -> Result { - if i >= self.results.len() || self.results[i].is_none() { - self.aiocbs[i].aio_return_unpinned() - } else { - self.results[i].unwrap() - } + /// Returns the file offset of the operation. + pub fn offset(&self) -> off_t { + self.aiocb.aiocb.0.aio_offset } +} - /// Retrieve error status of an individual `AioCb` submitted as part of an - /// `LioCb`. - /// - /// This is just like [`AioCb::error`], except it takes into account - /// operations that were restarted by [`LioCb::listio_resubmit`] - /// - /// [`AioCb::error`]: struct.AioCb.html#method.error - /// [`LioCb::listio_resubmit`]: #method.listio_resubmit - pub fn error(&mut self, i: usize) -> Result<()> { - if i >= self.results.len() || self.results[i].is_none() { - self.aiocbs[i].error_unpinned() - } else { - Ok(()) - } +impl<'a> Aio for AioWrite<'a> { + type Output = usize; + + aio_methods!(aio_write); +} + +impl<'a> AsMut for AioWrite<'a> { + fn as_mut(&mut self) -> &mut libc::aiocb { + &mut self.aiocb.aiocb.0 } } -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -impl<'a> Debug for LioCb<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("LioCb") - .field("aiocbs", &self.aiocbs) - .finish() +impl<'a> AsRef for AioWrite<'a> { + fn as_ref(&self) -> &libc::aiocb { + &self.aiocb.aiocb.0 } } -/// Used to construct `LioCb` -// This must be a separate class from LioCb due to pinning constraints. LioCb -// must use a boxed slice of AioCbs so they will have stable storage, but -// LioCbBuilder must use a Vec to make construction possible when the final size -// is unknown. -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -#[cfg_attr(docsrs, doc(cfg(all())))] +/// Asynchronously writes from a scatter/gather list of buffers to a file descriptor. +/// +/// # References +/// +/// [aio_writev](https://www.freebsd.org/cgi/man.cgi?query=aio_writev) +/// +/// # Examples +/// +#[cfg_attr(fbsd14, doc = " ```")] +#[cfg_attr(not(fbsd14), doc = " ```no_run")] +/// # use nix::errno::Errno; +/// # use nix::Error; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use std::{thread, time}; +/// # use std::io::IoSlice; +/// # use std::os::unix::io::AsRawFd; +/// # use tempfile::tempfile; +/// const wbuf0: &[u8] = b"abcdef"; +/// const wbuf1: &[u8] = b"123456"; +/// let len = wbuf0.len() + wbuf1.len(); +/// let wbufs = [IoSlice::new(wbuf0), IoSlice::new(wbuf1)]; +/// let mut f = tempfile().unwrap(); +/// let mut aiow = Box::pin( +/// AioWritev::new( +/// f.as_raw_fd(), +/// 2, //offset +/// &wbufs, +/// 0, //priority +/// SigevNotify::SigevNone +/// ) +/// ); +/// aiow.as_mut().submit().unwrap(); +/// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// assert_eq!(aiow.as_mut().aio_return().unwrap(), len); +/// ``` +#[cfg(target_os = "freebsd")] #[derive(Debug)] -pub struct LioCbBuilder<'a> { - /// A collection of [`AioCb`]s. - /// - /// [`AioCb`]: struct.AioCb.html - pub aiocbs: Vec>, +#[repr(transparent)] +pub struct AioWritev<'a> { + aiocb: AioCb, + _data: PhantomData<&'a [&'a [u8]]>, + _pin: PhantomPinned, } -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -#[cfg_attr(docsrs, doc(cfg(all())))] -impl<'a> LioCbBuilder<'a> { - /// Initialize an empty `LioCb` - pub fn with_capacity(capacity: usize) -> LioCbBuilder<'a> { - LioCbBuilder { - aiocbs: Vec::with_capacity(capacity), - } +#[cfg(target_os = "freebsd")] +impl<'a> AioWritev<'a> { + unsafe_pinned!(aiocb: AioCb); + + /// Returns the number of buffers the operation will read into. + pub fn iovlen(&self) -> usize { + self.aiocb.aiocb.0.aio_nbytes } - /// Add a new operation on an immutable slice to the [`LioCb`] under - /// construction. + /// Construct a new `AioWritev`. /// - /// Arguments are the same as for [`AioCb::from_slice`] + /// # Arguments /// - /// [`LioCb`]: struct.LioCb.html - /// [`AioCb::from_slice`]: struct.AioCb.html#method.from_slice - #[must_use] - pub fn emplace_slice(mut self, fd: RawFd, offs: off_t, buf: &'a [u8], - prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> Self - { - self.aiocbs.push(AioCb::from_slice_unpinned(fd, offs, buf, prio, - sigev_notify, opcode)); - self + /// * `fd`: File descriptor to write to + /// * `offs`: File offset + /// * `bufs`: A scatter/gather list of memory buffers. They must + /// outlive the `AioWritev`. + /// * `prio`: If POSIX Prioritized IO is supported, then the + /// operation will be prioritized at the process's + /// priority level minus `prio` + /// * `sigev_notify`: Determines how you will be notified of event + /// completion. + pub fn new( + fd: RawFd, + offs: off_t, + bufs: &[IoSlice<'a>], + prio: i32, + sigev_notify: SigevNotify, + ) -> Self { + let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); + // In vectored mode, aio_nbytes stores the length of the iovec array, + // not the byte count. + aiocb.aiocb.0.aio_nbytes = bufs.len(); + // casting an immutable buffer to a mutable pointer looks unsafe, + // but technically its only unsafe to dereference it, not to create + // it. Type Safety guarantees that we'll never pass aiocb to + // aio_read or aio_readv. + aiocb.aiocb.0.aio_buf = bufs.as_ptr() as *mut c_void; + aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITEV; + aiocb.aiocb.0.aio_offset = offs; + AioWritev { + aiocb, + _data: PhantomData, + _pin: PhantomPinned, + } } - /// Add a new operation on a mutable slice to the [`LioCb`] under - /// construction. - /// - /// Arguments are the same as for [`AioCb::from_mut_slice`] - /// - /// [`LioCb`]: struct.LioCb.html - /// [`AioCb::from_mut_slice`]: struct.AioCb.html#method.from_mut_slice - #[must_use] - pub fn emplace_mut_slice(mut self, fd: RawFd, offs: off_t, - buf: &'a mut [u8], prio: libc::c_int, - sigev_notify: SigevNotify, opcode: LioOpcode) - -> Self - { - self.aiocbs.push(AioCb::from_mut_slice_unpinned(fd, offs, buf, prio, - sigev_notify, opcode)); - self + /// Returns the file offset of the operation. + pub fn offset(&self) -> off_t { + self.aiocb.aiocb.0.aio_offset } +} - /// Finalize this [`LioCb`]. - /// - /// Afterwards it will be possible to issue the operations with - /// [`LioCb::listio`]. Conversely, it will no longer be possible to add new - /// operations with [`LioCbBuilder::emplace_slice`] or - /// [`LioCbBuilder::emplace_mut_slice`]. - /// - /// [`LioCb::listio`]: struct.LioCb.html#method.listio - /// [`LioCb::from_mut_slice`]: struct.LioCb.html#method.from_mut_slice - /// [`LioCb::from_slice`]: struct.LioCb.html#method.from_slice - pub fn finish(self) -> LioCb<'a> { - let len = self.aiocbs.len(); - LioCb { - aiocbs: self.aiocbs.into(), - list: Vec::with_capacity(len), - results: Vec::with_capacity(len) - } +#[cfg(target_os = "freebsd")] +impl<'a> Aio for AioWritev<'a> { + type Output = usize; + + aio_methods!(aio_writev); +} + +#[cfg(target_os = "freebsd")] +impl<'a> AsMut for AioWritev<'a> { + fn as_mut(&mut self) -> &mut libc::aiocb { + &mut self.aiocb.aiocb.0 + } +} + +#[cfg(target_os = "freebsd")] +impl<'a> AsRef for AioWritev<'a> { + fn as_ref(&self) -> &libc::aiocb { + &self.aiocb.aiocb.0 } } -#[cfg(not(any(target_os = "ios", target_os = "macos")))] +/// Cancels outstanding AIO requests for a given file descriptor. +/// +/// # Examples +/// +/// Issue an aio operation, then cancel all outstanding operations on that file +/// descriptor. +/// +/// ``` +/// # use nix::errno::Errno; +/// # use nix::Error; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use std::{thread, time}; +/// # use std::io::Write; +/// # use std::os::unix::io::AsRawFd; +/// # use tempfile::tempfile; +/// let wbuf = b"CDEF"; +/// let mut f = tempfile().unwrap(); +/// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), +/// 2, //offset +/// &wbuf[..], +/// 0, //priority +/// SigevNotify::SigevNone)); +/// aiocb.as_mut().submit().unwrap(); +/// let cs = aio_cancel_all(f.as_raw_fd()).unwrap(); +/// if cs == AioCancelStat::AioNotCanceled { +/// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// } +/// // Must call `aio_return`, but ignore the result +/// let _ = aiocb.as_mut().aio_return(); +/// ``` +/// +/// # References +/// +/// [`aio_cancel`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) +pub fn aio_cancel_all(fd: RawFd) -> Result { + match unsafe { libc::aio_cancel(fd, ptr::null_mut()) } { + libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), + libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), + libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), + -1 => Err(Errno::last()), + _ => panic!("unknown aio_cancel return value"), + } +} + +/// Suspends the calling process until at least one of the specified operations +/// have completed, a signal is delivered, or the timeout has passed. +/// +/// If `timeout` is `None`, `aio_suspend` will block indefinitely. +/// +/// # Examples +/// +/// Use `aio_suspend` to block until an aio operation completes. +/// +/// ``` +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use std::os::unix::io::AsRawFd; +/// # use tempfile::tempfile; +/// const WBUF: &[u8] = b"abcdef123456"; +/// let mut f = tempfile().unwrap(); +/// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), +/// 2, //offset +/// WBUF, +/// 0, //priority +/// SigevNotify::SigevNone)); +/// aiocb.as_mut().submit().unwrap(); +/// aio_suspend(&[&*aiocb], None).expect("aio_suspend failed"); +/// assert_eq!(aiocb.as_mut().aio_return().unwrap() as usize, WBUF.len()); +/// ``` +/// # References +/// +/// [`aio_suspend`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html) +pub fn aio_suspend( + list: &[&dyn AsRef], + timeout: Option, +) -> Result<()> { + let p = list as *const [&dyn AsRef] + as *const [*const libc::aiocb] + as *const *const libc::aiocb; + let timep = match timeout { + None => ptr::null::(), + Some(x) => x.as_ref() as *const libc::timespec, + }; + Errno::result(unsafe { libc::aio_suspend(p, list.len() as i32, timep) }) + .map(drop) +} + +/// Submits multiple asynchronous I/O requests with a single system call. +/// +/// They are not guaranteed to complete atomically, and the order in which the +/// requests are carried out is not specified. Reads, and writes may be freely +/// mixed. +/// +/// # Examples +/// +/// Use `lio_listio` to submit an aio operation and wait for its completion. In +/// this case, there is no need to use aio_suspend to wait or `error` to poll. +/// This mode is useful for otherwise-synchronous programs that want to execute +/// a handful of I/O operations in parallel. +/// ``` +/// # use std::os::unix::io::AsRawFd; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use tempfile::tempfile; +/// const WBUF: &[u8] = b"abcdef123456"; +/// let mut f = tempfile().unwrap(); +/// let mut aiow = Box::pin(AioWrite::new( +/// f.as_raw_fd(), +/// 2, // offset +/// WBUF, +/// 0, // priority +/// SigevNotify::SigevNone +/// )); +/// lio_listio(LioMode::LIO_WAIT, &mut[aiow.as_mut()], SigevNotify::SigevNone) +/// .unwrap(); +/// // At this point, we are guaranteed that aiow is complete. +/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); +/// ``` +/// +/// Use `lio_listio` to submit multiple asynchronous operations with a single +/// syscall, but receive notification individually. This is an efficient +/// technique for reducing overall context-switch overhead, especially when +/// combined with kqueue. +/// ``` +/// # use std::os::unix::io::AsRawFd; +/// # use std::thread; +/// # use std::time; +/// # use nix::errno::Errno; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::SigevNotify; +/// # use tempfile::tempfile; +/// const WBUF: &[u8] = b"abcdef123456"; +/// let mut f = tempfile().unwrap(); +/// let mut aiow = Box::pin(AioWrite::new( +/// f.as_raw_fd(), +/// 2, // offset +/// WBUF, +/// 0, // priority +/// SigevNotify::SigevNone +/// )); +/// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], SigevNotify::SigevNone) +/// .unwrap(); +/// // We must wait for the completion of each individual operation +/// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); +/// ``` +/// +/// Use `lio_listio` to submit multiple operations, and receive notification +/// only when all of them are complete. This can be useful when there is some +/// logical relationship between the operations. But beware! Errors or system +/// resource limitations may cause `lio_listio` to return `EIO`, `EAGAIN`, or +/// `EINTR`, in which case some but not all operations may have been submitted. +/// In that case, you must check the status of each individual operation, and +/// possibly resubmit some. +/// ``` +/// # use libc::c_int; +/// # use std::os::unix::io::AsRawFd; +/// # use std::sync::atomic::{AtomicBool, Ordering}; +/// # use std::thread; +/// # use std::time; +/// # use lazy_static::lazy_static; +/// # use nix::errno::Errno; +/// # use nix::sys::aio::*; +/// # use nix::sys::signal::*; +/// # use tempfile::tempfile; +/// lazy_static! { +/// pub static ref SIGNALED: AtomicBool = AtomicBool::new(false); +/// } +/// +/// extern fn sigfunc(_: c_int) { +/// SIGNALED.store(true, Ordering::Relaxed); +/// } +/// let sa = SigAction::new(SigHandler::Handler(sigfunc), +/// SaFlags::SA_RESETHAND, +/// SigSet::empty()); +/// SIGNALED.store(false, Ordering::Relaxed); +/// unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); +/// +/// const WBUF: &[u8] = b"abcdef123456"; +/// let mut f = tempfile().unwrap(); +/// let mut aiow = Box::pin(AioWrite::new( +/// f.as_raw_fd(), +/// 2, // offset +/// WBUF, +/// 0, // priority +/// SigevNotify::SigevNone +/// )); +/// let sev = SigevNotify::SigevSignal { signal: Signal::SIGUSR2, si_value: 0 }; +/// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], sev).unwrap(); +/// while !SIGNALED.load(Ordering::Relaxed) { +/// thread::sleep(time::Duration::from_millis(10)); +/// } +/// // At this point, since `lio_listio` returned success and delivered its +/// // notification, we know that all operations are complete. +/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); +/// ``` +pub fn lio_listio( + mode: LioMode, + list: &mut [Pin<&mut dyn AsMut>], + sigev_notify: SigevNotify, +) -> Result<()> { + let p = list as *mut [Pin<&mut dyn AsMut>] + as *mut [*mut libc::aiocb] + as *mut *mut libc::aiocb; + let sigev = SigEvent::new(sigev_notify); + let sigevp = &mut sigev.sigevent() as *mut libc::sigevent; + Errno::result(unsafe { + libc::lio_listio(mode as i32, p, list.len() as i32, sigevp) + }) + .map(drop) +} + #[cfg(test)] mod t { use super::*; - // It's important that `LioCb` be `UnPin`. The tokio-file crate relies on - // it. + /// aio_suspend relies on casting Rust Aio* struct pointers to libc::aiocb + /// pointers. This test ensures that such casts are valid. #[test] - fn liocb_is_unpin() { - use assert_impl::assert_impl; + fn casting() { + let sev = SigevNotify::SigevNone; + let aiof = AioFsync::new(666, AioFsyncMode::O_SYNC, 0, sev); + assert_eq!( + aiof.as_ref() as *const libc::aiocb, + &aiof as *const AioFsync as *const libc::aiocb + ); + + let mut rbuf = []; + let aior = AioRead::new(666, 0, &mut rbuf, 0, sev); + assert_eq!( + aior.as_ref() as *const libc::aiocb, + &aior as *const AioRead as *const libc::aiocb + ); + + let wbuf = []; + let aiow = AioWrite::new(666, 0, &wbuf, 0, sev); + assert_eq!( + aiow.as_ref() as *const libc::aiocb, + &aiow as *const AioWrite as *const libc::aiocb + ); + } + + #[cfg(target_os = "freebsd")] + #[test] + fn casting_vectored() { + let sev = SigevNotify::SigevNone; + + let mut rbuf = []; + let mut rbufs = [IoSliceMut::new(&mut rbuf)]; + let aiorv = AioReadv::new(666, 0, &mut rbufs[..], 0, sev); + assert_eq!( + aiorv.as_ref() as *const libc::aiocb, + &aiorv as *const AioReadv as *const libc::aiocb + ); - assert_impl!(Unpin: LioCb); + let wbuf = []; + let wbufs = [IoSlice::new(&wbuf)]; + let aiowv = AioWritev::new(666, 0, &wbufs, 0, sev); + assert_eq!( + aiowv.as_ref() as *const libc::aiocb, + &aiowv as *const AioWritev as *const libc::aiocb + ); } } diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index 80cd053f8d..ca35b5f88c 100644 --- a/test/sys/test_aio.rs +++ b/test/sys/test_aio.rs @@ -1,415 +1,525 @@ -use libc::{c_int, c_void}; -use nix::Result; -use nix::errno::*; -use nix::sys::aio::*; -use nix::sys::signal::{SaFlags, SigAction, sigaction, SigevNotify, SigHandler, Signal, SigSet}; -use nix::sys::time::{TimeSpec, TimeValLike}; -use std::io::{Write, Read, Seek, SeekFrom}; -use std::ops::Deref; -use std::os::unix::io::AsRawFd; -use std::pin::Pin; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::{thread, time}; +use std::{ + io::{Read, Seek, SeekFrom, Write}, + ops::Deref, + os::unix::io::AsRawFd, + pin::Pin, + sync::atomic::{AtomicBool, Ordering}, + thread, + time, +}; + +use libc::c_int; +use nix::{ + errno::*, + sys::{ + aio::*, + signal::{ + sigaction, + SaFlags, + SigAction, + SigHandler, + SigSet, + SigevNotify, + Signal, + }, + time::{TimeSpec, TimeValLike}, + }, +}; use tempfile::tempfile; -// Helper that polls an AioCb for completion or error -fn poll_aio(aiocb: &mut Pin>) -> Result<()> { - loop { - let err = aiocb.error(); - if err != Err(Errno::EINPROGRESS) { return err; }; - thread::sleep(time::Duration::from_millis(10)); - } +lazy_static! { + pub static ref SIGNALED: AtomicBool = AtomicBool::new(false); } -// Helper that polls a component of an LioCb for completion or error -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -fn poll_lio(liocb: &mut LioCb, i: usize) -> Result<()> { - loop { - let err = liocb.error(i); - if err != Err(Errno::EINPROGRESS) { return err; }; - thread::sleep(time::Duration::from_millis(10)); - } +extern "C" fn sigfunc(_: c_int) { + SIGNALED.store(true, Ordering::Relaxed); } -#[test] -fn test_accessors() { - let mut rbuf = vec![0; 4]; - let aiocb = AioCb::from_mut_slice( 1001, - 2, //offset - &mut rbuf, - 42, //priority - SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, - si_value: 99 - }, - LioOpcode::LIO_NOP); - assert_eq!(1001, aiocb.fd()); - assert_eq!(Some(LioOpcode::LIO_NOP), aiocb.lio_opcode()); - assert_eq!(4, aiocb.nbytes()); - assert_eq!(2, aiocb.offset()); - assert_eq!(42, aiocb.priority()); - let sev = aiocb.sigevent().sigevent(); - assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); - assert_eq!(99, sev.sigev_value.sival_ptr as i64); +// Helper that polls an AioCb for completion or error +macro_rules! poll_aio { + ($aiocb: expr) => { + loop { + let err = $aiocb.as_mut().error(); + if err != Err(Errno::EINPROGRESS) { + break err; + }; + thread::sleep(time::Duration::from_millis(10)); + } + }; } -// Tests AioCb.cancel. We aren't trying to test the OS's implementation, only -// our bindings. So it's sufficient to check that AioCb.cancel returned any -// AioCancelStat value. -#[test] -#[cfg_attr(target_env = "musl", ignore)] -fn test_cancel() { - let wbuf: &[u8] = b"CDEF"; - - let f = tempfile().unwrap(); - let mut aiocb = AioCb::from_slice( f.as_raw_fd(), - 0, //offset - wbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_NOP); - aiocb.write().unwrap(); - let err = aiocb.error(); - assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); +mod aio_fsync { + use super::*; + + #[test] + fn test_accessors() { + let aiocb = AioFsync::new( + 1001, + AioFsyncMode::O_SYNC, + 42, + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 99, + }, + ); + assert_eq!(1001, aiocb.fd()); + assert_eq!(AioFsyncMode::O_SYNC, aiocb.mode()); + assert_eq!(42, aiocb.priority()); + let sev = aiocb.sigevent().sigevent(); + assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); + assert_eq!(99, sev.sigev_value.sival_ptr as i64); + } - let cancelstat = aiocb.cancel(); - assert!(cancelstat.is_ok()); + /// `AioFsync::submit` should not modify the `AioCb` object if + /// `libc::aio_fsync` returns an error + // Skip on Linux, because Linux's AIO implementation can't detect errors + // synchronously + #[test] + #[cfg(any(target_os = "freebsd", target_os = "macos"))] + fn error() { + use std::mem; + + const INITIAL: &[u8] = b"abcdef123456"; + // Create an invalid AioFsyncMode + let mode = unsafe { mem::transmute(666) }; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let mut aiof = Box::pin(AioFsync::new( + f.as_raw_fd(), + mode, + 0, + SigevNotify::SigevNone, + )); + let err = aiof.as_mut().submit(); + assert!(err.is_err()); + } - // Wait for aiocb to complete, but don't care whether it succeeded - let _ = poll_aio(&mut aiocb); - let _ = aiocb.aio_return(); + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn ok() { + const INITIAL: &[u8] = b"abcdef123456"; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let fd = f.as_raw_fd(); + let mut aiof = Box::pin(AioFsync::new( + fd, + AioFsyncMode::O_SYNC, + 0, + SigevNotify::SigevNone, + )); + let err = aiof.as_mut().submit(); + assert!(err.is_ok()); + poll_aio!(&mut aiof).unwrap(); + aiof.as_mut().aio_return().unwrap(); + } } -// Tests using aio_cancel_all for all outstanding IOs. -#[test] -#[cfg_attr(target_env = "musl", ignore)] -fn test_aio_cancel_all() { - let wbuf: &[u8] = b"CDEF"; - - let f = tempfile().unwrap(); - let mut aiocb = AioCb::from_slice(f.as_raw_fd(), - 0, //offset - wbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_NOP); - aiocb.write().unwrap(); - let err = aiocb.error(); - assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); +mod aio_read { + use super::*; + + #[test] + fn test_accessors() { + let mut rbuf = vec![0; 4]; + let aiocb = AioRead::new( + 1001, + 2, //offset + &mut rbuf, + 42, //priority + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 99, + }, + ); + assert_eq!(1001, aiocb.fd()); + assert_eq!(4, aiocb.nbytes()); + assert_eq!(2, aiocb.offset()); + assert_eq!(42, aiocb.priority()); + let sev = aiocb.sigevent().sigevent(); + assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); + assert_eq!(99, sev.sigev_value.sival_ptr as i64); + } - let cancelstat = aio_cancel_all(f.as_raw_fd()); - assert!(cancelstat.is_ok()); + // Tests AioWrite.cancel. We aren't trying to test the OS's implementation, + // only our bindings. So it's sufficient to check that cancel + // returned any AioCancelStat value. + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn cancel() { + const INITIAL: &[u8] = b"abcdef123456"; + let mut rbuf = vec![0; 4]; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let fd = f.as_raw_fd(); + let mut aior = + Box::pin(AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone)); + aior.as_mut().submit().unwrap(); + + let cancelstat = aior.as_mut().cancel(); + assert!(cancelstat.is_ok()); + + // Wait for aiow to complete, but don't care whether it succeeded + let _ = poll_aio!(&mut aior); + let _ = aior.as_mut().aio_return(); + } - // Wait for aiocb to complete, but don't care whether it succeeded - let _ = poll_aio(&mut aiocb); - let _ = aiocb.aio_return(); -} + /// `AioRead::submit` should not modify the `AioCb` object if + /// `libc::aio_read` returns an error + // Skip on Linux, because Linux's AIO implementation can't detect errors + // synchronously + #[test] + #[cfg(any(target_os = "freebsd", target_os = "macos"))] + fn error() { + const INITIAL: &[u8] = b"abcdef123456"; + let mut rbuf = vec![0; 4]; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let mut aior = Box::pin(AioRead::new( + f.as_raw_fd(), + -1, //an invalid offset + &mut rbuf, + 0, //priority + SigevNotify::SigevNone, + )); + assert!(aior.as_mut().submit().is_err()); + } -#[test] -#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] -fn test_fsync() { - const INITIAL: &[u8] = b"abcdef123456"; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - let mut aiocb = AioCb::from_fd( f.as_raw_fd(), - 0, //priority - SigevNotify::SigevNone); - let err = aiocb.fsync(AioFsyncMode::O_SYNC); - assert!(err.is_ok()); - poll_aio(&mut aiocb).unwrap(); - aiocb.aio_return().unwrap(); -} + // Test a simple aio operation with no completion notification. We must + // poll for completion + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn ok() { + const INITIAL: &[u8] = b"abcdef123456"; + let mut rbuf = vec![0; 4]; + const EXPECT: &[u8] = b"cdef"; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + { + let fd = f.as_raw_fd(); + let mut aior = Box::pin(AioRead::new( + fd, + 2, + &mut rbuf, + 0, + SigevNotify::SigevNone, + )); + aior.as_mut().submit().unwrap(); -/// `AioCb::fsync` should not modify the `AioCb` object if `libc::aio_fsync` returns -/// an error -// Skip on Linux, because Linux's AIO implementation can't detect errors -// synchronously -#[test] -#[cfg(any(target_os = "freebsd", target_os = "macos"))] -fn test_fsync_error() { - use std::mem; + let err = poll_aio!(&mut aior); + assert_eq!(err, Ok(())); + assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len()); + } + assert_eq!(EXPECT, rbuf.deref().deref()); + } - const INITIAL: &[u8] = b"abcdef123456"; - // Create an invalid AioFsyncMode - let mode = unsafe { mem::transmute(666) }; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - let mut aiocb = AioCb::from_fd( f.as_raw_fd(), - 0, //priority - SigevNotify::SigevNone); - let err = aiocb.fsync(mode); - assert!(err.is_err()); + // Like ok, but allocates the structure on the stack. + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn on_stack() { + const INITIAL: &[u8] = b"abcdef123456"; + let mut rbuf = vec![0; 4]; + const EXPECT: &[u8] = b"cdef"; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + { + let fd = f.as_raw_fd(); + let mut aior = + AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone); + let mut aior = unsafe { Pin::new_unchecked(&mut aior) }; + aior.as_mut().submit().unwrap(); + + let err = poll_aio!(&mut aior); + assert_eq!(err, Ok(())); + assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len()); + } + assert_eq!(EXPECT, rbuf.deref().deref()); + } } -#[test] -// On Cirrus on Linux, this test fails due to a glibc bug. -// https://github.com/nix-rust/nix/issues/1099 -#[cfg_attr(target_os = "linux", ignore)] -// On Cirrus, aio_suspend is failing with EINVAL -// https://github.com/nix-rust/nix/issues/1361 -#[cfg_attr(target_os = "macos", ignore)] -fn test_aio_suspend() { - const INITIAL: &[u8] = b"abcdef123456"; - const WBUF: &[u8] = b"CDEFG"; - let timeout = TimeSpec::seconds(10); - let mut rbuf = vec![0; 4]; - let rlen = rbuf.len(); - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); +#[cfg(target_os = "freebsd")] +#[cfg(fbsd14)] +mod aio_readv { + use std::io::IoSliceMut; + + use super::*; + + #[test] + fn test_accessors() { + let mut rbuf0 = vec![0; 4]; + let mut rbuf1 = vec![0; 8]; + let mut rbufs = + [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)]; + let aiocb = AioReadv::new( + 1001, + 2, //offset + &mut rbufs, + 42, //priority + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 99, + }, + ); + assert_eq!(1001, aiocb.fd()); + assert_eq!(2, aiocb.iovlen()); + assert_eq!(2, aiocb.offset()); + assert_eq!(42, aiocb.priority()); + let sev = aiocb.sigevent().sigevent(); + assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); + assert_eq!(99, sev.sigev_value.sival_ptr as i64); + } - let mut wcb = AioCb::from_slice( f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_WRITE); - - let mut rcb = AioCb::from_mut_slice( f.as_raw_fd(), - 8, //offset - &mut rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_READ); - wcb.write().unwrap(); - rcb.read().unwrap(); - loop { + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn ok() { + const INITIAL: &[u8] = b"abcdef123456"; + let mut rbuf0 = vec![0; 4]; + let mut rbuf1 = vec![0; 2]; + let mut rbufs = + [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)]; + const EXPECT0: &[u8] = b"cdef"; + const EXPECT1: &[u8] = b"12"; + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); { - let cbbuf = [wcb.as_ref(), rcb.as_ref()]; - let r = aio_suspend(&cbbuf[..], Some(timeout)); - match r { - Err(Errno::EINTR) => continue, - Err(e) => panic!("aio_suspend returned {:?}", e), - Ok(_) => () - }; - } - if rcb.error() != Err(Errno::EINPROGRESS) && - wcb.error() != Err(Errno::EINPROGRESS) { - break + let fd = f.as_raw_fd(); + let mut aior = Box::pin(AioReadv::new( + fd, + 2, + &mut rbufs, + 0, + SigevNotify::SigevNone, + )); + aior.as_mut().submit().unwrap(); + + let err = poll_aio!(&mut aior); + assert_eq!(err, Ok(())); + assert_eq!( + aior.as_mut().aio_return().unwrap(), + EXPECT0.len() + EXPECT1.len() + ); } + assert_eq!(&EXPECT0, &rbuf0); + assert_eq!(&EXPECT1, &rbuf1); } - - assert_eq!(wcb.aio_return().unwrap() as usize, WBUF.len()); - assert_eq!(rcb.aio_return().unwrap() as usize, rlen); } -// Test a simple aio operation with no completion notification. We must poll -// for completion -#[test] -#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] -fn test_read() { - const INITIAL: &[u8] = b"abcdef123456"; - let mut rbuf = vec![0; 4]; - const EXPECT: &[u8] = b"cdef"; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - { - let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(), - 2, //offset - &mut rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_NOP); - aiocb.read().unwrap(); - - let err = poll_aio(&mut aiocb); - assert_eq!(err, Ok(())); - assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); +mod aio_write { + use super::*; + + #[test] + fn test_accessors() { + let wbuf = vec![0; 4]; + let aiocb = AioWrite::new( + 1001, + 2, //offset + &wbuf, + 42, //priority + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 99, + }, + ); + assert_eq!(1001, aiocb.fd()); + assert_eq!(4, aiocb.nbytes()); + assert_eq!(2, aiocb.offset()); + assert_eq!(42, aiocb.priority()); + let sev = aiocb.sigevent().sigevent(); + assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); + assert_eq!(99, sev.sigev_value.sival_ptr as i64); } - assert_eq!(EXPECT, rbuf.deref().deref()); -} + // Tests AioWrite.cancel. We aren't trying to test the OS's implementation, + // only our bindings. So it's sufficient to check that cancel + // returned any AioCancelStat value. + #[test] + #[cfg_attr(target_env = "musl", ignore)] + fn cancel() { + let wbuf: &[u8] = b"CDEF"; -/// `AioCb::read` should not modify the `AioCb` object if `libc::aio_read` -/// returns an error -// Skip on Linux, because Linux's AIO implementation can't detect errors -// synchronously -#[test] -#[cfg(any(target_os = "freebsd", target_os = "macos"))] -fn test_read_error() { - const INITIAL: &[u8] = b"abcdef123456"; - let mut rbuf = vec![0; 4]; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(), - -1, //an invalid offset - &mut rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_NOP); - assert!(aiocb.read().is_err()); -} + let f = tempfile().unwrap(); + let mut aiow = Box::pin(AioWrite::new( + f.as_raw_fd(), + 0, + wbuf, + 0, + SigevNotify::SigevNone, + )); + aiow.as_mut().submit().unwrap(); + let err = aiow.as_mut().error(); + assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); -// Tests from_mut_slice -#[test] -#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] -fn test_read_into_mut_slice() { - const INITIAL: &[u8] = b"abcdef123456"; - let mut rbuf = vec![0; 4]; - const EXPECT: &[u8] = b"cdef"; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - { - let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(), - 2, //offset - &mut rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_NOP); - aiocb.read().unwrap(); - - let err = poll_aio(&mut aiocb); - assert_eq!(err, Ok(())); - assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); + let cancelstat = aiow.as_mut().cancel(); + assert!(cancelstat.is_ok()); + + // Wait for aiow to complete, but don't care whether it succeeded + let _ = poll_aio!(&mut aiow); + let _ = aiow.as_mut().aio_return(); } - assert_eq!(rbuf, EXPECT); -} + // Test a simple aio operation with no completion notification. We must + // poll for completion. + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn ok() { + const INITIAL: &[u8] = b"abcdef123456"; + let wbuf = "CDEF".to_string().into_bytes(); + let mut rbuf = Vec::new(); + const EXPECT: &[u8] = b"abCDEF123456"; + + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let mut aiow = Box::pin(AioWrite::new( + f.as_raw_fd(), + 2, + &wbuf, + 0, + SigevNotify::SigevNone, + )); + aiow.as_mut().submit().unwrap(); -// Tests from_ptr -#[test] -#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] -fn test_read_into_pointer() { - const INITIAL: &[u8] = b"abcdef123456"; - let mut rbuf = vec![0; 4]; - const EXPECT: &[u8] = b"cdef"; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - { - // Safety: ok because rbuf lives until after poll_aio - let mut aiocb = unsafe { - AioCb::from_mut_ptr( f.as_raw_fd(), - 2, //offset - rbuf.as_mut_ptr() as *mut c_void, - rbuf.len(), - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_NOP) - }; - aiocb.read().unwrap(); - - let err = poll_aio(&mut aiocb); + let err = poll_aio!(&mut aiow); assert_eq!(err, Ok(())); - assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); - } + assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len()); - assert_eq!(rbuf, EXPECT); -} - -// Test reading into an immutable buffer. It should fail -// FIXME: This test fails to panic on Linux/musl -#[test] -#[should_panic(expected = "Can't read into an immutable buffer")] -#[cfg_attr(target_env = "musl", ignore)] -fn test_read_immutable_buffer() { - let rbuf: &[u8] = b"CDEF"; - let f = tempfile().unwrap(); - let mut aiocb = AioCb::from_slice( f.as_raw_fd(), - 2, //offset - rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_NOP); - aiocb.read().unwrap(); -} + f.seek(SeekFrom::Start(0)).unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); + assert_eq!(len, EXPECT.len()); + assert_eq!(rbuf, EXPECT); + } + // Like ok, but allocates the structure on the stack. + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn on_stack() { + const INITIAL: &[u8] = b"abcdef123456"; + let wbuf = "CDEF".to_string().into_bytes(); + let mut rbuf = Vec::new(); + const EXPECT: &[u8] = b"abCDEF123456"; + + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let mut aiow = AioWrite::new( + f.as_raw_fd(), + 2, //offset + &wbuf, + 0, //priority + SigevNotify::SigevNone, + ); + let mut aiow = unsafe { Pin::new_unchecked(&mut aiow) }; + aiow.as_mut().submit().unwrap(); -// Test a simple aio operation with no completion notification. We must poll -// for completion. Unlike test_aio_read, this test uses AioCb::from_slice -#[test] -#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] -fn test_write() { - const INITIAL: &[u8] = b"abcdef123456"; - let wbuf = "CDEF".to_string().into_bytes(); - let mut rbuf = Vec::new(); - const EXPECT: &[u8] = b"abCDEF123456"; + let err = poll_aio!(&mut aiow); + assert_eq!(err, Ok(())); + assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len()); - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - let mut aiocb = AioCb::from_slice( f.as_raw_fd(), - 2, //offset - &wbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_NOP); - aiocb.write().unwrap(); - - let err = poll_aio(&mut aiocb); - assert_eq!(err, Ok(())); - assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len()); + f.seek(SeekFrom::Start(0)).unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); + assert_eq!(len, EXPECT.len()); + assert_eq!(rbuf, EXPECT); + } - f.seek(SeekFrom::Start(0)).unwrap(); - let len = f.read_to_end(&mut rbuf).unwrap(); - assert_eq!(len, EXPECT.len()); - assert_eq!(rbuf, EXPECT); + /// `AioWrite::write` should not modify the `AioCb` object if + /// `libc::aio_write` returns an error. + // Skip on Linux, because Linux's AIO implementation can't detect errors + // synchronously + #[test] + #[cfg(any(target_os = "freebsd", target_os = "macos"))] + fn error() { + let wbuf = "CDEF".to_string().into_bytes(); + let mut aiow = Box::pin(AioWrite::new( + 666, // An invalid file descriptor + 0, //offset + &wbuf, + 0, //priority + SigevNotify::SigevNone, + )); + assert!(aiow.as_mut().submit().is_err()); + // Dropping the AioWrite at this point should not panic + } } -// Tests `AioCb::from_ptr` -#[test] -#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] -fn test_write_from_pointer() { - const INITIAL: &[u8] = b"abcdef123456"; - let wbuf = "CDEF".to_string().into_bytes(); - let mut rbuf = Vec::new(); - const EXPECT: &[u8] = b"abCDEF123456"; - - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - // Safety: ok because aiocb outlives poll_aio - let mut aiocb = unsafe { - AioCb::from_ptr( f.as_raw_fd(), - 2, //offset - wbuf.as_ptr() as *const c_void, - wbuf.len(), - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_NOP) - }; - aiocb.write().unwrap(); - - let err = poll_aio(&mut aiocb); - assert_eq!(err, Ok(())); - assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len()); - - f.seek(SeekFrom::Start(0)).unwrap(); - let len = f.read_to_end(&mut rbuf).unwrap(); - assert_eq!(len, EXPECT.len()); - assert_eq!(rbuf, EXPECT); -} +#[cfg(target_os = "freebsd")] +#[cfg(fbsd14)] +mod aio_writev { + use std::io::IoSlice; + + use super::*; + + #[test] + fn test_accessors() { + let wbuf0 = vec![0; 4]; + let wbuf1 = vec![0; 8]; + let wbufs = [IoSlice::new(&wbuf0), IoSlice::new(&wbuf1)]; + let aiocb = AioWritev::new( + 1001, + 2, //offset + &wbufs, + 42, //priority + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 99, + }, + ); + assert_eq!(1001, aiocb.fd()); + assert_eq!(2, aiocb.iovlen()); + assert_eq!(2, aiocb.offset()); + assert_eq!(42, aiocb.priority()); + let sev = aiocb.sigevent().sigevent(); + assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo); + assert_eq!(99, sev.sigev_value.sival_ptr as i64); + } -/// `AioCb::write` should not modify the `AioCb` object if `libc::aio_write` -/// returns an error -// Skip on Linux, because Linux's AIO implementation can't detect errors -// synchronously -#[test] -#[cfg(any(target_os = "freebsd", target_os = "macos"))] -fn test_write_error() { - let wbuf = "CDEF".to_string().into_bytes(); - let mut aiocb = AioCb::from_slice( 666, // An invalid file descriptor - 0, //offset - &wbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_NOP); - assert!(aiocb.write().is_err()); -} + // Test a simple aio operation with no completion notification. We must + // poll for completion. + #[test] + #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] + fn ok() { + const INITIAL: &[u8] = b"abcdef123456"; + let wbuf0 = b"BC"; + let wbuf1 = b"DEF"; + let wbufs = [IoSlice::new(wbuf0), IoSlice::new(wbuf1)]; + let wlen = wbuf0.len() + wbuf1.len(); + let mut rbuf = Vec::new(); + const EXPECT: &[u8] = b"aBCDEF123456"; + + let mut f = tempfile().unwrap(); + f.write_all(INITIAL).unwrap(); + let mut aiow = Box::pin(AioWritev::new( + f.as_raw_fd(), + 1, + &wbufs, + 0, + SigevNotify::SigevNone, + )); + aiow.as_mut().submit().unwrap(); -lazy_static! { - pub static ref SIGNALED: AtomicBool = AtomicBool::new(false); -} + let err = poll_aio!(&mut aiow); + assert_eq!(err, Ok(())); + assert_eq!(aiow.as_mut().aio_return().unwrap(), wlen); -extern fn sigfunc(_: c_int) { - SIGNALED.store(true, Ordering::Relaxed); + f.seek(SeekFrom::Start(0)).unwrap(); + let len = f.read_to_end(&mut rbuf).unwrap(); + assert_eq!(len, EXPECT.len()); + assert_eq!(rbuf, EXPECT); + } } // Test an aio operation with completion delivered by a signal -// FIXME: This test is ignored on mips because of failures in qemu in CI #[test] -#[cfg_attr(any(all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", target_arch = "mips64"), ignore)] -fn test_write_sigev_signal() { +#[cfg_attr( + any( + all(target_env = "musl", target_arch = "x86_64"), + target_arch = "mips", + target_arch = "mips64" + ), + ignore +)] +fn sigev_signal() { let _m = crate::SIGNAL_MTX.lock(); - let sa = SigAction::new(SigHandler::Handler(sigfunc), - SaFlags::SA_RESETHAND, - SigSet::empty()); + let sa = SigAction::new( + SigHandler::Handler(sigfunc), + SaFlags::SA_RESETHAND, + SigSet::empty(), + ); SIGNALED.store(false, Ordering::Relaxed); unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); @@ -420,201 +530,107 @@ fn test_write_sigev_signal() { let mut f = tempfile().unwrap(); f.write_all(INITIAL).unwrap(); - let mut aiocb = AioCb::from_slice( f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, - si_value: 0 //TODO: validate in sigfunc - }, - LioOpcode::LIO_NOP); - aiocb.write().unwrap(); + let mut aiow = Box::pin(AioWrite::new( + f.as_raw_fd(), + 2, //offset + WBUF, + 0, //priority + SigevNotify::SigevSignal { + signal: Signal::SIGUSR2, + si_value: 0, //TODO: validate in sigfunc + }, + )); + aiow.as_mut().submit().unwrap(); while !SIGNALED.load(Ordering::Relaxed) { thread::sleep(time::Duration::from_millis(10)); } - assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len()); + assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); f.seek(SeekFrom::Start(0)).unwrap(); let len = f.read_to_end(&mut rbuf).unwrap(); assert_eq!(len, EXPECT.len()); assert_eq!(rbuf, EXPECT); } -// Test LioCb::listio with LIO_WAIT, so all AIO ops should be complete by the -// time listio returns. -#[test] -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] -fn test_liocb_listio_wait() { - const INITIAL: &[u8] = b"abcdef123456"; - const WBUF: &[u8] = b"CDEF"; - let mut rbuf = vec![0; 4]; - let rlen = rbuf.len(); - let mut rbuf2 = Vec::new(); - const EXPECT: &[u8] = b"abCDEF123456"; - let mut f = tempfile().unwrap(); - - f.write_all(INITIAL).unwrap(); - - { - let mut liocb = LioCbBuilder::with_capacity(2) - .emplace_slice( - f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_WRITE - ).emplace_mut_slice( - f.as_raw_fd(), - 8, //offset - &mut rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_READ - ).finish(); - let err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone); - err.expect("lio_listio"); - - assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); - assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen); - } - assert_eq!(rbuf.deref().deref(), b"3456"); - - f.seek(SeekFrom::Start(0)).unwrap(); - let len = f.read_to_end(&mut rbuf2).unwrap(); - assert_eq!(len, EXPECT.len()); - assert_eq!(rbuf2, EXPECT); -} - -// Test LioCb::listio with LIO_NOWAIT and no SigEvent, so we must use some other -// mechanism to check for the individual AioCb's completion. +// Tests using aio_cancel_all for all outstanding IOs. #[test] -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] -fn test_liocb_listio_nowait() { - const INITIAL: &[u8] = b"abcdef123456"; - const WBUF: &[u8] = b"CDEF"; - let mut rbuf = vec![0; 4]; - let rlen = rbuf.len(); - let mut rbuf2 = Vec::new(); - const EXPECT: &[u8] = b"abCDEF123456"; - let mut f = tempfile().unwrap(); +#[cfg_attr(target_env = "musl", ignore)] +fn test_aio_cancel_all() { + let wbuf: &[u8] = b"CDEF"; - f.write_all(INITIAL).unwrap(); + let f = tempfile().unwrap(); + let mut aiocb = Box::pin(AioWrite::new( + f.as_raw_fd(), + 0, //offset + wbuf, + 0, //priority + SigevNotify::SigevNone, + )); + aiocb.as_mut().submit().unwrap(); + let err = aiocb.as_mut().error(); + assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); - { - let mut liocb = LioCbBuilder::with_capacity(2) - .emplace_slice( - f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_WRITE - ).emplace_mut_slice( - f.as_raw_fd(), - 8, //offset - &mut rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_READ - ).finish(); - let err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone); - err.expect("lio_listio"); - - poll_lio(&mut liocb, 0).unwrap(); - poll_lio(&mut liocb, 1).unwrap(); - assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); - assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen); - } - assert_eq!(rbuf.deref().deref(), b"3456"); + let cancelstat = aio_cancel_all(f.as_raw_fd()); + assert!(cancelstat.is_ok()); - f.seek(SeekFrom::Start(0)).unwrap(); - let len = f.read_to_end(&mut rbuf2).unwrap(); - assert_eq!(len, EXPECT.len()); - assert_eq!(rbuf2, EXPECT); + // Wait for aiocb to complete, but don't care whether it succeeded + let _ = poll_aio!(&mut aiocb); + let _ = aiocb.as_mut().aio_return(); } -// Test LioCb::listio with LIO_NOWAIT and a SigEvent to indicate when all -// AioCb's are complete. -// FIXME: This test is ignored on mips/mips64 because of failures in qemu in CI. #[test] -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -#[cfg_attr(any(target_arch = "mips", target_arch = "mips64", target_env = "musl"), ignore)] -fn test_liocb_listio_signal() { - let _m = crate::SIGNAL_MTX.lock(); +// On Cirrus on Linux, this test fails due to a glibc bug. +// https://github.com/nix-rust/nix/issues/1099 +#[cfg_attr(target_os = "linux", ignore)] +// On Cirrus, aio_suspend is failing with EINVAL +// https://github.com/nix-rust/nix/issues/1361 +#[cfg_attr(target_os = "macos", ignore)] +fn test_aio_suspend() { const INITIAL: &[u8] = b"abcdef123456"; - const WBUF: &[u8] = b"CDEF"; + const WBUF: &[u8] = b"CDEFG"; + let timeout = TimeSpec::seconds(10); let mut rbuf = vec![0; 4]; let rlen = rbuf.len(); - let mut rbuf2 = Vec::new(); - const EXPECT: &[u8] = b"abCDEF123456"; let mut f = tempfile().unwrap(); - let sa = SigAction::new(SigHandler::Handler(sigfunc), - SaFlags::SA_RESETHAND, - SigSet::empty()); - let sigev_notify = SigevNotify::SigevSignal { signal: Signal::SIGUSR2, - si_value: 0 }; - f.write_all(INITIAL).unwrap(); - { - let mut liocb = LioCbBuilder::with_capacity(2) - .emplace_slice( - f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_WRITE - ).emplace_mut_slice( - f.as_raw_fd(), - 8, //offset - &mut rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_READ - ).finish(); - SIGNALED.store(false, Ordering::Relaxed); - unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); - let err = liocb.listio(LioMode::LIO_NOWAIT, sigev_notify); - err.expect("lio_listio"); - while !SIGNALED.load(Ordering::Relaxed) { - thread::sleep(time::Duration::from_millis(10)); + let mut wcb = Box::pin(AioWrite::new( + f.as_raw_fd(), + 2, //offset + WBUF, + 0, //priority + SigevNotify::SigevNone, + )); + + let mut rcb = Box::pin(AioRead::new( + f.as_raw_fd(), + 8, //offset + &mut rbuf, + 0, //priority + SigevNotify::SigevNone, + )); + wcb.as_mut().submit().unwrap(); + rcb.as_mut().submit().unwrap(); + loop { + { + let cbbuf = [ + &*wcb as &dyn AsRef, + &*rcb as &dyn AsRef, + ]; + let r = aio_suspend(&cbbuf[..], Some(timeout)); + match r { + Err(Errno::EINTR) => continue, + Err(e) => panic!("aio_suspend returned {:?}", e), + Ok(_) => (), + }; + } + if rcb.as_mut().error() != Err(Errno::EINPROGRESS) && + wcb.as_mut().error() != Err(Errno::EINPROGRESS) + { + break; } - - assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); - assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen); } - assert_eq!(rbuf.deref().deref(), b"3456"); - - f.seek(SeekFrom::Start(0)).unwrap(); - let len = f.read_to_end(&mut rbuf2).unwrap(); - assert_eq!(len, EXPECT.len()); - assert_eq!(rbuf2, EXPECT); -} -// Try to use LioCb::listio to read into an immutable buffer. It should fail -// FIXME: This test fails to panic on Linux/musl -#[test] -#[cfg(not(any(target_os = "ios", target_os = "macos")))] -#[should_panic(expected = "Can't read into an immutable buffer")] -#[cfg_attr(target_env = "musl", ignore)] -fn test_liocb_listio_read_immutable() { - let rbuf: &[u8] = b"abcd"; - let f = tempfile().unwrap(); - - - let mut liocb = LioCbBuilder::with_capacity(1) - .emplace_slice( - f.as_raw_fd(), - 2, //offset - rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_READ - ).finish(); - let _ = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone); + assert_eq!(wcb.as_mut().aio_return().unwrap(), WBUF.len()); + assert_eq!(rcb.as_mut().aio_return().unwrap(), rlen); } diff --git a/test/sys/test_aio_drop.rs b/test/sys/test_aio_drop.rs index f9ff97af6c..0836a5422d 100644 --- a/test/sys/test_aio_drop.rs +++ b/test/sys/test_aio_drop.rs @@ -20,11 +20,10 @@ fn test_drop() { let f = tempfile().unwrap(); f.set_len(6).unwrap(); - let mut aiocb = AioCb::from_slice( f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_NOP); - aiocb.write().unwrap(); + let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), + 2, //offset + WBUF, + 0, //priority + SigevNotify::SigevNone)); + aiocb.as_mut().submit().unwrap(); } diff --git a/test/sys/test_lio_listio_resubmit.rs b/test/sys/test_lio_listio_resubmit.rs deleted file mode 100644 index 2ed058c27c..0000000000 --- a/test/sys/test_lio_listio_resubmit.rs +++ /dev/null @@ -1,106 +0,0 @@ -// vim: tw=80 - -// Annoyingly, Cargo is unable to conditionally build an entire test binary. So -// we must disable the test here rather than in Cargo.toml -#![cfg(target_os = "freebsd")] - -use nix::errno::*; -use nix::libc::off_t; -use nix::sys::aio::*; -use nix::sys::signal::SigevNotify; -use nix::unistd::{SysconfVar, sysconf}; -use std::os::unix::io::AsRawFd; -use std::{thread, time}; -use sysctl::{CtlValue, Sysctl}; -use tempfile::tempfile; - -const BYTES_PER_OP: usize = 512; - -/// Attempt to collect final status for all of `liocb`'s operations, freeing -/// system resources -fn finish_liocb(liocb: &mut LioCb) { - for j in 0..liocb.len() { - loop { - let e = liocb.error(j); - match e { - Ok(()) => break, - Err(Errno::EINPROGRESS) => - thread::sleep(time::Duration::from_millis(10)), - Err(x) => panic!("aio_error({:?})", x) - } - } - assert_eq!(liocb.aio_return(j).unwrap(), BYTES_PER_OP as isize); - } -} - -// Deliberately exceed system resource limits, causing lio_listio to return EIO. -// This test must run in its own process since it deliberately uses all AIO -// resources. ATM it is only enabled on FreeBSD, because I don't know how to -// check system AIO limits on other operating systems. -#[test] -fn test_lio_listio_resubmit() { - let mut resubmit_count = 0; - - // Lookup system resource limits - let alm = sysconf(SysconfVar::AIO_LISTIO_MAX) - .expect("sysconf").unwrap() as usize; - let ctl = sysctl::Ctl::new("vfs.aio.max_aio_queue_per_proc").unwrap(); - let maqpp = if let CtlValue::Int(x) = ctl.value().unwrap() { - x as usize - } else { - panic!("unknown sysctl"); - }; - - // Find lio_listio sizes that satisfy the AIO_LISTIO_MAX constraint and also - // result in a final lio_listio call that can only partially be queued - let target_ops = maqpp + alm / 2; - let num_listios = (target_ops + alm - 3) / (alm - 2); - let ops_per_listio = (target_ops + num_listios - 1) / num_listios; - assert!((num_listios - 1) * ops_per_listio < maqpp, - "the last lio_listio won't make any progress; fix the algorithm"); - println!("Using {:?} LioCbs of {:?} operations apiece", num_listios, - ops_per_listio); - - let f = tempfile().unwrap(); - let buffer_set = (0..num_listios).map(|_| { - (0..ops_per_listio).map(|_| { - vec![0u8; BYTES_PER_OP] - }).collect::>() - }).collect::>(); - - let mut liocbs = (0..num_listios).map(|i| { - let mut builder = LioCbBuilder::with_capacity(ops_per_listio); - for j in 0..ops_per_listio { - let offset = (BYTES_PER_OP * (i * ops_per_listio + j)) as off_t; - builder = builder.emplace_slice(f.as_raw_fd(), - offset, - &buffer_set[i][j][..], - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_WRITE); - } - let mut liocb = builder.finish(); - let mut err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone); - while err == Err(Errno::EIO) || - err == Err(Errno::EAGAIN) || - err == Err(Errno::EINTR) { - // - thread::sleep(time::Duration::from_millis(10)); - resubmit_count += 1; - err = liocb.listio_resubmit(LioMode::LIO_NOWAIT, - SigevNotify::SigevNone); - } - liocb - }).collect::>(); - - // Ensure that every AioCb completed - for liocb in liocbs.iter_mut() { - finish_liocb(liocb); - } - - if resubmit_count > 0 { - println!("Resubmitted {:?} times, test passed", resubmit_count); - } else { - println!("Never resubmitted. Test ambiguous"); - } -} From d02e27476cbf23b6818e57e017fd6148a98b7a92 Mon Sep 17 00:00:00 2001 From: Al Hoang <3811822-hoanga@users.noreply.gitlab.com> Date: Fri, 22 Apr 2022 23:56:51 -0500 Subject: [PATCH 100/358] add haiku support * enabled as much functionality and defines that match updated libc definitions for haiku --- .cirrus.yml | 3 + CHANGELOG.md | 3 + README.md | 1 + bors.toml | 1 + src/dir.rs | 6 +- src/errno.rs | 209 ++++++++++++++++++++++++++++++++++++-- src/fcntl.rs | 4 +- src/features.rs | 1 + src/net/if_.rs | 1 + src/sys/ioctl/mod.rs | 2 + src/sys/mman.rs | 3 + src/sys/mod.rs | 2 +- src/sys/signal.rs | 50 +++++++-- src/sys/socket/addr.rs | 14 ++- src/sys/socket/mod.rs | 6 +- src/sys/socket/sockopt.rs | 5 +- src/sys/stat.rs | 2 +- src/sys/statvfs.rs | 2 + src/sys/termios.rs | 20 +++- src/sys/uio.rs | 4 +- src/unistd.rs | 95 +++++++++-------- test/sys/mod.rs | 8 +- test/sys/test_uio.rs | 4 +- test/sys/test_wait.rs | 5 +- test/test.rs | 4 +- test/test_dir.rs | 1 + test/test_net.rs | 5 +- test/test_resource.rs | 4 +- test/test_stat.rs | 36 ++++--- test/test_unistd.rs | 47 +++++---- 30 files changed, 424 insertions(+), 124 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 231cc38fb3..ae184f86e4 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -298,6 +298,9 @@ task: - name: Linux armv7 uclibceabihf env: TARGET: armv7-unknown-linux-uclibceabihf + - name: Haiku x86_64 + env: + TARGET: x86_64-unknown-haiku setup_script: - rustup component add rust-src << : *BUILD diff --git a/CHANGELOG.md b/CHANGELOG.md index de4d22e2c0..4cb9d2aec5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). - impl From for std::net::SocketAddrV4 and impl From for std::net::SocketAddrV6. (#[1711](https://github.com/nix-rust/nix/pull/1711)) +- Fixed compilation and updated support on Haiku +- Added support for the `x86_64-unknown-haiku` target. + (#[1703](https://github.com/nix-rust/nix/pull/1703)) ### Changed diff --git a/README.md b/README.md index b0c27b16f3..44e620cce5 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ Tier 3: * armv7-unknown-linux-uclibceabihf * x86_64-fuchsia * x86_64-unknown-dragonfly + * x86_64-unknown-haiku * x86_64-unknown-linux-gnux32 * x86_64-unknown-openbsd * x86_64-unknown-redox diff --git a/bors.toml b/bors.toml index b020ca389e..3936888423 100644 --- a/bors.toml +++ b/bors.toml @@ -36,6 +36,7 @@ status = [ "iOS aarch64", "iOS x86_64", "Illumos", + "Haiku x86_64", ] # Set bors's timeout to 1 hour diff --git a/src/dir.rs b/src/dir.rs index 396b54fb03..c9b5af8fc4 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -226,7 +226,7 @@ impl Entry { /// notably, some Linux filesystems don't implement this. The caller should use `stat` or /// `fstat` if this returns `None`. pub fn file_type(&self) -> Option { - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] + #[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "haiku")))] match self.0.d_type { libc::DT_FIFO => Some(Type::Fifo), libc::DT_CHR => Some(Type::CharacterDevice), @@ -238,8 +238,8 @@ impl Entry { /* libc::DT_UNKNOWN | */ _ => None, } - // illumos and Solaris systems do not have the d_type member at all: - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + // illumos, Solaris, and Haiku systems do not have the d_type member at all: + #[cfg(any(target_os = "illumos", target_os = "solaris", target_os = "haiku"))] None } } diff --git a/src/errno.rs b/src/errno.rs index 17744fe22a..759b649d8f 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -30,6 +30,10 @@ cfg_if! { unsafe fn errno_location() -> *mut c_int { libc::___errno() } + } else if #[cfg(any(target_os = "haiku",))] { + unsafe fn errno_location() -> *mut c_int { + libc::_errnop() + } } } @@ -201,6 +205,7 @@ fn desc(errno: Errno) -> &'static str { ENOMEM => "Out of memory", EACCES => "Permission denied", EFAULT => "Bad address", + #[cfg(not(target_os = "haiku"))] ENOTBLK => "Block device required", EBUSY => "Device or resource busy", EEXIST => "File exists", @@ -237,8 +242,11 @@ fn desc(errno: Errno) -> &'static str { EPROTOTYPE => "Protocol wrong type for socket", ENOPROTOOPT => "Protocol not available", EPROTONOSUPPORT => "Protocol not supported", + #[cfg(not(target_os = "haiku"))] ESOCKTNOSUPPORT => "Socket type not supported", + #[cfg(not(target_os = "haiku"))] EPFNOSUPPORT => "Protocol family not supported", + #[cfg(not(target_os = "haiku"))] EAFNOSUPPORT => "Address family not supported by protocol", EADDRINUSE => "Address already in use", EADDRNOTAVAIL => "Cannot assign requested address", @@ -251,6 +259,7 @@ fn desc(errno: Errno) -> &'static str { EISCONN => "Transport endpoint is already connected", ENOTCONN => "Transport endpoint is not connected", ESHUTDOWN => "Cannot send after transport endpoint shutdown", + #[cfg(not(target_os = "haiku"))] ETOOMANYREFS => "Too many references: cannot splice", ETIMEDOUT => "Connection timed out", ECONNREFUSED => "Connection refused", @@ -409,7 +418,7 @@ fn desc(errno: Errno) -> &'static str { EBADMSG => "Trying to read unreadable message", #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] + target_os = "fuchsia", target_os = "haiku"))] EOVERFLOW => "Value too large for defined data type", #[cfg(any(target_os = "linux", target_os = "android", @@ -516,7 +525,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any(target_os = "linux", target_os = "android", target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] + target_os = "fuchsia", target_os = "haiku"))] ECANCELED => "Operation canceled", #[cfg(any(target_os = "linux", target_os = "android", @@ -587,24 +596,26 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "netbsd", target_os = "redox"))] + target_os = "netbsd", target_os = "redox", + target_os = "haiku"))] EILSEQ => "Illegal byte sequence", #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd"))] + target_os = "openbsd", target_os = "netbsd", + target_os = "haiku"))] ENOATTR => "Attribute not found", #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", target_os = "openbsd", target_os = "netbsd", - target_os = "redox"))] + target_os = "redox", target_os = "haiku"))] EBADMSG => "Bad message", #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", target_os = "openbsd", target_os = "netbsd", - target_os = "redox"))] + target_os = "redox", target_os = "haiku"))] EPROTO => "Protocol error", #[cfg(any(target_os = "macos", target_os = "freebsd", @@ -620,7 +631,8 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", target_os = "openbsd", target_os = "netbsd", - target_os = "illumos", target_os = "solaris"))] + target_os = "illumos", target_os = "solaris", + target_os = "haiku"))] ENOTSUP => "Operation not supported", #[cfg(any(target_os = "macos", target_os = "freebsd", @@ -638,14 +650,14 @@ fn desc(errno: Errno) -> &'static str { target_os = "dragonfly", target_os = "ios", target_os = "openbsd", target_os = "netbsd", target_os = "redox", target_os = "illumos", - target_os = "solaris"))] + target_os = "solaris", target_os = "haiku"))] EDQUOT => "Disc quota exceeded", #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", target_os = "openbsd", target_os = "netbsd", target_os = "redox", target_os = "illumos", - target_os = "solaris"))] + target_os = "solaris", target_os = "haiku"))] ESTALE => "Stale NFS file handle", #[cfg(any(target_os = "macos", target_os = "freebsd", @@ -714,7 +726,7 @@ fn desc(errno: Errno) -> &'static str { EBADMACHO => "Malformed Macho file", #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "netbsd"))] + target_os = "netbsd", target_os = "haiku"))] EMULTIHOP => "Reserved", #[cfg(any(target_os = "macos", target_os = "ios", @@ -722,7 +734,7 @@ fn desc(errno: Errno) -> &'static str { ENODATA => "No message available on STREAM", #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "netbsd"))] + target_os = "netbsd", target_os = "haiku"))] ENOLINK => "Reserved", #[cfg(any(target_os = "macos", target_os = "ios", @@ -2725,3 +2737,178 @@ mod consts { } } } + +#[cfg(target_os = "haiku")] +mod consts { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr(i32)] + #[non_exhaustive] + pub enum Errno { + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, + EPROTONOSUPPORT = libc::EPROTONOSUPPORT, + ENOTSUP = libc::ENOTSUP, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + EOVERFLOW = libc::EOVERFLOW, + ECANCELED = libc::ECANCELED, + EILSEQ = libc::EILSEQ, + ENOATTR = libc::ENOATTR, + EBADMSG = libc::EBADMSG, + EMULTIHOP = libc::EMULTIHOP, + ENOLINK = libc::ENOLINK, + EPROTO = libc::EPROTO, + } + + impl Errno { + pub const EWOULDBLOCK: Errno = Errno::EAGAIN; + pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; + } + + pub const fn from_i32(e: i32) -> Errno { + use self::Errno::*; + + match e { + libc::EPERM => EPERM, + libc::ENOENT => ENOENT, + libc::ESRCH => ESRCH, + libc::EINTR => EINTR, + libc::EIO => EIO, + libc::ENXIO => ENXIO, + libc::E2BIG => E2BIG, + libc::ENOEXEC => ENOEXEC, + libc::EBADF => EBADF, + libc::ECHILD => ECHILD, + libc::EDEADLK => EDEADLK, + libc::ENOMEM => ENOMEM, + libc::EACCES => EACCES, + libc::EFAULT => EFAULT, + libc::EBUSY => EBUSY, + libc::EEXIST => EEXIST, + libc::EXDEV => EXDEV, + libc::ENODEV => ENODEV, + libc::ENOTDIR => ENOTDIR, + libc::EISDIR => EISDIR, + libc::EINVAL => EINVAL, + libc::ENFILE => ENFILE, + libc::EMFILE => EMFILE, + libc::ENOTTY => ENOTTY, + libc::ETXTBSY => ETXTBSY, + libc::EFBIG => EFBIG, + libc::ENOSPC => ENOSPC, + libc::ESPIPE => ESPIPE, + libc::EROFS => EROFS, + libc::EMLINK => EMLINK, + libc::EPIPE => EPIPE, + libc::EDOM => EDOM, + libc::ERANGE => ERANGE, + libc::EAGAIN => EAGAIN, + libc::EINPROGRESS => EINPROGRESS, + libc::EALREADY => EALREADY, + libc::ENOTSOCK => ENOTSOCK, + libc::EDESTADDRREQ => EDESTADDRREQ, + libc::EMSGSIZE => EMSGSIZE, + libc::EPROTOTYPE => EPROTOTYPE, + libc::ENOPROTOOPT => ENOPROTOOPT, + libc::EPROTONOSUPPORT => EPROTONOSUPPORT, + libc::ENOTSUP => ENOTSUP, + libc::EADDRINUSE => EADDRINUSE, + libc::EADDRNOTAVAIL => EADDRNOTAVAIL, + libc::ENETDOWN => ENETDOWN, + libc::ENETUNREACH => ENETUNREACH, + libc::ENETRESET => ENETRESET, + libc::ECONNABORTED => ECONNABORTED, + libc::ECONNRESET => ECONNRESET, + libc::ENOBUFS => ENOBUFS, + libc::EISCONN => EISCONN, + libc::ENOTCONN => ENOTCONN, + libc::ESHUTDOWN => ESHUTDOWN, + libc::ETIMEDOUT => ETIMEDOUT, + libc::ECONNREFUSED => ECONNREFUSED, + libc::ELOOP => ELOOP, + libc::ENAMETOOLONG => ENAMETOOLONG, + libc::EHOSTDOWN => EHOSTDOWN, + libc::EHOSTUNREACH => EHOSTUNREACH, + libc::ENOTEMPTY => ENOTEMPTY, + libc::EDQUOT => EDQUOT, + libc::ESTALE => ESTALE, + libc::ENOLCK => ENOLCK, + libc::ENOSYS => ENOSYS, + libc::EIDRM => EIDRM, + libc::ENOMSG => ENOMSG, + libc::EOVERFLOW => EOVERFLOW, + libc::ECANCELED => ECANCELED, + libc::EILSEQ => EILSEQ, + libc::ENOATTR => ENOATTR, + libc::EBADMSG => EBADMSG, + libc::EMULTIHOP => EMULTIHOP, + libc::ENOLINK => ENOLINK, + libc::EPROTO => EPROTO, + _ => UnknownErrno, + } + } +} + diff --git a/src/fcntl.rs b/src/fcntl.rs index 5272c80955..7319302d2a 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -58,7 +58,7 @@ libc_bitflags!( /// Open the file in append-only mode. O_APPEND; /// Generate a signal when input or output becomes possible. - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] + #[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] O_ASYNC; /// Closes the file descriptor once an `execve` call is made. @@ -128,7 +128,7 @@ libc_bitflags!( #[cfg_attr(docsrs, doc(cfg(all())))] O_NOCTTY; /// Same as `O_NONBLOCK`. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] O_NDELAY; /// `open()` will fail if the given path is a symbolic link. diff --git a/src/features.rs b/src/features.rs index 6108098610..d2adc1693b 100644 --- a/src/features.rs +++ b/src/features.rs @@ -114,6 +114,7 @@ mod os { #[cfg(any(target_os = "macos", target_os = "ios", target_os = "fuchsia", + target_os = "haiku", target_os = "solaris"))] mod os { /// Check if the OS supports atomic close-on-exec for sockets diff --git a/src/net/if_.rs b/src/net/if_.rs index ebe8bcceeb..535d6c2269 100644 --- a/src/net/if_.rs +++ b/src/net/if_.rs @@ -28,6 +28,7 @@ libc_bitflags!( IFF_BROADCAST; /// Internal debugging flag. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) + #[cfg(not(target_os = "haiku"))] IFF_DEBUG; /// Interface is a loopback interface. (see /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html)) diff --git a/src/sys/ioctl/mod.rs b/src/sys/ioctl/mod.rs index 203b7d06f3..ce9c5db072 100644 --- a/src/sys/ioctl/mod.rs +++ b/src/sys/ioctl/mod.rs @@ -236,6 +236,7 @@ pub use self::linux::*; target_os = "ios", target_os = "macos", target_os = "netbsd", + target_os = "haiku", target_os = "openbsd"))] #[macro_use] mod bsd; @@ -246,6 +247,7 @@ mod bsd; target_os = "ios", target_os = "macos", target_os = "netbsd", + target_os = "haiku", target_os = "openbsd"))] pub use self::bsd::*; diff --git a/src/sys/mman.rs b/src/sys/mman.rs index a7469a1792..700e231c62 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -351,6 +351,7 @@ libc_bitflags!{ } } +#[cfg(not(target_os = "haiku"))] libc_bitflags!{ /// Flags for [`mlockall`]. pub struct MlockAllFlags: c_int { @@ -393,6 +394,7 @@ pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> { /// Locked pages never move to the swap area. For more information, see [`mlockall(2)`]. /// /// [`mlockall(2)`]: https://man7.org/linux/man-pages/man2/mlockall.2.html +#[cfg(not(target_os = "haiku"))] pub fn mlockall(flags: MlockAllFlags) -> Result<()> { unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop) } @@ -402,6 +404,7 @@ pub fn mlockall(flags: MlockAllFlags) -> Result<()> { /// For more information, see [`munlockall(2)`]. /// /// [`munlockall(2)`]: https://man7.org/linux/man-pages/man2/munlockall.2.html +#[cfg(not(target_os = "haiku"))] pub fn munlockall() -> Result<()> { unsafe { Errno::result(libc::munlockall()) }.map(drop) } diff --git a/src/sys/mod.rs b/src/sys/mod.rs index e5639f20ab..9f0d037ecc 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -94,7 +94,7 @@ feature! { pub mod reboot; } -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))] +#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos", target_os = "haiku")))] feature! { #![feature = "resource"] pub mod resource; diff --git a/src/sys/signal.rs b/src/sys/signal.rs index f982b4e79b..9a4e90e4ce 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -89,6 +89,8 @@ libc_enum!{ /// Window size changes SIGWINCH, /// Input/output possible signal + #[cfg(not(target_os = "haiku"))] + #[cfg_attr(docsrs, doc(cfg(all())))] SIGIO, #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] @@ -99,13 +101,13 @@ libc_enum!{ SIGSYS, #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", - target_os = "redox")))] + target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Emulator trap SIGEMT, #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", - target_os = "redox")))] + target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Information request SIGINFO, @@ -150,6 +152,7 @@ impl FromStr for Signal { "SIGVTALRM" => Signal::SIGVTALRM, "SIGPROF" => Signal::SIGPROF, "SIGWINCH" => Signal::SIGWINCH, + #[cfg(not(target_os = "haiku"))] "SIGIO" => Signal::SIGIO, #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] @@ -157,11 +160,11 @@ impl FromStr for Signal { "SIGSYS" => Signal::SIGSYS, #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", - target_os = "redox")))] + target_os = "redox", target_os = "haiku")))] "SIGEMT" => Signal::SIGEMT, #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", - target_os = "redox")))] + target_os = "redox", target_os = "haiku")))] "SIGINFO" => Signal::SIGINFO, _ => return Err(Errno::EINVAL), }) @@ -208,6 +211,7 @@ impl Signal { Signal::SIGVTALRM => "SIGVTALRM", Signal::SIGPROF => "SIGPROF", Signal::SIGWINCH => "SIGWINCH", + #[cfg(not(target_os = "haiku"))] Signal::SIGIO => "SIGIO", #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] @@ -215,11 +219,11 @@ impl Signal { Signal::SIGSYS => "SIGSYS", #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", - target_os = "redox")))] + target_os = "redox", target_os = "haiku")))] Signal::SIGEMT => "SIGEMT", #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", - target_os = "redox")))] + target_os = "redox", target_os = "haiku")))] Signal::SIGINFO => "SIGINFO", } } @@ -274,6 +278,37 @@ const SIGNALS: [Signal; 29] = [ SIGWINCH, SIGIO, SIGSYS]; +#[cfg(target_os = "haiku")] +#[cfg(feature = "signal")] +const SIGNALS: [Signal; 28] = [ + SIGHUP, + SIGINT, + SIGQUIT, + SIGILL, + SIGTRAP, + SIGABRT, + SIGBUS, + SIGFPE, + SIGKILL, + SIGUSR1, + SIGSEGV, + SIGUSR2, + SIGPIPE, + SIGALRM, + SIGTERM, + SIGCHLD, + SIGCONT, + SIGSTOP, + SIGTSTP, + SIGTTIN, + SIGTTOU, + SIGURG, + SIGXCPU, + SIGXFSZ, + SIGVTALRM, + SIGPROF, + SIGWINCH, + SIGSYS]; #[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten", target_os = "fuchsia"), not(any(target_arch = "mips", target_arch = "mips64", @@ -349,7 +384,7 @@ const SIGNALS: [Signal; 30] = [ SIGSYS]; #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "fuchsia", target_os = "emscripten", - target_os = "redox")))] + target_os = "redox", target_os = "haiku")))] #[cfg(feature = "signal")] const SIGNALS: [Signal; 31] = [ SIGHUP, @@ -417,6 +452,7 @@ impl Signal { /// Alias for [`SIGABRT`] pub const SIGIOT : Signal = SIGABRT; /// Alias for [`SIGIO`] +#[cfg(not(target_os = "haiku"))] pub const SIGPOLL : Signal = SIGIO; /// Alias for [`SIGSYS`] pub const SIGUNUSED : Signal = SIGSYS; diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 5cd4678c3c..6d38f26c31 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -26,6 +26,7 @@ use crate::sys::socket::addr::sys_control::SysControlAddr; target_os = "illumos", target_os = "netbsd", target_os = "openbsd", + target_os = "haiku", target_os = "fuchsia"))] #[cfg(feature = "net")] pub use self::datalink::LinkAddr; @@ -120,6 +121,7 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] Rose = libc::AF_ROSE, /// DECet protocol sockets. + #[cfg(not(target_os = "haiku"))] Decnet = libc::AF_DECnet, /// Reserved for "802.2LLC project"; never used. #[cfg(any(target_os = "android", target_os = "linux"))] @@ -151,6 +153,7 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] Rds = libc::AF_RDS, /// IBM SNA + #[cfg(not(target_os = "haiku"))] Sna = libc::AF_SNA, /// Socket interface over IrDA #[cfg(any(target_os = "android", target_os = "linux"))] @@ -202,7 +205,7 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] RxRpc = libc::AF_RXRPC, /// New "modular ISDN" driver interface protocol - #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] + #[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] Isdn = libc::AF_ISDN, /// Nokia cellular modem IPC/RPC interface @@ -1158,6 +1161,7 @@ impl SockaddrIn { target_os = "ios", target_os = "macos", target_os = "netbsd", + target_os = "haiku", target_os = "openbsd"))] sin_len: Self::size() as u8, sin_family: AddressFamily::Inet as sa_family_t, @@ -1442,6 +1446,7 @@ impl SockaddrLike for SockaddrStorage { target_os = "macos", target_os = "illumos", target_os = "netbsd", + target_os = "haiku", target_os = "openbsd"))] #[cfg(feature = "net")] libc::AF_LINK => LinkAddr::from_raw(addr, l) @@ -2411,6 +2416,7 @@ mod datalink { target_os = "macos", target_os = "illumos", target_os = "netbsd", + target_os = "haiku", target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] mod datalink { @@ -2425,11 +2431,13 @@ mod datalink { impl LinkAddr { /// interface index, if != 0, system given index for interface + #[cfg(not(target_os = "haiku"))] pub fn ifindex(&self) -> usize { self.0.sdl_index as usize } /// Datalink type + #[cfg(not(target_os = "haiku"))] pub fn datalink_type(&self) -> u8 { self.0.sdl_type } @@ -2445,6 +2453,7 @@ mod datalink { } /// link layer selector length + #[cfg(not(target_os = "haiku"))] pub fn slen(&self) -> usize { self.0.sdl_slen as usize } @@ -2737,7 +2746,8 @@ mod tests { target_os = "macos", target_os = "netbsd", target_os = "illumos", - target_os = "openbsd"))] + target_os = "openbsd", + target_os = "haiku"))] let l = mem::size_of::(); #[cfg(any( target_os = "android", diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index c661389200..6386e62b6b 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -38,7 +38,7 @@ pub use self::addr::{ UnixAddr, }; #[allow(deprecated)] -#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] +#[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "haiku")))] #[cfg(feature = "net")] pub use self::addr::{ InetAddr, @@ -57,7 +57,7 @@ pub use self::addr::{ UnixAddr, }; #[allow(deprecated)] -#[cfg(any(target_os = "illumos", target_os = "solaris"))] +#[cfg(any(target_os = "illumos", target_os = "solaris", target_os = "haiku"))] #[cfg(feature = "net")] pub use self::addr::{ InetAddr, @@ -118,6 +118,7 @@ pub enum SockType { Raw = libc::SOCK_RAW, /// Provides a reliable datagram layer that does not /// guarantee ordering. + #[cfg(not(any(target_os = "haiku")))] Rdm = libc::SOCK_RDM, } @@ -845,6 +846,7 @@ impl ControlMessageOwned { let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _); ControlMessageOwned::ScmCreds(cred.into()) } + #[cfg(not(target_os = "haiku"))] (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => { let tv: libc::timeval = ptr::read_unaligned(p as *const _); ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 14fea808fc..73d154065f 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -399,7 +399,7 @@ cfg_if! { TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); } } -#[cfg(not(target_os = "openbsd"))] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku")))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -413,7 +413,7 @@ sockopt_impl!( #[allow(missing_docs)] // Not documented by Linux! TcpRepair, Both, libc::IPPROTO_TCP, libc::TCP_REPAIR, u32); -#[cfg(not(target_os = "openbsd"))] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku")))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -473,6 +473,7 @@ sockopt_impl!( /// Specifies exact type of timestamping information collected by the kernel /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) Timestamping, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPING, super::TimestampingFlag); +#[cfg(not(target_os = "haiku"))] sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. ReceiveTimestamp, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool); diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 67a1b7f769..5cf2deb75e 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -53,7 +53,7 @@ pub fn mknod(path: &P, kind: SFlag, perm: Mode, dev: dev_t) } /// Create a special or ordinary file, relative to a given directory. -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] +#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn mknodat( dirfd: RawFd, diff --git a/src/sys/statvfs.rs b/src/sys/statvfs.rs index ab54b4b50b..38b1fdcc50 100644 --- a/src/sys/statvfs.rs +++ b/src/sys/statvfs.rs @@ -16,8 +16,10 @@ libc_bitflags!( #[derive(Default)] pub struct FsFlags: c_ulong { /// Read Only + #[cfg(not(target_os = "haiku"))] ST_RDONLY; /// Do not allow the set-uid bits to have an effect + #[cfg(not(target_os = "haiku"))] ST_NOSUID; /// Do not interpret character or block-special devices #[cfg(any(target_os = "android", target_os = "linux"))] diff --git a/src/sys/termios.rs b/src/sys/termios.rs index 8870f6be7b..2e1b53d7c9 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -255,8 +255,9 @@ libc_enum!{ /// enum. /// /// B0 is special and will disable the port. + #[cfg_attr(all(any(target_os = "haiku"), target_pointer_width = "64"), repr(u8))] #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))] - #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64")), repr(u32))] + #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos", target_os = "haiku"), target_pointer_width = "64")), repr(u32))] #[non_exhaustive] pub enum BaudRate { B0, @@ -374,6 +375,14 @@ impl From for u32 { } } +#[cfg(target_os = "haiku")] +impl From for u8 { + fn from(b: BaudRate) -> u8 { + b as u8 + } +} + + // TODO: Add TCSASOFT, which will require treating this as a bitfield. libc_enum! { /// Specify when a port configuration change should occur. @@ -426,6 +435,7 @@ libc_enum! { } // TODO: Make this usable directly as a slice index. +#[cfg(not(target_os = "haiku"))] libc_enum! { /// Indices into the `termios.c_cc` array for special characters. #[repr(usize)] @@ -524,7 +534,7 @@ libc_bitflags! { #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] IXANY; - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] IMAXBEL; #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] @@ -851,7 +861,7 @@ libc_bitflags! { #[cfg_attr(docsrs, doc(cfg(all())))] ALTWERASE; IEXTEN; - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] EXTPROC; TOSTOP; @@ -979,6 +989,7 @@ cfg_if!{ /// /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that /// this is part of the 4.4BSD standard and not part of POSIX. + #[cfg(not(target_os = "haiku"))] pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { let inner_termios = unsafe { termios.get_libc_termios_mut() }; let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) }; @@ -1095,6 +1106,9 @@ mod test { #[test] fn try_from() { assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0)); + #[cfg(not(target_os = "haiku"))] assert!(BaudRate::try_from(999999999).is_err()); + #[cfg(target_os = "haiku")] + assert!(BaudRate::try_from(99).is_err()); } } diff --git a/src/sys/uio.rs b/src/sys/uio.rs index ba6c64ef26..4b3851f5a1 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -39,7 +39,7 @@ pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result { /// or an error occurs. The file offset is not changed. /// /// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result { @@ -62,7 +62,7 @@ pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], /// changed. /// /// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn preadv(fd: RawFd, iov: &mut [IoSliceMut<'_>], offset: off_t) -> Result { diff --git a/src/unistd.rs b/src/unistd.rs index 764b3dee43..8c42fd2b50 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -549,7 +549,7 @@ pub fn mkfifo(path: &P, mode: Mode) -> Result<()> { // mkfifoat is not implemented in OSX or android #[inline] #[cfg(not(any( - target_os = "macos", target_os = "ios", + target_os = "macos", target_os = "ios", target_os = "haiku", target_os = "android", target_os = "redox")))] pub fn mkfifoat(dirfd: Option, path: &P, mode: Mode) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { @@ -1546,7 +1546,7 @@ pub fn getgroups() -> Result> { /// # /// # try_main().unwrap(); /// ``` -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] +#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))] pub fn setgroups(groups: &[Gid]) -> Result<()> { cfg_if! { if #[cfg(any(target_os = "dragonfly", @@ -1673,7 +1673,7 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result> { /// # /// # try_main().unwrap(); /// ``` -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] +#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))] pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { cfg_if! { if #[cfg(any(target_os = "ios", target_os = "macos"))] { @@ -1802,7 +1802,7 @@ pub fn sleep(seconds: c_uint) -> c_uint { feature! { #![feature = "acct"] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] pub mod acct { use crate::{Result, NixPath}; use crate::errno::Errno; @@ -2088,12 +2088,12 @@ feature! { pub enum SysconfVar { /// Maximum number of I/O operations in a single list I/O call supported by /// the implementation. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX, /// Maximum number of outstanding asynchronous I/O operations supported by /// the implementation. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] AIO_MAX = libc::_SC_AIO_MAX, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", @@ -2110,19 +2110,19 @@ pub enum SysconfVar { #[cfg_attr(docsrs, doc(cfg(all())))] ATEXIT_MAX = libc::_SC_ATEXIT_MAX, /// Maximum obase values allowed by the bc utility. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] BC_BASE_MAX = libc::_SC_BC_BASE_MAX, /// Maximum number of elements permitted in an array by the bc utility. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] BC_DIM_MAX = libc::_SC_BC_DIM_MAX, /// Maximum scale value allowed by the bc utility. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX, /// Maximum length of a string constant accepted by the bc utility. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] BC_STRING_MAX = libc::_SC_BC_STRING_MAX, /// Maximum number of simultaneous processes per real user ID. @@ -2131,16 +2131,16 @@ pub enum SysconfVar { CLK_TCK = libc::_SC_CLK_TCK, /// Maximum number of weights that can be assigned to an entry of the /// LC_COLLATE order keyword in the locale definition file - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX, /// Maximum number of timer expiration overruns. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX, /// Maximum number of expressions that can be nested within parentheses by /// the expr utility. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", @@ -2159,10 +2159,11 @@ pub enum SysconfVar { /// input line (either standard input or another file), when the utility is /// described as processing text files. The length includes room for the /// trailing . - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] LINE_MAX = libc::_SC_LINE_MAX, /// Maximum length of a login name. + #[cfg(not(target_os = "haiku"))] LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX, /// Maximum number of simultaneous supplementary group IDs per process. NGROUPS_MAX = libc::_SC_NGROUPS_MAX, @@ -2175,11 +2176,11 @@ pub enum SysconfVar { #[cfg_attr(docsrs, doc(cfg(all())))] GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX, /// The maximum number of open message queue descriptors a process may hold. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX, /// The maximum number of message priorities supported by the implementation. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX, /// A value one greater than the maximum value that the system may assign to @@ -2197,7 +2198,7 @@ pub enum SysconfVar { /// The implementation supports barriers. _POSIX_BARRIERS = libc::_SC_BARRIERS, /// The implementation supports asynchronous input and output. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", @@ -2213,7 +2214,7 @@ pub enum SysconfVar { /// The implementation supports the Process CPU-Time Clocks option. _POSIX_CPUTIME = libc::_SC_CPUTIME, /// The implementation supports the File Synchronization option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_FSYNC = libc::_SC_FSYNC, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", @@ -2227,15 +2228,15 @@ pub enum SysconfVar { #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL, /// The implementation supports memory mapped Files. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES, /// The implementation supports the Process Memory Locking option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MEMLOCK = libc::_SC_MEMLOCK, /// The implementation supports the Range Memory Locking option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE, /// The implementation supports memory protection. @@ -2243,7 +2244,7 @@ pub enum SysconfVar { #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION, /// The implementation supports the Message Passing option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING, /// The implementation supports the Monotonic Clock option. @@ -2257,7 +2258,7 @@ pub enum SysconfVar { /// The implementation supports the Prioritized Input and Output option. _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO, /// The implementation supports the Process Scheduling option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", @@ -2293,7 +2294,7 @@ pub enum SysconfVar { #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES, /// The implementation supports the Shared Memory Objects option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", @@ -2324,7 +2325,7 @@ pub enum SysconfVar { #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX, /// The implementation supports the Synchronized Input and Output option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO, /// The implementation supports the Thread Stack Address Attribute option. @@ -2342,11 +2343,11 @@ pub enum SysconfVar { _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME, /// The implementation supports the Non-Robust Mutex Priority Inheritance /// option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT, /// The implementation supports the Non-Robust Mutex Priority Protection option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT, /// The implementation supports the Thread Execution Scheduling option. @@ -2369,7 +2370,7 @@ pub enum SysconfVar { /// The implementation supports the Robust Mutex Priority Protection option. _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT, /// The implementation supports thread-safe functions. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", @@ -2466,28 +2467,28 @@ pub enum SysconfVar { /// using at least 64 bits. _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG, /// The implementation supports the C-Language Binding option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_C_BIND = libc::_SC_2_C_BIND, /// The implementation supports the C-Language Development Utilities option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_C_DEV = libc::_SC_2_C_DEV, /// The implementation supports the Terminal Characteristics option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM, /// The implementation supports the FORTRAN Development Utilities option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV, /// The implementation supports the FORTRAN Runtime Utilities option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN, /// The implementation supports the creation of locales by the localedef /// utility. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", @@ -2528,16 +2529,16 @@ pub enum SysconfVar { /// The implementation supports the Track Batch Job Request option. _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK, /// The implementation supports the Software Development Utilities option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_SW_DEV = libc::_SC_2_SW_DEV, /// The implementation supports the User Portability Utilities option. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_UPE = libc::_SC_2_UPE, /// Integer value indicating version of the Shell and Utilities volume of /// POSIX.1 to which the implementation conforms. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_VERSION = libc::_SC_2_VERSION, /// The size of a system page in bytes. @@ -2545,18 +2546,19 @@ pub enum SysconfVar { /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two /// enum constants to have the same value, so nix omits `PAGESIZE`. PAGE_SIZE = libc::_SC_PAGE_SIZE, - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS, - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX, #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN, - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX, + #[cfg(not(target_os = "haiku"))] RE_DUP_MAX = libc::_SC_RE_DUP_MAX, #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", target_os = "ios", target_os="linux", target_os = "macos", @@ -2619,7 +2621,7 @@ pub enum SysconfVar { _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS, /// The implementation supports the Issue 4, Version 2 Shared Memory Option /// Group. - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _XOPEN_SHM = libc::_SC_XOPEN_SHM, #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", @@ -2875,6 +2877,7 @@ pub struct User { /// Login class #[cfg(not(any(target_os = "android", target_os = "fuchsia", + target_os = "haiku", target_os = "illumos", target_os = "linux", target_os = "solaris")))] @@ -2883,6 +2886,7 @@ pub struct User { /// Last password change #[cfg(not(any(target_os = "android", target_os = "fuchsia", + target_os = "haiku", target_os = "illumos", target_os = "linux", target_os = "solaris")))] @@ -2891,6 +2895,7 @@ pub struct User { /// Expiration time of account #[cfg(not(any(target_os = "android", target_os = "fuchsia", + target_os = "haiku", target_os = "illumos", target_os = "linux", target_os = "solaris")))] @@ -2898,7 +2903,7 @@ pub struct User { pub expire: libc::time_t } -#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd +#[cfg(not(target_os = "redox"))] //RedoxFS does not support passwd impl From<&libc::passwd> for User { fn from(pw: &libc::passwd) -> User { unsafe { @@ -2913,18 +2918,21 @@ impl From<&libc::passwd> for User { gid: Gid::from_raw((*pw).pw_gid), #[cfg(not(any(target_os = "android", target_os = "fuchsia", + target_os = "haiku", target_os = "illumos", target_os = "linux", target_os = "solaris")))] class: CString::new(CStr::from_ptr((*pw).pw_class).to_bytes()).unwrap(), #[cfg(not(any(target_os = "android", target_os = "fuchsia", + target_os = "haiku", target_os = "illumos", target_os = "linux", target_os = "solaris")))] change: (*pw).pw_change, #[cfg(not(any(target_os = "android", target_os = "fuchsia", + target_os = "haiku", target_os = "illumos", target_os = "linux", target_os = "solaris")))] @@ -2960,18 +2968,21 @@ impl From for libc::passwd { pw_gid: u.gid.0, #[cfg(not(any(target_os = "android", target_os = "fuchsia", + target_os = "haiku", target_os = "illumos", target_os = "linux", target_os = "solaris")))] pw_class: u.class.into_raw(), #[cfg(not(any(target_os = "android", target_os = "fuchsia", + target_os = "haiku", target_os = "illumos", target_os = "linux", target_os = "solaris")))] pw_change: u.change, #[cfg(not(any(target_os = "android", target_os = "fuchsia", + target_os = "haiku", target_os = "illumos", target_os = "linux", target_os = "solaris")))] diff --git a/test/sys/mod.rs b/test/sys/mod.rs index 91c0aae708..768d4d302b 100644 --- a/test/sys/mod.rs +++ b/test/sys/mod.rs @@ -15,17 +15,17 @@ mod test_aio; mod test_mman; #[cfg(target_os = "linux")] mod test_signalfd; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] mod test_socket; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox")))] mod test_sockopt; #[cfg(not(target_os = "redox"))] mod test_select; #[cfg(any(target_os = "android", target_os = "linux"))] mod test_sysinfo; -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] mod test_termios; -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] mod test_ioctl; mod test_wait; mod test_uio; diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index 7dd12a21b0..847381f160 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -145,7 +145,7 @@ fn test_pread() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_pwritev() { use std::io::Read; @@ -175,7 +175,7 @@ fn test_pwritev() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_preadv() { use std::io::Write; diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs index 90d9fcf51c..058573a178 100644 --- a/test/sys/test_wait.rs +++ b/test/sys/test_wait.rs @@ -6,7 +6,7 @@ use nix::sys::wait::*; use libc::_exit; #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_wait_signal() { let _m = crate::FORK_MTX.lock(); @@ -27,7 +27,7 @@ fn test_wait_signal() { #[cfg(any( target_os = "android", target_os = "freebsd", - target_os = "haiku", + //target_os = "haiku", all(target_os = "linux", not(target_env = "uclibc")), ))] #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] @@ -63,6 +63,7 @@ fn test_wait_exit() { } } +#[cfg(not(target_os = "haiku"))] #[test] #[cfg(any( target_os = "android", diff --git a/test/test.rs b/test/test.rs index 3cac48f77f..240d6e37c4 100644 --- a/test/test.rs +++ b/test/test.rs @@ -1,6 +1,6 @@ #[macro_use] extern crate cfg_if; -#[cfg_attr(not(target_os = "redox"), macro_use)] +#[cfg_attr(not(any(target_os = "redox", target_os = "haiku")), macro_use)] extern crate nix; #[macro_use] extern crate lazy_static; @@ -26,7 +26,7 @@ mod test_net; mod test_nix_path; mod test_resource; mod test_poll; -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] mod test_pty; #[cfg(any(target_os = "android", target_os = "dragonfly", diff --git a/test/test_dir.rs b/test/test_dir.rs index 2940b6eafb..aaef34e4d6 100644 --- a/test/test_dir.rs +++ b/test/test_dir.rs @@ -50,6 +50,7 @@ fn rewind() { assert_eq!(entries2, entries3); } +#[cfg(not(target_os = "haiku"))] #[test] fn ebadf() { assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::EBADF); diff --git a/test/test_net.rs b/test/test_net.rs index 40ecd6bb75..78a09b6c63 100644 --- a/test/test_net.rs +++ b/test/test_net.rs @@ -3,9 +3,12 @@ use nix::net::if_::*; #[cfg(any(target_os = "android", target_os = "linux"))] const LOOPBACK: &[u8] = b"lo"; -#[cfg(not(any(target_os = "android", target_os = "linux")))] +#[cfg(not(any(target_os = "android", target_os = "linux", target_os = "haiku")))] const LOOPBACK: &[u8] = b"lo0"; +#[cfg(target_os = "haiku")] +const LOOPBACK: &[u8] = b"loop"; + #[test] fn test_if_nametoindex() { assert!(if_nametoindex(LOOPBACK).is_ok()); diff --git a/test/test_resource.rs b/test/test_resource.rs index c89d601e27..f96bf90341 100644 --- a/test/test_resource.rs +++ b/test/test_resource.rs @@ -1,4 +1,4 @@ -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))] +#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos", target_os = "haiku")))] use nix::sys::resource::{getrlimit, setrlimit, Resource}; /// Tests the RLIMIT_NOFILE functionality of getrlimit(), where the resource RLIMIT_NOFILE refers @@ -10,7 +10,7 @@ use nix::sys::resource::{getrlimit, setrlimit, Resource}; /// to put the new soft limit in effect, and then getrlimit() once more to ensure the limits have /// been updated. #[test] -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))] +#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos", target_os = "haiku")))] pub fn test_resource_limits_nofile() { let (mut soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); diff --git a/test/test_stat.rs b/test/test_stat.rs index 8baa6555b6..3a09eca54d 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -1,10 +1,12 @@ -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] use std::fs; use std::fs::File; #[cfg(not(target_os = "redox"))] -use std::os::unix::fs::{symlink, PermissionsExt}; +use std::os::unix::fs::{symlink}; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use std::os::unix::fs::{PermissionsExt}; use std::os::unix::prelude::AsRawFd; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] use std::time::{Duration, UNIX_EPOCH}; #[cfg(not(target_os = "redox"))] use std::path::Path; @@ -18,25 +20,30 @@ use nix::fcntl; #[cfg(not(target_os = "redox"))] use nix::errno::Errno; #[cfg(not(target_os = "redox"))] -use nix::sys::stat::{self, futimens, utimes}; +use nix::sys::stat::{self}; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use nix::sys::stat::{futimens, utimes}; use nix::sys::stat::{fchmod, stat}; #[cfg(not(target_os = "redox"))] -use nix::sys::stat::{fchmodat, utimensat, mkdirat}; +use nix::sys::stat::{fchmodat, mkdirat}; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use nix::sys::stat::{utimensat}; #[cfg(any(target_os = "linux", - target_os = "haiku", target_os = "ios", target_os = "macos", target_os = "freebsd", target_os = "netbsd"))] use nix::sys::stat::lutimes; #[cfg(not(target_os = "redox"))] -use nix::sys::stat::{FchmodatFlags, UtimensatFlags}; +use nix::sys::stat::{FchmodatFlags}; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use nix::sys::stat::{UtimensatFlags}; use nix::sys::stat::Mode; #[cfg(not(any(target_os = "netbsd", target_os = "redox")))] use nix::sys::stat::FileStat; -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] use nix::sys::time::{TimeSpec, TimeVal, TimeValLike}; #[cfg(not(target_os = "redox"))] use nix::unistd::chdir; @@ -191,7 +198,7 @@ fn test_fchmodat() { /// /// The atime and mtime are expressed with a resolution of seconds because some file systems /// (like macOS's HFS+) do not have higher granularity. -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata) { assert_eq!( Duration::new(exp_atime_sec, 0), @@ -202,7 +209,7 @@ fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata) } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_utimes() { let tempdir = tempfile::tempdir().unwrap(); let fullpath = tempdir.path().join("file"); @@ -214,7 +221,6 @@ fn test_utimes() { #[test] #[cfg(any(target_os = "linux", - target_os = "haiku", target_os = "ios", target_os = "macos", target_os = "freebsd", @@ -238,7 +244,7 @@ fn test_lutimes() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_futimens() { let tempdir = tempfile::tempdir().unwrap(); let fullpath = tempdir.path().join("file"); @@ -251,7 +257,7 @@ fn test_futimens() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_utimensat() { let _dr = crate::DirRestore::new(); let tempdir = tempfile::tempdir().unwrap(); @@ -283,7 +289,7 @@ fn test_mkdirat_success_path() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_mkdirat_success_mode() { let expected_bits = stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits(); let tempdir = tempfile::tempdir().unwrap(); @@ -312,6 +318,7 @@ fn test_mkdirat_fail() { target_os = "freebsd", target_os = "ios", target_os = "macos", + target_os = "haiku", target_os = "redox")))] fn test_mknod() { use stat::{lstat, mknod, SFlag}; @@ -331,6 +338,7 @@ fn test_mknod() { target_os = "illumos", target_os = "ios", target_os = "macos", + target_os = "haiku", target_os = "redox")))] fn test_mknodat() { use fcntl::{AtFlags, OFlag}; diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 0f56b929d3..120a9dd362 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -1,5 +1,7 @@ #[cfg(not(target_os = "redox"))] -use nix::fcntl::{self, open, readlink}; +use nix::fcntl::{self, open}; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use nix::fcntl::{readlink}; use nix::fcntl::OFlag; use nix::unistd::*; use nix::unistd::ForkResult::*; @@ -7,7 +9,7 @@ use nix::unistd::ForkResult::*; use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction}; use nix::sys::wait::*; use nix::sys::stat::{self, Mode, SFlag}; -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] use nix::pty::{posix_openpt, grantpt, unlockpt, ptsname}; use nix::errno::Errno; use std::env; @@ -18,7 +20,7 @@ use std::fs::DirBuilder; use std::fs::{self, File}; use std::io::Write; use std::os::unix::prelude::*; -#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] +#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "haiku")))] use std::path::Path; use tempfile::{tempdir, tempfile}; use libc::{_exit, mode_t, off_t}; @@ -114,7 +116,7 @@ fn test_mkfifo_directory() { #[test] #[cfg(not(any( target_os = "macos", target_os = "ios", - target_os = "android", target_os = "redox")))] + target_os = "android", target_os = "redox", target_os = "haiku")))] fn test_mkfifoat_none() { let _m = crate::CWD_LOCK.read(); @@ -131,7 +133,7 @@ fn test_mkfifoat_none() { #[test] #[cfg(not(any( target_os = "macos", target_os = "ios", - target_os = "android", target_os = "redox")))] + target_os = "android", target_os = "redox", target_os = "haiku")))] fn test_mkfifoat() { use nix::fcntl; @@ -149,7 +151,7 @@ fn test_mkfifoat() { #[test] #[cfg(not(any( target_os = "macos", target_os = "ios", - target_os = "android", target_os = "redox")))] + target_os = "android", target_os = "redox", target_os = "haiku")))] fn test_mkfifoat_directory_none() { let _m = crate::CWD_LOCK.read(); @@ -160,7 +162,7 @@ fn test_mkfifoat_directory_none() { #[test] #[cfg(not(any( target_os = "macos", target_os = "ios", - target_os = "android", target_os = "redox")))] + target_os = "android", target_os = "redox", target_os = "haiku")))] fn test_mkfifoat_directory() { // mkfifoat should fail if a directory is given let tempdir = tempdir().unwrap(); @@ -201,7 +203,7 @@ mod linux_android { #[test] // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "fuchsia")))] +#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] fn test_setgroups() { // Skip this test when not run as root as `setgroups()` requires root. skip_if_not_root!("test_setgroups"); @@ -228,6 +230,7 @@ fn test_setgroups() { target_os = "macos", target_os = "redox", target_os = "fuchsia", + target_os = "haiku", target_os = "illumos")))] fn test_initgroups() { // Skip this test when not run as root as `initgroups()` and `setgroups()` @@ -555,7 +558,7 @@ cfg_if!{ skip_if_jailed!("test_acct"); } } - } else if #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] { + } else if #[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] { macro_rules! require_acct{ () => { skip_if_not_root!("test_acct"); @@ -565,7 +568,7 @@ cfg_if!{ } #[test] -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] fn test_acct() { use tempfile::NamedTempFile; use std::process::Command; @@ -786,7 +789,7 @@ fn test_canceling_alarm() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_symlinkat() { let _m = crate::CWD_LOCK.read(); @@ -814,7 +817,7 @@ fn test_symlinkat() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_file() { let tempdir = tempdir().unwrap(); let oldfilename = "foo.txt"; @@ -835,7 +838,7 @@ fn test_linkat_file() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_olddirfd_none() { let _dr = crate::DirRestore::new(); @@ -860,7 +863,7 @@ fn test_linkat_olddirfd_none() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_newdirfd_none() { let _dr = crate::DirRestore::new(); @@ -885,7 +888,7 @@ fn test_linkat_newdirfd_none() { } #[test] -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))] +#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))] fn test_linkat_no_follow_symlink() { let _m = crate::CWD_LOCK.read(); @@ -922,7 +925,7 @@ fn test_linkat_no_follow_symlink() { } #[test] -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_linkat_follow_symlink() { let _m = crate::CWD_LOCK.read(); @@ -1033,7 +1036,13 @@ fn test_access_file_exists() { #[test] fn test_user_into_passwd() { // get the UID of the "nobody" user - let nobody = User::from_name("nobody").unwrap().unwrap(); + #[cfg(not(target_os = "haiku"))] + let test_username = "nobody"; + // "nobody" unavailable on haiku + #[cfg(target_os = "haiku")] + let test_username = "user"; + + let nobody = User::from_name(test_username).unwrap().unwrap(); let pwd: libc::passwd = nobody.into(); let _: User = (&pwd).into(); } @@ -1078,7 +1087,7 @@ fn test_setfsuid() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] fn test_ttyname() { let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); assert!(fd.as_raw_fd() > 0); @@ -1109,7 +1118,7 @@ fn test_ttyname_not_pty() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] +#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] fn test_ttyname_invalid_fd() { assert_eq!(ttyname(-1), Err(Errno::EBADF)); } From c1c1c6cfe41e597b745c4770c665b58a268cebc9 Mon Sep 17 00:00:00 2001 From: Nikita Baksalyar Date: Thu, 14 Apr 2022 01:05:30 +0100 Subject: [PATCH 101/358] Add ptrace::read_user and ptrace::write_user --- CHANGELOG.md | 2 ++ src/sys/ptrace/linux.rs | 21 +++++++++++++++++++++ test/sys/test_ptrace.rs | 19 +++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cb9d2aec5..59d25af03a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed compilation and updated support on Haiku - Added support for the `x86_64-unknown-haiku` target. (#[1703](https://github.com/nix-rust/nix/pull/1703)) +- Added `ptrace::read_user` and `ptrace::write_user` for Linux. + (#[1697](https://github.com/nix-rust/nix/pull/1697)) ### Changed diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs index 24152d7d5a..1d9b241c1f 100644 --- a/src/sys/ptrace/linux.rs +++ b/src/sys/ptrace/linux.rs @@ -481,3 +481,24 @@ pub unsafe fn write( { ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) } + +/// Reads a word from a user area at `offset`. +/// The user struct definition can be found in `/usr/include/sys/user.h`. +pub fn read_user(pid: Pid, offset: AddressType) -> Result { + ptrace_peek(Request::PTRACE_PEEKUSER, pid, offset, ptr::null_mut()) +} + +/// Writes a word to a user area at `offset`. +/// The user struct definition can be found in `/usr/include/sys/user.h`. +/// +/// # Safety +/// +/// The `data` argument is passed directly to `ptrace(2)`. Read that man page +/// for guidance. +pub unsafe fn write_user( + pid: Pid, + offset: AddressType, + data: *mut c_void) -> Result<()> +{ + ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop) +} diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs index 89c4e2ddad..8556a54845 100644 --- a/test/sys/test_ptrace.rs +++ b/test/sys/test_ptrace.rs @@ -1,3 +1,8 @@ +#[cfg(all(target_os = "linux", + any(target_arch = "x86_64", + target_arch = "x86"), + target_env = "gnu"))] +use memoffset::offset_of; use nix::errno::Errno; use nix::unistd::getpid; use nix::sys::ptrace; @@ -197,15 +202,29 @@ fn test_ptrace_syscall() { #[cfg(target_arch = "x86")] let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as libc::c_long; + // this duplicates `get_syscall_id` for the purpose of testing `ptrace::read_user`. + #[cfg(target_arch = "x86_64")] + let rax_offset = offset_of!(libc::user_regs_struct, orig_rax); + #[cfg(target_arch = "x86")] + let rax_offset = offset_of!(libc::user_regs_struct, orig_eax); + + let get_syscall_from_user_area = || { + // Find the offset of `user.regs.rax` (or `user.regs.eax` for x86) + let rax_offset = offset_of!(libc::user, regs) + rax_offset; + ptrace::read_user(child, rax_offset as _).unwrap() as libc::c_long + }; + // kill entry ptrace::syscall(child, None).unwrap(); assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); assert_eq!(get_syscall_id(), ::libc::SYS_kill); + assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill); // kill exit ptrace::syscall(child, None).unwrap(); assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); assert_eq!(get_syscall_id(), ::libc::SYS_kill); + assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill); // receive signal ptrace::syscall(child, None).unwrap(); From 598925c78fcf528c2b97f0510196b4360973ba4c Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sun, 15 May 2022 23:32:24 -0500 Subject: [PATCH 102/358] Fix nightly clippy in tests --- test/sys/test_uio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index 847381f160..fc2dfabeef 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -253,7 +253,7 @@ fn test_process_vm_readv() { } let _ = write(w, b"\0"); let _ = close(w); - loop { let _ = pause(); } + loop { pause(); } }, } } From 06f0446d907b8470dfca81bd3f2d4852ca15cab5 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 29 May 2022 13:10:50 -0600 Subject: [PATCH 103/358] Use released libc version 0.2.126 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ebd9182a53..65b4b9aed1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { git = "http://github.com/rust-lang/libc.git", rev = "cd99f681181c310abfba742aef11115d2eff03dc", features = [ "extra_traits" ] } +libc = { version = "0.2.126", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } From 6f1c748938cd7e87a52756dcbfc90e8d1c6c2848 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 29 May 2022 14:00:48 -0600 Subject: [PATCH 104/358] Clippy cleanup for latest nightly --- src/sys/time.rs | 12 ++++++------ src/sys/uio.rs | 4 ++++ src/unistd.rs | 4 ++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/sys/time.rs b/src/sys/time.rs index 1e62b76a90..c29259b24a 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -76,7 +76,7 @@ pub(crate) mod timer { /// An enumeration allowing the definition of the expiration time of an alarm, /// recurring or not. - #[derive(Debug, Clone, Copy, PartialEq)] + #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum Expiration { /// Alarm will trigger once after the time given in `TimeSpec` OneShot(TimeSpec), @@ -243,7 +243,7 @@ impl PartialOrd for TimeSpec { impl TimeValLike for TimeSpec { #[inline] fn seconds(seconds: i64) -> TimeSpec { - assert!(seconds >= TS_MIN_SECONDS && seconds <= TS_MAX_SECONDS, + assert!((TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds), "TimeSpec out of bounds; seconds={}", seconds); #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 }) @@ -270,7 +270,7 @@ impl TimeValLike for TimeSpec { #[inline] fn nanoseconds(nanoseconds: i64) -> TimeSpec { let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); - assert!(secs >= TS_MIN_SECONDS && secs <= TS_MAX_SECONDS, + assert!((TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs), "TimeSpec out of bounds"); #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 TimeSpec(timespec {tv_sec: secs as time_t, @@ -456,7 +456,7 @@ impl PartialOrd for TimeVal { impl TimeValLike for TimeVal { #[inline] fn seconds(seconds: i64) -> TimeVal { - assert!(seconds >= TV_MIN_SECONDS && seconds <= TV_MAX_SECONDS, + assert!((TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds), "TimeVal out of bounds; seconds={}", seconds); #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 }) @@ -474,7 +474,7 @@ impl TimeValLike for TimeVal { #[inline] fn microseconds(microseconds: i64) -> TimeVal { let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); - assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS, + assert!((TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), "TimeVal out of bounds"); #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 TimeVal(timeval {tv_sec: secs as time_t, @@ -487,7 +487,7 @@ impl TimeValLike for TimeVal { fn nanoseconds(nanoseconds: i64) -> TimeVal { let microseconds = nanoseconds / 1000; let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); - assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS, + assert!((TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), "TimeVal out of bounds"); #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 TimeVal(timeval {tv_sec: secs as time_t, diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 4b3851f5a1..1908973b49 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -132,6 +132,10 @@ pub struct RemoteIoVec { note = "`IoVec` is no longer used in the public interface, use `IoSlice` or `IoSliceMut` instead" )] #[repr(transparent)] +#[allow(renamed_and_removed_lints)] +#[allow(clippy::unknown_clippy_lints)] +// Clippy false positive: https://github.com/rust-lang/rust-clippy/issues/8867 +#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct IoVec(pub(crate) libc::iovec, PhantomData); diff --git a/src/unistd.rs b/src/unistd.rs index 8c42fd2b50..142aae796c 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2857,7 +2857,7 @@ feature! { /// guaranteed to conform to [`NAME_REGEX`](https://serverfault.com/a/73101/407341), which only /// contains ASCII. #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct User { /// Username pub name: String, @@ -3076,7 +3076,7 @@ impl User { /// Representation of a Group, based on `libc::group` #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Group { /// Group name pub name: String, From 51f1ef33a41477e2dc32ba857b5b591c9bda4041 Mon Sep 17 00:00:00 2001 From: Keith Koskie Date: Mon, 30 May 2022 15:53:17 -0400 Subject: [PATCH 105/358] Add infallible conversion from uid_t and gid_t Implements the following traits: * From for Uid * From for Gid --- CHANGELOG.md | 2 ++ src/unistd.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59d25af03a..89f2b268ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added `aio_writev` and `aio_readv`. (#[1713](https://github.com/nix-rust/nix/pull/1713)) +- impl `From` for `Uid` and `From` for `Gid` + (#[1727](https://github.com/nix-rust/nix/pull/1727)) - impl From for std::net::SocketAddrV4 and impl From for std::net::SocketAddrV6. (#[1711](https://github.com/nix-rust/nix/pull/1711)) diff --git a/src/unistd.rs b/src/unistd.rs index 8c42fd2b50..67037944bc 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -87,6 +87,12 @@ impl From for uid_t { } } +impl From for Uid { + fn from(uid: uid_t) -> Self { + Uid(uid) + } +} + impl fmt::Display for Uid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) @@ -131,6 +137,12 @@ impl From for gid_t { } } +impl From for Gid { + fn from(gid: gid_t) -> Self { + Gid(gid) + } +} + impl fmt::Display for Gid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) From 1520d7b316932f86beb32931c4aa86bdbb97e416 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 31 May 2022 10:02:35 -0600 Subject: [PATCH 106/358] Enable SockaddrStorage::{as_link_addr, as_link_addr_mut} on Linux. This was an oversight from #1684. Fixes #1728 --- CHANGELOG.md | 5 +++++ src/sys/socket/addr.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89f2b268ea..9f40e4089f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,11 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1713](https://github.com/nix-rust/nix/pull/1713)) ### Fixed + +- Enabled `SockaddrStorage::{as_link_addr, as_link_addr_mut}` for Linux-like + operating systems. + (#[1729](https://github.com/nix-rust/nix/pull/1729)) + ### Removed - Removed support for resubmitting partially complete `lio_listio` operations. diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 6d38f26c31..8de501a413 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1514,6 +1514,14 @@ impl SockaddrStorage { accessors!{as_alg_addr, as_alg_addr_mut, AlgAddr, AddressFamily::Alg, libc::sockaddr_alg, alg} + #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "linux"))] + #[cfg(feature = "net")] + accessors!{ + as_link_addr, as_link_addr_mut, LinkAddr, + AddressFamily::Packet, libc::sockaddr_ll, dl} + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -2682,6 +2690,25 @@ mod tests { format!("{}", la); } + #[cfg(all( + any(target_os = "android", + target_os = "fuchsia", + target_os = "linux"), + target_endian = "little" + ))] + #[test] + fn linux_loopback() { + let bytes = [17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0]; + let sa = bytes.as_ptr() as *const libc::sockaddr; + let len = None; + let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); + assert_eq!(sock_addr.family(), Some(AddressFamily::Packet)); + match sock_addr.as_link_addr() { + Some(dl) => assert_eq!(dl.addr(), Some([1, 2, 3, 4, 5, 6])), + None => panic!("Can't unwrap sockaddr storage") + } + } + #[cfg(any(target_os = "ios", target_os = "macos" ))] From 0ac338b74445bf55ffd70d6bc85f4339d151f6fc Mon Sep 17 00:00:00 2001 From: Alex Rawson Date: Tue, 31 May 2022 17:51:45 -0500 Subject: [PATCH 107/358] Ignore doctests for unexported macros Due to rust-lang/rust#97030, cargo test will fail to doctest macros unless they are exported, breaking the examples for libc_bitflags! and libc_enum!. Adds `ignore` to the examples for these macros to stop tests from failing. --- src/macros.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 018534fa67..99e0de8866 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -19,7 +19,7 @@ macro_rules! feature { /// The `libc` crate must be in scope with the name `libc`. /// /// # Example -/// ``` +/// ```ignore /// libc_bitflags!{ /// pub struct ProtFlags: libc::c_int { /// PROT_NONE; @@ -39,7 +39,7 @@ macro_rules! feature { /// various flags have different types, so we cast the broken ones to the right /// type. /// -/// ``` +/// ```ignore /// libc_bitflags!{ /// pub struct SaFlags: libc::c_ulong { /// SA_NOCLDSTOP as libc::c_ulong; @@ -80,7 +80,7 @@ macro_rules! libc_bitflags { /// The `libc` crate must be in scope with the name `libc`. /// /// # Example -/// ``` +/// ```ignore /// libc_enum!{ /// pub enum ProtFlags { /// PROT_NONE, From 80f8320ffd9caf64542916a63f986ba1f95e4613 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Mon, 6 Jun 2022 18:50:19 -0500 Subject: [PATCH 108/358] Cleanup cfg blocks Remove obsolete references to target_env = wasi, target_os = nacl, target_os = osx, and a typo'd target_os = fushsia that didn't compile when fixed. - target_env = wasi is dead: https://github.com/rust-lang/rust/pull/60117 - target_os = nacl is dead: https://github.com/rust-lang/rust/pull/45041 - target_os = osx is dead, but I can't find a link. --- src/env.rs | 1 - src/fcntl.rs | 6 +++--- src/lib.rs | 1 - src/net/if_.rs | 3 +-- src/sys/socket/sockopt.rs | 6 ++---- test/sys/test_sockopt.rs | 3 +-- test/test_fcntl.rs | 4 ++-- 7 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/env.rs b/src/env.rs index bcae28713e..95177a1d2a 100644 --- a/src/env.rs +++ b/src/env.rs @@ -42,7 +42,6 @@ pub unsafe fn clearenv() -> std::result::Result<(), ClearEnvError> { cfg_if! { if #[cfg(any(target_os = "fuchsia", target_os = "wasi", - target_env = "wasi", target_env = "uclibc", target_os = "linux", target_os = "android", diff --git a/src/fcntl.rs b/src/fcntl.rs index 7319302d2a..6f9fa15d3f 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -20,7 +20,7 @@ use crate::{ target_os = "android", target_os = "emscripten", target_os = "fuchsia", - any(target_os = "wasi", target_env = "wasi"), + target_os = "wasi", target_env = "uclibc", target_os = "freebsd" ))] @@ -828,7 +828,7 @@ pub fn fspacectl_all(fd: RawFd, offset: libc::off_t, len: libc::off_t) target_os = "android", target_os = "emscripten", target_os = "fuchsia", - any(target_os = "wasi", target_env = "wasi"), + target_os = "wasi", target_env = "uclibc", target_os = "freebsd" ))] @@ -877,7 +877,7 @@ mod posix_fadvise { target_os = "dragonfly", target_os = "emscripten", target_os = "fuchsia", - any(target_os = "wasi", target_env = "wasi"), + target_os = "wasi", target_os = "freebsd" ))] pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<()> { diff --git a/src/lib.rs b/src/lib.rs index d4dcbc4ceb..fb6774051a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,7 +116,6 @@ feature! { } #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "fushsia", target_os = "linux", target_os = "netbsd"))] feature! { diff --git a/src/net/if_.rs b/src/net/if_.rs index 535d6c2269..045efad9cc 100644 --- a/src/net/if_.rs +++ b/src/net/if_.rs @@ -103,8 +103,7 @@ libc_bitflags!( target_os = "freebsd", target_os = "macos", target_os = "netbsd", - target_os = "openbsd", - target_os = "osx"))] + target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] IFF_SIMPLEX; /// Supports multicast. (see diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 73d154065f..33c86cd272 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -380,8 +380,7 @@ sockopt_impl!( #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "linux", - target_os = "nacl"))] + target_os = "linux"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -993,8 +992,7 @@ mod test { } #[cfg(any(target_os = "freebsd", - target_os = "linux", - target_os = "nacl"))] + target_os = "linux"))] #[test] fn can_get_listen_on_tcp_socket() { use super::super::*; diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 4f75e17846..a17bc09f68 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -170,8 +170,7 @@ fn test_so_tcp_keepalive() { #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "linux", - target_os = "nacl"))] { + target_os = "linux"))] { let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap(); setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap(); assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1); diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index ebfc43e25f..5f2e53bd9b 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -462,7 +462,7 @@ mod linux_android { target_os = "android", target_os = "emscripten", target_os = "fuchsia", - any(target_os = "wasi", target_env = "wasi"), + target_os = "wasi", target_env = "uclibc", target_os = "freebsd"))] mod test_posix_fadvise { @@ -495,7 +495,7 @@ mod test_posix_fadvise { target_os = "dragonfly", target_os = "emscripten", target_os = "fuchsia", - any(target_os = "wasi", target_env = "wasi"), + target_os = "wasi", target_os = "freebsd"))] mod test_posix_fallocate { From 5a122f83a045b915695283ccc9f1a69a8c824751 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 7 Jun 2022 15:52:03 +0100 Subject: [PATCH 109/358] Fix socket address family check for VsockAddr::from_raw. --- src/sys/socket/addr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 8de501a413..ad9e1bcb1b 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -2566,7 +2566,7 @@ pub mod vsock { return None; } } - if (*addr).sa_family as i32 != libc::AF_INET6 as i32 { + if (*addr).sa_family as i32 != libc::AF_VSOCK as i32 { return None; } Some(VsockAddr(*(addr as *const libc::sockaddr_vm))) From d3cc30c3daa1171d06e92ce83c24554a4f28fc46 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 7 Jun 2022 15:52:49 +0100 Subject: [PATCH 110/358] Fix socket address family check for SysControlAddr::from_raw. --- src/sys/socket/addr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index ad9e1bcb1b..9d5c61ce32 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -2259,7 +2259,7 @@ pub mod sys_control { return None; } } - if (*addr).sa_family as i32 != libc::AF_INET6 as i32 { + if (*addr).sa_family as i32 != libc::AF_SYSTEM as i32 { return None; } Some(SysControlAddr(*(addr as *const libc::sockaddr_ctl))) From ccf1b804551c6e09ad8aac24f6e39989a618fe22 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 7 Jun 2022 16:22:03 +0100 Subject: [PATCH 111/358] Mention fix in changelog. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f40e4089f..96befe3fd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Enabled `SockaddrStorage::{as_link_addr, as_link_addr_mut}` for Linux-like operating systems. (#[1729](https://github.com/nix-rust/nix/pull/1729)) +- Fixed `SockaddrLike::from_raw` implementations for `VsockAddr` and + `SysControlAddr`. + (#[1736](https://github.com/nix-rust/nix/pull/1736)) ### Removed From c8a9cf33514430b5de9e73bcaee21cb6e2dbd1c6 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 7 Jun 2022 20:10:46 -0600 Subject: [PATCH 112/358] Fix the test_acct test It has never actually executed its command, so the only reason that it ever worked is that on most systems there are usually processes starting and exiting all the time. --- test/test_unistd.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 120a9dd362..b3b69bbb0e 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -583,7 +583,10 @@ fn test_acct() { acct::enable(path).unwrap(); loop { - Command::new("echo").arg("Hello world"); + Command::new("echo") + .arg("Hello world") + .output() + .unwrap(); let len = fs::metadata(path).unwrap().len(); if len > 0 { break; } thread::sleep(time::Duration::from_millis(10)); From c3081e4896344dbf0c27103a60c90eaa8d35715e Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Wed, 8 Jun 2022 09:52:53 +0200 Subject: [PATCH 113/358] ppoll: make sigmask parameter optional ppoll(2) supports 'sigmask' as NULL. In that case no signal mask manipulation is performed. Let's make `sigmask` parameter of `nix::poll::ppoll` optional to allow that behaviour. Signed-off-by: Stefano Garzarella --- CHANGELOG.md | 2 ++ src/poll.rs | 8 ++++++-- test/test_poll.rs | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f40e4089f..e338d9aa45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Changes the type of the `priority` arguments to `i32`. * Changes the return type of `aio_return` to `usize`. (#[1713](https://github.com/nix-rust/nix/pull/1713)) +- `nix::poll::ppoll`: `sigmask` parameter is now optional. + (#[1739](https://github.com/nix-rust/nix/pull/1739)) ### Fixed diff --git a/src/poll.rs b/src/poll.rs index 6d332b0350..3004d24c37 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -151,20 +151,24 @@ feature! { /// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it /// with the `sigmask` argument. If you want `ppoll` to block indefinitely, /// specify `None` as `timeout` (it is like `timeout = -1` for `poll`). +/// If `sigmask` is `None`, then no signal mask manipulation is performed, +/// so in that case `ppoll` differs from `poll` only in the precision of the +/// timeout argument. /// #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] pub fn ppoll( fds: &mut [PollFd], timeout: Option, - sigmask: crate::sys::signal::SigSet + sigmask: Option ) -> Result { let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); + let sigmask = sigmask.as_ref().map_or(core::ptr::null(), |r| r.as_ref()); let res = unsafe { libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd, fds.len() as libc::nfds_t, timeout, - sigmask.as_ref()) + sigmask) }; Errno::result(res) } diff --git a/test/test_poll.rs b/test/test_poll.rs index e4b369f3f2..120e8e56f5 100644 --- a/test/test_poll.rs +++ b/test/test_poll.rs @@ -53,14 +53,14 @@ fn test_ppoll() { // Poll an idle pipe. Should timeout let sigset = SigSet::empty(); - let nfds = loop_while_eintr!(ppoll(&mut fds, Some(timeout), sigset)); + let nfds = loop_while_eintr!(ppoll(&mut fds, Some(timeout), Some(sigset))); assert_eq!(nfds, 0); assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN)); write(w, b".").unwrap(); // Poll a readable pipe. Should return an event. - let nfds = ppoll(&mut fds, Some(timeout), SigSet::empty()).unwrap(); + let nfds = ppoll(&mut fds, Some(timeout), None).unwrap(); assert_eq!(nfds, 1); assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); } From 67552057828206621ba6a69cb1ef272200d5ddc6 Mon Sep 17 00:00:00 2001 From: Costin-Robert Sin Date: Sun, 19 Jun 2022 02:49:07 +0300 Subject: [PATCH 114/358] Fix typo by adding a semicolon Signed-off-by: Costin-Robert Sin --- src/unistd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unistd.rs b/src/unistd.rs index 2a8389ef7e..21fc39e697 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -608,7 +608,7 @@ fn reserve_double_buffer_size(buf: &mut Vec, limit: usize) -> Result<()> { use std::cmp::min; if buf.capacity() >= limit { - return Err(Errno::ERANGE) + return Err(Errno::ERANGE); } let capacity = min(buf.capacity() * 2, limit); From a240d82880db4edb0a8e0bb801e07ae94981c689 Mon Sep 17 00:00:00 2001 From: Costin-Robert Sin Date: Sun, 19 Jun 2022 02:52:08 +0300 Subject: [PATCH 115/358] Minimise the use of the unsafe block inside pipe function Some of the operations inside the pipe function are safe and should not be included inside an unsafe block. Signed-off-by: Costin-Robert Sin --- src/unistd.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 21fc39e697..5d8a56378d 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -1118,15 +1118,13 @@ pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result std::result::Result<(RawFd, RawFd), Error> { - unsafe { - let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); + let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); - let res = libc::pipe(fds.as_mut_ptr() as *mut c_int); + let res = unsafe { libc::pipe(fds.as_mut_ptr() as *mut c_int) }; - Error::result(res)?; + Error::result(res)?; - Ok((fds.assume_init()[0], fds.assume_init()[1])) - } + unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } } feature! { From 9313a189d8b80be9685d110b51be41bbd67abdfc Mon Sep 17 00:00:00 2001 From: Gustavo Noronha Silva Date: Sat, 18 Jun 2022 21:34:59 -0300 Subject: [PATCH 116/358] Add getrusage wrapper Includes an enum to specify what to get resource usage for, and a new struct that provides a more readable view into libc::rusage, including using TimeVal for user and system CPU time. --- CHANGELOG.md | 2 + src/sys/resource.rs | 186 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 182 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 580bcbcaee..b7c3df5f53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1703](https://github.com/nix-rust/nix/pull/1703)) - Added `ptrace::read_user` and `ptrace::write_user` for Linux. (#[1697](https://github.com/nix-rust/nix/pull/1697)) +- Added `getrusage` and helper types `UsageWho` and `Usage` + (#[1747](https://github.com/nix-rust/nix/pull/1747)) ### Changed diff --git a/src/sys/resource.rs b/src/sys/resource.rs index 76ceaf5b90..e9a11d95d4 100644 --- a/src/sys/resource.rs +++ b/src/sys/resource.rs @@ -1,7 +1,9 @@ //! Configure the process resource limits. use cfg_if::cfg_if; +use libc::{c_int, c_long, rusage}; use crate::errno::Errno; +use crate::sys::time::TimeVal; use crate::Result; pub use libc::rlim_t; use std::mem; @@ -19,7 +21,7 @@ cfg_if! { target_os = "dragonfly", all(target_os = "linux", not(target_env = "gnu")) ))]{ - use libc::{c_int, rlimit}; + use libc::rlimit; } } @@ -242,11 +244,7 @@ pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> { /// [`Resource`]: enum.Resource.html /// /// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`. -pub fn setrlimit( - resource: Resource, - soft_limit: rlim_t, - hard_limit: rlim_t, -) -> Result<()> { +pub fn setrlimit(resource: Resource, soft_limit: rlim_t, hard_limit: rlim_t) -> Result<()> { let new_rlim = rlimit { rlim_cur: soft_limit, rlim_max: hard_limit, @@ -261,3 +259,179 @@ pub fn setrlimit( Errno::result(res).map(drop) } + +libc_enum! { + /// Whose resource usage should be returned by [`getrusage`]. + #[repr(i32)] + #[non_exhaustive] + pub enum UsageWho { + /// Resource usage for the current process. + RUSAGE_SELF, + + /// Resource usage for all the children that have terminated and been waited for. + RUSAGE_CHILDREN, + + #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + /// Resource usage for the calling thread. + RUSAGE_THREAD, + } +} + +/// Output of `getrusage` with information about resource usage. Some of the fields +/// may be unused in some platforms, and will be always zeroed out. See their manuals +/// for details. +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct Usage(rusage); + +impl AsRef for Usage { + fn as_ref(&self) -> &rusage { + &self.0 + } +} + +impl AsMut for Usage { + fn as_mut(&mut self) -> &mut rusage { + &mut self.0 + } +} + +impl Usage { + /// Total amount of time spent executing in user mode. + pub fn user_time(&self) -> TimeVal { + TimeVal::from(self.0.ru_utime) + } + + /// Total amount of time spent executing in kernel mode. + pub fn system_time(&self) -> TimeVal { + TimeVal::from(self.0.ru_stime) + } + + /// The resident set size at its peak, in kilobytes. + pub fn max_rss(&self) -> c_long { + self.0.ru_maxrss + } + + /// Integral value expressed in kilobytes times ticks of execution indicating + /// the amount of text memory shared with other processes. + pub fn shared_integral(&self) -> c_long { + self.0.ru_ixrss + } + + /// Integral value expressed in kilobytes times ticks of execution indicating + /// the amount of unshared memory used by data. + pub fn unshared_data_integral(&self) -> c_long { + self.0.ru_idrss + } + + /// Integral value expressed in kilobytes times ticks of execution indicating + /// the amount of unshared memory used for stack space. + pub fn unshared_stack_integral(&self) -> c_long { + self.0.ru_isrss + } + + /// Number of page faults that were served without resorting to I/O, with pages + /// that have been allocated previously by the kernel. + pub fn minor_page_faults(&self) -> c_long { + self.0.ru_minflt + } + + /// Number of page faults that were served through I/O (i.e. swap). + pub fn major_page_faults(&self) -> c_long { + self.0.ru_majflt + } + + /// Number of times all of the memory was fully swapped out. + pub fn full_swaps(&self) -> c_long { + self.0.ru_nswap + } + + /// Number of times a read was done from a block device. + pub fn block_reads(&self) -> c_long { + self.0.ru_inblock + } + + /// Number of times a write was done to a block device. + pub fn block_writes(&self) -> c_long { + self.0.ru_oublock + } + + /// Number of IPC messages sent. + pub fn ipc_sends(&self) -> c_long { + self.0.ru_msgsnd + } + + /// Number of IPC messages received. + pub fn ipc_receives(&self) -> c_long { + self.0.ru_msgrcv + } + + /// Number of signals received. + pub fn signals(&self) -> c_long { + self.0.ru_nsignals + } + + /// Number of times a context switch was voluntarily invoked. + pub fn voluntary_context_switches(&self) -> c_long { + self.0.ru_nvcsw + } + + /// Number of times a context switch was imposed by the kernel (usually due to + /// time slice expiring or preemption by a higher priority process). + pub fn involuntary_context_switches(&self) -> c_long { + self.0.ru_nivcsw + } +} + +/// Get usage information for a process, its children or the current thread +/// +/// Real time information can be obtained for either the current process or (in some +/// systems) thread, but information about children processes is only provided for +/// those that have terminated and been waited for (see [`super::wait::wait`]). +/// +/// Some information may be missing depending on the platform, and the way information +/// is provided for children may also vary. Check the manuals for details. +/// +/// # References +/// +/// * [getrusage(2)](https://pubs.opengroup.org/onlinepubs/009696699/functions/getrusage.html) +/// * [Linux](https://man7.org/linux/man-pages/man2/getrusage.2.html) +/// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=getrusage) +/// * [NetBSD](https://man.netbsd.org/getrusage.2) +/// * [MacOS](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getrusage.2.html) +/// +/// [`UsageWho`]: enum.UsageWho.html +/// +/// Note: `getrusage` provides a safe wrapper to libc's [`libc::getrusage`]. +pub fn getrusage(who: UsageWho) -> Result { + unsafe { + let mut rusage = mem::MaybeUninit::::uninit(); + let res = libc::getrusage(who as c_int, rusage.as_mut_ptr()); + Errno::result(res).map(|_| Usage(rusage.assume_init())) + } +} + +#[cfg(test)] +mod test { + use super::{getrusage, UsageWho}; + + #[test] + pub fn test_self_cpu_time() { + // Make sure some CPU time is used. + let mut numbers: Vec = (1..1_000_000).collect(); + numbers.iter_mut().for_each(|item| *item *= 2); + + // FIXME: this is here to help ensure the compiler does not optimize the whole + // thing away. Replace the assert with test::black_box once stabilized. + assert_eq!(numbers[100..200].iter().sum::(), 30_100); + + let usage = getrusage(UsageWho::RUSAGE_SELF).expect("Failed to call getrusage for SELF"); + let rusage = usage.as_ref(); + + let user = usage.user_time(); + assert!(user.tv_sec() > 0 || user.tv_usec() > 0); + assert_eq!(user.tv_sec(), rusage.ru_utime.tv_sec); + assert_eq!(user.tv_usec(), rusage.ru_utime.tv_usec); + } +} From 8f08a69c28fad5ee875d69e4c8a1b8eed2203cb4 Mon Sep 17 00:00:00 2001 From: Costin-Robert Sin Date: Sun, 19 Jun 2022 15:28:40 +0300 Subject: [PATCH 117/358] Add format test to CI To enforce uniformity for all PRs, the CI checks if the code is formatted rigth using `cargo fmt` tool. Signed-off-by: Costin-Robert Sin --- .cirrus.yml | 8 ++++++++ bors.toml | 1 + rustfmt.toml | 1 + 3 files changed, 10 insertions(+) create mode 100644 rustfmt.toml diff --git a/.cirrus.yml b/.cirrus.yml index ae184f86e4..ee150f1931 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -320,3 +320,11 @@ task: check_script: - cargo check before_cache_script: rm -rf $CARGO_HOME/registry/index + +# Tasks that checks if the code is formatted right using `cargo fmt` tool +task: + name: Rust Formatter + container: + image: rust:latest + setup_script: rustup +$TOOLCHAIN component add rustfmt + test_script: $TOOL +$TOOLCHAIN fmt --all -- --check \ No newline at end of file diff --git a/bors.toml b/bors.toml index 3936888423..b6f81c33af 100644 --- a/bors.toml +++ b/bors.toml @@ -33,6 +33,7 @@ status = [ "OpenBSD x86_64", "Redox x86_64", "Rust Stable", + "Rust Formatter", "iOS aarch64", "iOS x86_64", "Illumos", diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000000..5c8d9318b3 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +max_width = 80 \ No newline at end of file From 3e6cb639f0d9afde57d9cc03526c2e488641231b Mon Sep 17 00:00:00 2001 From: Costin-Robert Sin Date: Tue, 21 Jun 2022 15:36:05 +0300 Subject: [PATCH 118/358] Fix all formating problems to pass CI formating test Signed-off-by: Costin-Robert Sin --- src/errno.rs | 2956 ++++++++++++++++++++--------------- src/fcntl.rs | 15 +- src/lib.rs | 61 +- src/sys/ioctl/bsd.rs | 38 +- src/sys/ioctl/linux.rs | 64 +- src/sys/ioctl/mod.rs | 52 +- src/sys/mod.rs | 88 +- src/sys/signal.rs | 379 ++--- src/sys/sysinfo.rs | 6 +- src/sys/time.rs | 193 ++- src/unistd.rs | 82 +- test/common/mod.rs | 31 +- test/sys/mod.rs | 48 +- test/sys/test_aio.rs | 26 +- test/sys/test_aio_drop.rs | 30 +- test/sys/test_epoll.rs | 7 +- test/sys/test_inotify.rs | 16 +- test/sys/test_ioctl.rs | 83 +- test/sys/test_mman.rs | 118 +- test/sys/test_ptrace.rs | 127 +- test/sys/test_select.rs | 5 +- test/sys/test_signal.rs | 50 +- test/sys/test_signalfd.rs | 2 +- test/sys/test_socket.rs | 1050 ++++++++----- test/sys/test_sockopt.rs | 227 ++- test/sys/test_sysinfo.rs | 12 +- test/sys/test_termios.rs | 26 +- test/sys/test_timerfd.rs | 18 +- test/sys/test_uio.rs | 98 +- test/sys/test_wait.rs | 137 +- test/test.rs | 62 +- test/test_dir.rs | 18 +- test/test_fcntl.rs | 156 +- test/test_kmod/mod.rs | 58 +- test/test_mount.rs | 167 +- test/test_mq.rs | 49 +- test/test_net.rs | 6 +- test/test_nix_path.rs | 1 + test/test_nmount.rs | 20 +- test/test_poll.rs | 18 +- test/test_pty.rs | 28 +- test/test_ptymaster_drop.rs | 2 +- test/test_resource.rs | 17 +- test/test_sched.rs | 5 +- test/test_sendfile.rs | 42 +- test/test_stat.rs | 223 ++- test/test_timer.rs | 25 +- test/test_unistd.rs | 367 +++-- 48 files changed, 4348 insertions(+), 2961 deletions(-) diff --git a/src/errno.rs b/src/errno.rs index 759b649d8f..912fb94f55 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -1,8 +1,8 @@ +use crate::{Error, Result}; use cfg_if::cfg_if; use libc::{c_int, c_void}; use std::convert::TryFrom; -use std::{fmt, io, error}; -use crate::{Error, Result}; +use std::{error, fmt, io}; pub use self::consts::*; @@ -47,9 +47,7 @@ fn clear() { /// Returns the platform-specific value of errno pub fn errno() -> i32 { - unsafe { - (*errno_location()) as i32 - } + unsafe { (*errno_location()) as i32 } } impl Errno { @@ -63,29 +61,20 @@ impl Errno { /// let e = Error::from(Errno::EPERM); /// assert_eq!(Some(Errno::EPERM), e.as_errno()); /// ``` - #[deprecated( - since = "0.22.0", - note = "It's a no-op now; just delete it." - )] + #[deprecated(since = "0.22.0", note = "It's a no-op now; just delete it.")] pub const fn as_errno(self) -> Option { Some(self) } /// Create a nix Error from a given errno - #[deprecated( - since = "0.22.0", - note = "It's a no-op now; just delete it." - )] + #[deprecated(since = "0.22.0", note = "It's a no-op now; just delete it.")] #[allow(clippy::wrong_self_convention)] // False positive pub fn from_errno(errno: Errno) -> Error { errno } /// Create a new invalid argument error (`EINVAL`) - #[deprecated( - since = "0.22.0", - note = "Use Errno::EINVAL instead" - )] + #[deprecated(since = "0.22.0", note = "Use Errno::EINVAL instead")] pub const fn invalid_argument() -> Error { Errno::EINVAL } @@ -122,10 +111,7 @@ impl Errno { /// In older versions of Nix, `Error::Sys` was an enum variant. Now it's a /// function, which is compatible with most of the former use cases of the /// enum variant. But you should use `Error(Errno::...)` instead. - #[deprecated( - since = "0.22.0", - note = "Use Errno::... instead" - )] + #[deprecated(since = "0.22.0", note = "Use Errno::... instead")] #[allow(non_snake_case)] #[inline] pub const fn Sys(errno: Errno) -> Error { @@ -140,23 +126,33 @@ pub trait ErrnoSentinel: Sized { } impl ErrnoSentinel for isize { - fn sentinel() -> Self { -1 } + fn sentinel() -> Self { + -1 + } } impl ErrnoSentinel for i32 { - fn sentinel() -> Self { -1 } + fn sentinel() -> Self { + -1 + } } impl ErrnoSentinel for i64 { - fn sentinel() -> Self { -1 } + fn sentinel() -> Self { + -1 + } } impl ErrnoSentinel for *mut c_void { - fn sentinel() -> Self { -1isize as *mut c_void } + fn sentinel() -> Self { + -1isize as *mut c_void + } } impl ErrnoSentinel for libc::sighandler_t { - fn sentinel() -> Self { libc::SIG_ERR } + fn sentinel() -> Self { + libc::SIG_ERR + } } impl error::Error for Errno {} @@ -177,9 +173,7 @@ impl TryFrom for Errno { type Error = io::Error; fn try_from(ioerror: io::Error) -> std::result::Result { - ioerror.raw_os_error() - .map(Errno::from_i32) - .ok_or(ioerror) + ioerror.raw_os_error().map(Errno::from_i32).ok_or(ioerror) } } @@ -190,736 +184,1117 @@ fn last() -> Errno { fn desc(errno: Errno) -> &'static str { use self::Errno::*; match errno { - UnknownErrno => "Unknown errno", - EPERM => "Operation not permitted", - ENOENT => "No such file or directory", - ESRCH => "No such process", - EINTR => "Interrupted system call", - EIO => "I/O error", - ENXIO => "No such device or address", - E2BIG => "Argument list too long", - ENOEXEC => "Exec format error", - EBADF => "Bad file number", - ECHILD => "No child processes", - EAGAIN => "Try again", - ENOMEM => "Out of memory", - EACCES => "Permission denied", - EFAULT => "Bad address", + UnknownErrno => "Unknown errno", + EPERM => "Operation not permitted", + ENOENT => "No such file or directory", + ESRCH => "No such process", + EINTR => "Interrupted system call", + EIO => "I/O error", + ENXIO => "No such device or address", + E2BIG => "Argument list too long", + ENOEXEC => "Exec format error", + EBADF => "Bad file number", + ECHILD => "No child processes", + EAGAIN => "Try again", + ENOMEM => "Out of memory", + EACCES => "Permission denied", + EFAULT => "Bad address", #[cfg(not(target_os = "haiku"))] - ENOTBLK => "Block device required", - EBUSY => "Device or resource busy", - EEXIST => "File exists", - EXDEV => "Cross-device link", - ENODEV => "No such device", - ENOTDIR => "Not a directory", - EISDIR => "Is a directory", - EINVAL => "Invalid argument", - ENFILE => "File table overflow", - EMFILE => "Too many open files", - ENOTTY => "Not a typewriter", - ETXTBSY => "Text file busy", - EFBIG => "File too large", - ENOSPC => "No space left on device", - ESPIPE => "Illegal seek", - EROFS => "Read-only file system", - EMLINK => "Too many links", - EPIPE => "Broken pipe", - EDOM => "Math argument out of domain of func", - ERANGE => "Math result not representable", - EDEADLK => "Resource deadlock would occur", - ENAMETOOLONG => "File name too long", - ENOLCK => "No record locks available", - ENOSYS => "Function not implemented", - ENOTEMPTY => "Directory not empty", - ELOOP => "Too many symbolic links encountered", - ENOMSG => "No message of desired type", - EIDRM => "Identifier removed", - EINPROGRESS => "Operation now in progress", - EALREADY => "Operation already in progress", - ENOTSOCK => "Socket operation on non-socket", - EDESTADDRREQ => "Destination address required", - EMSGSIZE => "Message too long", - EPROTOTYPE => "Protocol wrong type for socket", - ENOPROTOOPT => "Protocol not available", + ENOTBLK => "Block device required", + EBUSY => "Device or resource busy", + EEXIST => "File exists", + EXDEV => "Cross-device link", + ENODEV => "No such device", + ENOTDIR => "Not a directory", + EISDIR => "Is a directory", + EINVAL => "Invalid argument", + ENFILE => "File table overflow", + EMFILE => "Too many open files", + ENOTTY => "Not a typewriter", + ETXTBSY => "Text file busy", + EFBIG => "File too large", + ENOSPC => "No space left on device", + ESPIPE => "Illegal seek", + EROFS => "Read-only file system", + EMLINK => "Too many links", + EPIPE => "Broken pipe", + EDOM => "Math argument out of domain of func", + ERANGE => "Math result not representable", + EDEADLK => "Resource deadlock would occur", + ENAMETOOLONG => "File name too long", + ENOLCK => "No record locks available", + ENOSYS => "Function not implemented", + ENOTEMPTY => "Directory not empty", + ELOOP => "Too many symbolic links encountered", + ENOMSG => "No message of desired type", + EIDRM => "Identifier removed", + EINPROGRESS => "Operation now in progress", + EALREADY => "Operation already in progress", + ENOTSOCK => "Socket operation on non-socket", + EDESTADDRREQ => "Destination address required", + EMSGSIZE => "Message too long", + EPROTOTYPE => "Protocol wrong type for socket", + ENOPROTOOPT => "Protocol not available", EPROTONOSUPPORT => "Protocol not supported", #[cfg(not(target_os = "haiku"))] ESOCKTNOSUPPORT => "Socket type not supported", #[cfg(not(target_os = "haiku"))] - EPFNOSUPPORT => "Protocol family not supported", + EPFNOSUPPORT => "Protocol family not supported", #[cfg(not(target_os = "haiku"))] - EAFNOSUPPORT => "Address family not supported by protocol", - EADDRINUSE => "Address already in use", - EADDRNOTAVAIL => "Cannot assign requested address", - ENETDOWN => "Network is down", - ENETUNREACH => "Network is unreachable", - ENETRESET => "Network dropped connection because of reset", - ECONNABORTED => "Software caused connection abort", - ECONNRESET => "Connection reset by peer", - ENOBUFS => "No buffer space available", - EISCONN => "Transport endpoint is already connected", - ENOTCONN => "Transport endpoint is not connected", - ESHUTDOWN => "Cannot send after transport endpoint shutdown", + EAFNOSUPPORT => "Address family not supported by protocol", + EADDRINUSE => "Address already in use", + EADDRNOTAVAIL => "Cannot assign requested address", + ENETDOWN => "Network is down", + ENETUNREACH => "Network is unreachable", + ENETRESET => "Network dropped connection because of reset", + ECONNABORTED => "Software caused connection abort", + ECONNRESET => "Connection reset by peer", + ENOBUFS => "No buffer space available", + EISCONN => "Transport endpoint is already connected", + ENOTCONN => "Transport endpoint is not connected", + ESHUTDOWN => "Cannot send after transport endpoint shutdown", #[cfg(not(target_os = "haiku"))] - ETOOMANYREFS => "Too many references: cannot splice", - ETIMEDOUT => "Connection timed out", - ECONNREFUSED => "Connection refused", - EHOSTDOWN => "Host is down", - EHOSTUNREACH => "No route to host", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ECHRNG => "Channel number out of range", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EL2NSYNC => "Level 2 not synchronized", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EL3HLT => "Level 3 halted", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EL3RST => "Level 3 reset", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ELNRNG => "Link number out of range", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EUNATCH => "Protocol driver not attached", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ENOCSI => "No CSI structure available", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EL2HLT => "Level 2 halted", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EBADE => "Invalid exchange", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EBADR => "Invalid request descriptor", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EXFULL => "Exchange full", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ENOANO => "No anode", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EBADRQC => "Invalid request code", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EBADSLT => "Invalid slot", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EBFONT => "Bad font file format", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ENOSTR => "Device not a stream", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ENODATA => "No data available", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ETIME => "Timer expired", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ENOSR => "Out of streams resources", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ENONET => "Machine is not on the network", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ENOPKG => "Package not installed", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EREMOTE => "Object is remote", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ENOLINK => "Link has been severed", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EADV => "Advertise error", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ESRMNT => "Srmount error", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ECOMM => "Communication error on send", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EPROTO => "Protocol error", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EMULTIHOP => "Multihop attempted", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - EDOTDOT => "RFS specific error", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - EBADMSG => "Not a data message", + ETOOMANYREFS => "Too many references: cannot splice", + ETIMEDOUT => "Connection timed out", + ECONNREFUSED => "Connection refused", + EHOSTDOWN => "Host is down", + EHOSTUNREACH => "No route to host", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ECHRNG => "Channel number out of range", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EL2NSYNC => "Level 2 not synchronized", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EL3HLT => "Level 3 halted", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EL3RST => "Level 3 reset", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ELNRNG => "Link number out of range", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EUNATCH => "Protocol driver not attached", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOCSI => "No CSI structure available", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EL2HLT => "Level 2 halted", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EBADE => "Invalid exchange", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EBADR => "Invalid request descriptor", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EXFULL => "Exchange full", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOANO => "No anode", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EBADRQC => "Invalid request code", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EBADSLT => "Invalid slot", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EBFONT => "Bad font file format", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOSTR => "Device not a stream", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENODATA => "No data available", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ETIME => "Timer expired", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOSR => "Out of streams resources", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENONET => "Machine is not on the network", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOPKG => "Package not installed", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EREMOTE => "Object is remote", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOLINK => "Link has been severed", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EADV => "Advertise error", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ESRMNT => "Srmount error", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ECOMM => "Communication error on send", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EPROTO => "Protocol error", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EMULTIHOP => "Multihop attempted", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EDOTDOT => "RFS specific error", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EBADMSG => "Not a data message", + + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + EBADMSG => "Trying to read unreadable message", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "haiku" + ))] + EOVERFLOW => "Value too large for defined data type", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ENOTUNIQ => "Name not unique on network", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EBADFD => "File descriptor in bad state", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EREMCHG => "Remote address changed", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ELIBACC => "Can not access a needed shared library", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ELIBBAD => "Accessing a corrupted shared library", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ELIBSCN => ".lib section in a.out corrupted", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ELIBMAX => "Attempting to link in too many shared libraries", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ELIBEXEC => "Cannot exec a shared library directly", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia", + target_os = "openbsd" + ))] + EILSEQ => "Illegal byte sequence", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ERESTART => "Interrupted system call should be restarted", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + ESTRPIPE => "Streams pipe error", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia" + ))] + EUSERS => "Too many users", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "netbsd", + target_os = "redox" + ))] + EOPNOTSUPP => "Operation not supported on transport endpoint", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + ESTALE => "Stale file handle", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EUCLEAN => "Structure needs cleaning", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + ENOTNAM => "Not a XENIX named type file", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + ENAVAIL => "No XENIX semaphores available", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EISNAM => "Is a named type file", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EREMOTEIO => "Remote I/O error", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EDQUOT => "Quota exceeded", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "openbsd", + target_os = "dragonfly" + ))] + ENOMEDIUM => "No medium found", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "openbsd" + ))] + EMEDIUMTYPE => "Wrong medium type", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "illumos", + target_os = "solaris", + target_os = "fuchsia", + target_os = "haiku" + ))] + ECANCELED => "Operation canceled", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + ENOKEY => "Required key not available", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EKEYEXPIRED => "Key has expired", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EKEYREVOKED => "Key has been revoked", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EKEYREJECTED => "Key was rejected by service", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] + EOWNERDEAD => "Owner died", #[cfg(any(target_os = "illumos", target_os = "solaris"))] - EBADMSG => "Trying to read unreadable message", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia", target_os = "haiku"))] - EOVERFLOW => "Value too large for defined data type", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ENOTUNIQ => "Name not unique on network", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EBADFD => "File descriptor in bad state", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EREMCHG => "Remote address changed", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ELIBACC => "Can not access a needed shared library", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ELIBBAD => "Accessing a corrupted shared library", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ELIBSCN => ".lib section in a.out corrupted", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ELIBMAX => "Attempting to link in too many shared libraries", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ELIBEXEC => "Cannot exec a shared library directly", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia", target_os = "openbsd"))] - EILSEQ => "Illegal byte sequence", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ERESTART => "Interrupted system call should be restarted", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - ESTRPIPE => "Streams pipe error", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia"))] - EUSERS => "Too many users", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia", target_os = "netbsd", - target_os = "redox"))] - EOPNOTSUPP => "Operation not supported on transport endpoint", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - ESTALE => "Stale file handle", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - EUCLEAN => "Structure needs cleaning", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - ENOTNAM => "Not a XENIX named type file", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - ENAVAIL => "No XENIX semaphores available", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - EISNAM => "Is a named type file", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - EREMOTEIO => "Remote I/O error", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - EDQUOT => "Quota exceeded", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia", target_os = "openbsd", - target_os = "dragonfly"))] - ENOMEDIUM => "No medium found", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia", target_os = "openbsd"))] - EMEDIUMTYPE => "Wrong medium type", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "illumos", target_os = "solaris", - target_os = "fuchsia", target_os = "haiku"))] - ECANCELED => "Operation canceled", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - ENOKEY => "Required key not available", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - EKEYEXPIRED => "Key has expired", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - EKEYREVOKED => "Key has been revoked", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - EKEYREJECTED => "Key was rejected by service", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] - EOWNERDEAD => "Owner died", - - #[cfg(any( target_os = "illumos", target_os = "solaris"))] - EOWNERDEAD => "Process died with lock", - - #[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] + EOWNERDEAD => "Process died with lock", + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia" + ))] ENOTRECOVERABLE => "State not recoverable", #[cfg(any(target_os = "illumos", target_os = "solaris"))] ENOTRECOVERABLE => "Lock is not recoverable", - #[cfg(any(all(target_os = "linux", not(target_arch="mips")), - target_os = "fuchsia"))] - ERFKILL => "Operation not possible due to RF-kill", + #[cfg(any( + all(target_os = "linux", not(target_arch = "mips")), + target_os = "fuchsia" + ))] + ERFKILL => "Operation not possible due to RF-kill", - #[cfg(any(all(target_os = "linux", not(target_arch="mips")), - target_os = "fuchsia"))] - EHWPOISON => "Memory page has hardware error", + #[cfg(any( + all(target_os = "linux", not(target_arch = "mips")), + target_os = "fuchsia" + ))] + EHWPOISON => "Memory page has hardware error", #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - EDOOFUS => "Programming error", - - #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "redox"))] - EMULTIHOP => "Multihop attempted", - - #[cfg(any(target_os = "freebsd", target_os = "dragonfly", - target_os = "redox"))] - ENOLINK => "Link has been severed", + EDOOFUS => "Programming error", + + #[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "redox" + ))] + EMULTIHOP => "Multihop attempted", + + #[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "redox" + ))] + ENOLINK => "Link has been severed", #[cfg(target_os = "freebsd")] - ENOTCAPABLE => "Capabilities insufficient", + ENOTCAPABLE => "Capabilities insufficient", #[cfg(target_os = "freebsd")] - ECAPMODE => "Not permitted in capability mode", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd"))] - ENEEDAUTH => "Need authenticator", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd", - target_os = "redox", target_os = "illumos", - target_os = "solaris"))] - EOVERFLOW => "Value too large to be stored in data type", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "netbsd", target_os = "redox", - target_os = "haiku"))] - EILSEQ => "Illegal byte sequence", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd", - target_os = "haiku"))] - ENOATTR => "Attribute not found", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd", - target_os = "redox", target_os = "haiku"))] - EBADMSG => "Bad message", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd", - target_os = "redox", target_os = "haiku"))] - EPROTO => "Protocol error", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd"))] + ECAPMODE => "Not permitted in capability mode", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + ENEEDAUTH => "Need authenticator", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox", + target_os = "illumos", + target_os = "solaris" + ))] + EOVERFLOW => "Value too large to be stored in data type", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "netbsd", + target_os = "redox", + target_os = "haiku" + ))] + EILSEQ => "Illegal byte sequence", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "haiku" + ))] + ENOATTR => "Attribute not found", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox", + target_os = "haiku" + ))] + EBADMSG => "Bad message", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox", + target_os = "haiku" + ))] + EPROTO => "Protocol error", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd" + ))] ENOTRECOVERABLE => "State not recoverable", - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd"))] - EOWNERDEAD => "Previous owner died", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd", - target_os = "illumos", target_os = "solaris", - target_os = "haiku"))] - ENOTSUP => "Operation not supported", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd"))] - EPROCLIM => "Too many processes", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd", - target_os = "redox"))] - EUSERS => "Too many users", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd", - target_os = "redox", target_os = "illumos", - target_os = "solaris", target_os = "haiku"))] - EDQUOT => "Disc quota exceeded", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd", - target_os = "redox", target_os = "illumos", - target_os = "solaris", target_os = "haiku"))] - ESTALE => "Stale NFS file handle", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd", - target_os = "redox"))] - EREMOTE => "Too many levels of remote in path", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd"))] - EBADRPC => "RPC struct is bad", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd"))] - ERPCMISMATCH => "RPC version wrong", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd"))] - EPROGUNAVAIL => "RPC prog. not avail", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd"))] - EPROGMISMATCH => "Program version wrong", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd"))] - EPROCUNAVAIL => "Bad procedure for program", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd"))] - EFTYPE => "Inappropriate file type or format", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd"))] - EAUTH => "Authentication error", - - #[cfg(any(target_os = "macos", target_os = "freebsd", - target_os = "dragonfly", target_os = "ios", - target_os = "openbsd", target_os = "netbsd", - target_os = "redox"))] - ECANCELED => "Operation canceled", + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd" + ))] + EOWNERDEAD => "Previous owner died", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" + ))] + ENOTSUP => "Operation not supported", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EPROCLIM => "Too many processes", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox" + ))] + EUSERS => "Too many users", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox", + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" + ))] + EDQUOT => "Disc quota exceeded", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox", + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" + ))] + ESTALE => "Stale NFS file handle", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox" + ))] + EREMOTE => "Too many levels of remote in path", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EBADRPC => "RPC struct is bad", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + ERPCMISMATCH => "RPC version wrong", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EPROGUNAVAIL => "RPC prog. not avail", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EPROGMISMATCH => "Program version wrong", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EPROCUNAVAIL => "Bad procedure for program", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EFTYPE => "Inappropriate file type or format", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd" + ))] + EAUTH => "Authentication error", + + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "openbsd", + target_os = "netbsd", + target_os = "redox" + ))] + ECANCELED => "Operation canceled", #[cfg(any(target_os = "macos", target_os = "ios"))] - EPWROFF => "Device power is off", + EPWROFF => "Device power is off", #[cfg(any(target_os = "macos", target_os = "ios"))] - EDEVERR => "Device error, e.g. paper out", + EDEVERR => "Device error, e.g. paper out", #[cfg(any(target_os = "macos", target_os = "ios"))] - EBADEXEC => "Bad executable", + EBADEXEC => "Bad executable", #[cfg(any(target_os = "macos", target_os = "ios"))] - EBADARCH => "Bad CPU type in executable", + EBADARCH => "Bad CPU type in executable", #[cfg(any(target_os = "macos", target_os = "ios"))] - ESHLIBVERS => "Shared library version mismatch", + ESHLIBVERS => "Shared library version mismatch", #[cfg(any(target_os = "macos", target_os = "ios"))] - EBADMACHO => "Malformed Macho file", - - #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "netbsd", target_os = "haiku"))] - EMULTIHOP => "Reserved", - - #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "netbsd", target_os = "redox"))] - ENODATA => "No message available on STREAM", - - #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "netbsd", target_os = "haiku"))] - ENOLINK => "Reserved", - - #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "netbsd", target_os = "redox"))] - ENOSR => "No STREAM resources", - - #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "netbsd", target_os = "redox"))] - ENOSTR => "Not a STREAM", - - #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "netbsd", target_os = "redox"))] - ETIME => "STREAM ioctl timeout", - - #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "illumos", target_os = "solaris"))] - EOPNOTSUPP => "Operation not supported on socket", + EBADMACHO => "Malformed Macho file", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "haiku" + ))] + EMULTIHOP => "Reserved", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "redox" + ))] + ENODATA => "No message available on STREAM", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "haiku" + ))] + ENOLINK => "Reserved", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "redox" + ))] + ENOSR => "No STREAM resources", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "redox" + ))] + ENOSTR => "Not a STREAM", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "redox" + ))] + ETIME => "STREAM ioctl timeout", + + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "illumos", + target_os = "solaris" + ))] + EOPNOTSUPP => "Operation not supported on socket", #[cfg(any(target_os = "macos", target_os = "ios"))] - ENOPOLICY => "No such policy registered", + ENOPOLICY => "No such policy registered", #[cfg(any(target_os = "macos", target_os = "ios"))] - EQFULL => "Interface output queue is full", + EQFULL => "Interface output queue is full", #[cfg(target_os = "openbsd")] - EOPNOTSUPP => "Operation not supported", + EOPNOTSUPP => "Operation not supported", #[cfg(target_os = "openbsd")] - EIPSEC => "IPsec processing failure", + EIPSEC => "IPsec processing failure", #[cfg(target_os = "dragonfly")] - EASYNC => "Async", + EASYNC => "Async", #[cfg(any(target_os = "illumos", target_os = "solaris"))] - EDEADLOCK => "Resource deadlock would occur", + EDEADLOCK => "Resource deadlock would occur", #[cfg(any(target_os = "illumos", target_os = "solaris"))] - ELOCKUNMAPPED => "Locked lock was unmapped", + ELOCKUNMAPPED => "Locked lock was unmapped", #[cfg(any(target_os = "illumos", target_os = "solaris"))] - ENOTACTIVE => "Facility is not active", + ENOTACTIVE => "Facility is not active", } } -#[cfg(any(target_os = "linux", target_os = "android", - target_os = "fuchsia"))] +#[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))] mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] #[non_exhaustive] pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EAGAIN = libc::EAGAIN, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EDEADLK = libc::EDEADLK, - ENAMETOOLONG = libc::ENAMETOOLONG, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - ENOTEMPTY = libc::ENOTEMPTY, - ELOOP = libc::ELOOP, - ENOMSG = libc::ENOMSG, - EIDRM = libc::EIDRM, - ECHRNG = libc::ECHRNG, - EL2NSYNC = libc::EL2NSYNC, - EL3HLT = libc::EL3HLT, - EL3RST = libc::EL3RST, - ELNRNG = libc::ELNRNG, - EUNATCH = libc::EUNATCH, - ENOCSI = libc::ENOCSI, - EL2HLT = libc::EL2HLT, - EBADE = libc::EBADE, - EBADR = libc::EBADR, - EXFULL = libc::EXFULL, - ENOANO = libc::ENOANO, - EBADRQC = libc::EBADRQC, - EBADSLT = libc::EBADSLT, - EBFONT = libc::EBFONT, - ENOSTR = libc::ENOSTR, - ENODATA = libc::ENODATA, - ETIME = libc::ETIME, - ENOSR = libc::ENOSR, - ENONET = libc::ENONET, - ENOPKG = libc::ENOPKG, - EREMOTE = libc::EREMOTE, - ENOLINK = libc::ENOLINK, - EADV = libc::EADV, - ESRMNT = libc::ESRMNT, - ECOMM = libc::ECOMM, - EPROTO = libc::EPROTO, - EMULTIHOP = libc::EMULTIHOP, - EDOTDOT = libc::EDOTDOT, - EBADMSG = libc::EBADMSG, - EOVERFLOW = libc::EOVERFLOW, - ENOTUNIQ = libc::ENOTUNIQ, - EBADFD = libc::EBADFD, - EREMCHG = libc::EREMCHG, - ELIBACC = libc::ELIBACC, - ELIBBAD = libc::ELIBBAD, - ELIBSCN = libc::ELIBSCN, - ELIBMAX = libc::ELIBMAX, - ELIBEXEC = libc::ELIBEXEC, - EILSEQ = libc::EILSEQ, - ERESTART = libc::ERESTART, - ESTRPIPE = libc::ESTRPIPE, - EUSERS = libc::EUSERS, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EAGAIN = libc::EAGAIN, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EDEADLK = libc::EDEADLK, + ENAMETOOLONG = libc::ENAMETOOLONG, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + ENOTEMPTY = libc::ENOTEMPTY, + ELOOP = libc::ELOOP, + ENOMSG = libc::ENOMSG, + EIDRM = libc::EIDRM, + ECHRNG = libc::ECHRNG, + EL2NSYNC = libc::EL2NSYNC, + EL3HLT = libc::EL3HLT, + EL3RST = libc::EL3RST, + ELNRNG = libc::ELNRNG, + EUNATCH = libc::EUNATCH, + ENOCSI = libc::ENOCSI, + EL2HLT = libc::EL2HLT, + EBADE = libc::EBADE, + EBADR = libc::EBADR, + EXFULL = libc::EXFULL, + ENOANO = libc::ENOANO, + EBADRQC = libc::EBADRQC, + EBADSLT = libc::EBADSLT, + EBFONT = libc::EBFONT, + ENOSTR = libc::ENOSTR, + ENODATA = libc::ENODATA, + ETIME = libc::ETIME, + ENOSR = libc::ENOSR, + ENONET = libc::ENONET, + ENOPKG = libc::ENOPKG, + EREMOTE = libc::EREMOTE, + ENOLINK = libc::ENOLINK, + EADV = libc::EADV, + ESRMNT = libc::ESRMNT, + ECOMM = libc::ECOMM, + EPROTO = libc::EPROTO, + EMULTIHOP = libc::EMULTIHOP, + EDOTDOT = libc::EDOTDOT, + EBADMSG = libc::EBADMSG, + EOVERFLOW = libc::EOVERFLOW, + ENOTUNIQ = libc::ENOTUNIQ, + EBADFD = libc::EBADFD, + EREMCHG = libc::EREMCHG, + ELIBACC = libc::ELIBACC, + ELIBBAD = libc::ELIBBAD, + ELIBSCN = libc::ELIBSCN, + ELIBMAX = libc::ELIBMAX, + ELIBEXEC = libc::ELIBEXEC, + EILSEQ = libc::EILSEQ, + ERESTART = libc::ERESTART, + ESTRPIPE = libc::ESTRPIPE, + EUSERS = libc::EUSERS, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, EPROTONOSUPPORT = libc::EPROTONOSUPPORT, ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - EOPNOTSUPP = libc::EOPNOTSUPP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - EALREADY = libc::EALREADY, - EINPROGRESS = libc::EINPROGRESS, - ESTALE = libc::ESTALE, - EUCLEAN = libc::EUCLEAN, - ENOTNAM = libc::ENOTNAM, - ENAVAIL = libc::ENAVAIL, - EISNAM = libc::EISNAM, - EREMOTEIO = libc::EREMOTEIO, - EDQUOT = libc::EDQUOT, - ENOMEDIUM = libc::ENOMEDIUM, - EMEDIUMTYPE = libc::EMEDIUMTYPE, - ECANCELED = libc::ECANCELED, - ENOKEY = libc::ENOKEY, - EKEYEXPIRED = libc::EKEYEXPIRED, - EKEYREVOKED = libc::EKEYREVOKED, - EKEYREJECTED = libc::EKEYREJECTED, - EOWNERDEAD = libc::EOWNERDEAD, + EOPNOTSUPP = libc::EOPNOTSUPP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + EALREADY = libc::EALREADY, + EINPROGRESS = libc::EINPROGRESS, + ESTALE = libc::ESTALE, + EUCLEAN = libc::EUCLEAN, + ENOTNAM = libc::ENOTNAM, + ENAVAIL = libc::ENAVAIL, + EISNAM = libc::EISNAM, + EREMOTEIO = libc::EREMOTEIO, + EDQUOT = libc::EDQUOT, + ENOMEDIUM = libc::ENOMEDIUM, + EMEDIUMTYPE = libc::EMEDIUMTYPE, + ECANCELED = libc::ECANCELED, + ENOKEY = libc::ENOKEY, + EKEYEXPIRED = libc::EKEYEXPIRED, + EKEYREVOKED = libc::EKEYREVOKED, + EKEYREJECTED = libc::EKEYREJECTED, + EOWNERDEAD = libc::EOWNERDEAD, ENOTRECOVERABLE = libc::ENOTRECOVERABLE, - #[cfg(not(any(target_os = "android", target_arch="mips")))] - ERFKILL = libc::ERFKILL, - #[cfg(not(any(target_os = "android", target_arch="mips")))] - EHWPOISON = libc::EHWPOISON, + #[cfg(not(any(target_os = "android", target_arch = "mips")))] + ERFKILL = libc::ERFKILL, + #[cfg(not(any(target_os = "android", target_arch = "mips")))] + EHWPOISON = libc::EHWPOISON, } #[deprecated( @@ -931,17 +1306,17 @@ mod consts { since = "0.22.1", note = "use nix::errno::Errno::EDEADLOCK instead" )] - pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const EDEADLOCK: Errno = Errno::EDEADLK; #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::ENOTSUP instead" )] - pub const ENOTSUP: Errno = Errno::EOPNOTSUPP; + pub const ENOTSUP: Errno = Errno::EOPNOTSUPP; impl Errno { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - pub const ENOTSUP: Errno = Errno::EOPNOTSUPP; + pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const ENOTSUP: Errno = Errno::EOPNOTSUPP; } pub const fn from_i32(e: i32) -> Errno { @@ -1077,11 +1452,11 @@ mod consts { libc::EKEYREJECTED => EKEYREJECTED, libc::EOWNERDEAD => EOWNERDEAD, libc::ENOTRECOVERABLE => ENOTRECOVERABLE, - #[cfg(not(any(target_os = "android", target_arch="mips")))] + #[cfg(not(any(target_os = "android", target_arch = "mips")))] libc::ERFKILL => ERFKILL, - #[cfg(not(any(target_os = "android", target_arch="mips")))] + #[cfg(not(any(target_os = "android", target_arch = "mips")))] libc::EHWPOISON => EHWPOISON, - _ => UnknownErrno, + _ => UnknownErrno, } } } @@ -1092,120 +1467,120 @@ mod consts { #[repr(i32)] #[non_exhaustive] pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, EPROTONOSUPPORT = libc::EPROTONOSUPPORT, ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - ENOTSUP = libc::ENOTSUP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EPROCLIM = libc::EPROCLIM, - EUSERS = libc::EUSERS, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - EREMOTE = libc::EREMOTE, - EBADRPC = libc::EBADRPC, - ERPCMISMATCH = libc::ERPCMISMATCH, - EPROGUNAVAIL = libc::EPROGUNAVAIL, - EPROGMISMATCH = libc::EPROGMISMATCH, - EPROCUNAVAIL = libc::EPROCUNAVAIL, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EFTYPE = libc::EFTYPE, - EAUTH = libc::EAUTH, - ENEEDAUTH = libc::ENEEDAUTH, - EPWROFF = libc::EPWROFF, - EDEVERR = libc::EDEVERR, - EOVERFLOW = libc::EOVERFLOW, - EBADEXEC = libc::EBADEXEC, - EBADARCH = libc::EBADARCH, - ESHLIBVERS = libc::ESHLIBVERS, - EBADMACHO = libc::EBADMACHO, - ECANCELED = libc::ECANCELED, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - EILSEQ = libc::EILSEQ, - ENOATTR = libc::ENOATTR, - EBADMSG = libc::EBADMSG, - EMULTIHOP = libc::EMULTIHOP, - ENODATA = libc::ENODATA, - ENOLINK = libc::ENOLINK, - ENOSR = libc::ENOSR, - ENOSTR = libc::ENOSTR, - EPROTO = libc::EPROTO, - ETIME = libc::ETIME, - EOPNOTSUPP = libc::EOPNOTSUPP, - ENOPOLICY = libc::ENOPOLICY, + ENOTSUP = libc::ENOTSUP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EPROCLIM = libc::EPROCLIM, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + EBADRPC = libc::EBADRPC, + ERPCMISMATCH = libc::ERPCMISMATCH, + EPROGUNAVAIL = libc::EPROGUNAVAIL, + EPROGMISMATCH = libc::EPROGMISMATCH, + EPROCUNAVAIL = libc::EPROCUNAVAIL, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EFTYPE = libc::EFTYPE, + EAUTH = libc::EAUTH, + ENEEDAUTH = libc::ENEEDAUTH, + EPWROFF = libc::EPWROFF, + EDEVERR = libc::EDEVERR, + EOVERFLOW = libc::EOVERFLOW, + EBADEXEC = libc::EBADEXEC, + EBADARCH = libc::EBADARCH, + ESHLIBVERS = libc::ESHLIBVERS, + EBADMACHO = libc::EBADMACHO, + ECANCELED = libc::ECANCELED, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + EILSEQ = libc::EILSEQ, + ENOATTR = libc::ENOATTR, + EBADMSG = libc::EBADMSG, + EMULTIHOP = libc::EMULTIHOP, + ENODATA = libc::ENODATA, + ENOLINK = libc::ENOLINK, + ENOSR = libc::ENOSR, + ENOSTR = libc::ENOSTR, + EPROTO = libc::EPROTO, + ETIME = libc::ETIME, + EOPNOTSUPP = libc::EOPNOTSUPP, + ENOPOLICY = libc::ENOPOLICY, ENOTRECOVERABLE = libc::ENOTRECOVERABLE, - EOWNERDEAD = libc::EOWNERDEAD, - EQFULL = libc::EQFULL, + EOWNERDEAD = libc::EOWNERDEAD, + EQFULL = libc::EQFULL, } #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::ELAST instead" )] - pub const ELAST: Errno = Errno::EQFULL; + pub const ELAST: Errno = Errno::EQFULL; #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::EWOULDBLOCK instead" @@ -1215,12 +1590,12 @@ mod consts { since = "0.22.1", note = "use nix::errno::Errno::EDEADLOCK instead" )] - pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const EDEADLOCK: Errno = Errno::EDEADLK; impl Errno { - pub const ELAST: Errno = Errno::EQFULL; + pub const ELAST: Errno = Errno::EQFULL; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const EDEADLOCK: Errno = Errno::EDEADLK; } pub const fn from_i32(e: i32) -> Errno { @@ -1333,7 +1708,7 @@ mod consts { libc::ENOTRECOVERABLE => ENOTRECOVERABLE, libc::EOWNERDEAD => EOWNERDEAD, libc::EQFULL => EQFULL, - _ => UnknownErrno, + _ => UnknownErrno, } } } @@ -1344,110 +1719,110 @@ mod consts { #[repr(i32)] #[non_exhaustive] pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, EPROTONOSUPPORT = libc::EPROTONOSUPPORT, ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - ENOTSUP = libc::ENOTSUP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EPROCLIM = libc::EPROCLIM, - EUSERS = libc::EUSERS, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - EREMOTE = libc::EREMOTE, - EBADRPC = libc::EBADRPC, - ERPCMISMATCH = libc::ERPCMISMATCH, - EPROGUNAVAIL = libc::EPROGUNAVAIL, - EPROGMISMATCH = libc::EPROGMISMATCH, - EPROCUNAVAIL = libc::EPROCUNAVAIL, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EFTYPE = libc::EFTYPE, - EAUTH = libc::EAUTH, - ENEEDAUTH = libc::ENEEDAUTH, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - EOVERFLOW = libc::EOVERFLOW, - ECANCELED = libc::ECANCELED, - EILSEQ = libc::EILSEQ, - ENOATTR = libc::ENOATTR, - EDOOFUS = libc::EDOOFUS, - EBADMSG = libc::EBADMSG, - EMULTIHOP = libc::EMULTIHOP, - ENOLINK = libc::ENOLINK, - EPROTO = libc::EPROTO, - ENOTCAPABLE = libc::ENOTCAPABLE, - ECAPMODE = libc::ECAPMODE, + ENOTSUP = libc::ENOTSUP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EPROCLIM = libc::EPROCLIM, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + EBADRPC = libc::EBADRPC, + ERPCMISMATCH = libc::ERPCMISMATCH, + EPROGUNAVAIL = libc::EPROGUNAVAIL, + EPROGMISMATCH = libc::EPROGMISMATCH, + EPROCUNAVAIL = libc::EPROCUNAVAIL, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EFTYPE = libc::EFTYPE, + EAUTH = libc::EAUTH, + ENEEDAUTH = libc::ENEEDAUTH, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + EOVERFLOW = libc::EOVERFLOW, + ECANCELED = libc::ECANCELED, + EILSEQ = libc::EILSEQ, + ENOATTR = libc::ENOATTR, + EDOOFUS = libc::EDOOFUS, + EBADMSG = libc::EBADMSG, + EMULTIHOP = libc::EMULTIHOP, + ENOLINK = libc::ENOLINK, + EPROTO = libc::EPROTO, + ENOTCAPABLE = libc::ENOTCAPABLE, + ECAPMODE = libc::ECAPMODE, ENOTRECOVERABLE = libc::ENOTRECOVERABLE, - EOWNERDEAD = libc::EOWNERDEAD, + EOWNERDEAD = libc::EOWNERDEAD, } #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::ELAST instead" )] - pub const ELAST: Errno = Errno::EOWNERDEAD; + pub const ELAST: Errno = Errno::EOWNERDEAD; #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::EWOULDBLOCK instead" @@ -1457,18 +1832,18 @@ mod consts { since = "0.22.1", note = "use nix::errno::Errno::EDEADLOCK instead" )] - pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const EDEADLOCK: Errno = Errno::EDEADLK; #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::EOPNOTSUPP instead" )] - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; + pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; impl Errno { - pub const ELAST: Errno = Errno::EOWNERDEAD; + pub const ELAST: Errno = Errno::EOWNERDEAD; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; + pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; } pub const fn from_i32(e: i32) -> Errno { @@ -1571,122 +1946,121 @@ mod consts { libc::ECAPMODE => ECAPMODE, libc::ENOTRECOVERABLE => ENOTRECOVERABLE, libc::EOWNERDEAD => EOWNERDEAD, - _ => UnknownErrno, + _ => UnknownErrno, } } } - #[cfg(target_os = "dragonfly")] mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] #[non_exhaustive] pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, EPROTONOSUPPORT = libc::EPROTONOSUPPORT, ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - ENOTSUP = libc::ENOTSUP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EPROCLIM = libc::EPROCLIM, - EUSERS = libc::EUSERS, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - EREMOTE = libc::EREMOTE, - EBADRPC = libc::EBADRPC, - ERPCMISMATCH = libc::ERPCMISMATCH, - EPROGUNAVAIL = libc::EPROGUNAVAIL, - EPROGMISMATCH = libc::EPROGMISMATCH, - EPROCUNAVAIL = libc::EPROCUNAVAIL, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EFTYPE = libc::EFTYPE, - EAUTH = libc::EAUTH, - ENEEDAUTH = libc::ENEEDAUTH, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - EOVERFLOW = libc::EOVERFLOW, - ECANCELED = libc::ECANCELED, - EILSEQ = libc::EILSEQ, - ENOATTR = libc::ENOATTR, - EDOOFUS = libc::EDOOFUS, - EBADMSG = libc::EBADMSG, - EMULTIHOP = libc::EMULTIHOP, - ENOLINK = libc::ENOLINK, - EPROTO = libc::EPROTO, - ENOMEDIUM = libc::ENOMEDIUM, + ENOTSUP = libc::ENOTSUP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EPROCLIM = libc::EPROCLIM, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + EBADRPC = libc::EBADRPC, + ERPCMISMATCH = libc::ERPCMISMATCH, + EPROGUNAVAIL = libc::EPROGUNAVAIL, + EPROGMISMATCH = libc::EPROGMISMATCH, + EPROCUNAVAIL = libc::EPROCUNAVAIL, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EFTYPE = libc::EFTYPE, + EAUTH = libc::EAUTH, + ENEEDAUTH = libc::ENEEDAUTH, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + EOVERFLOW = libc::EOVERFLOW, + ECANCELED = libc::ECANCELED, + EILSEQ = libc::EILSEQ, + ENOATTR = libc::ENOATTR, + EDOOFUS = libc::EDOOFUS, + EBADMSG = libc::EBADMSG, + EMULTIHOP = libc::EMULTIHOP, + ENOLINK = libc::ENOLINK, + EPROTO = libc::EPROTO, + ENOMEDIUM = libc::ENOMEDIUM, ENOTRECOVERABLE = libc::ENOTRECOVERABLE, - EOWNERDEAD = libc::EOWNERDEAD, - EASYNC = libc::EASYNC, + EOWNERDEAD = libc::EOWNERDEAD, + EASYNC = libc::EASYNC, } #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::ELAST instead" )] - pub const ELAST: Errno = Errno::EASYNC; + pub const ELAST: Errno = Errno::EASYNC; #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::EWOULDBLOCK instead" @@ -1696,18 +2070,18 @@ mod consts { since = "0.22.1", note = "use nix::errno::Errno::EDEADLOCK instead" )] - pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const EDEADLOCK: Errno = Errno::EDEADLK; #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::EOPNOTSUPP instead" )] - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; + pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; impl Errno { - pub const ELAST: Errno = Errno::EASYNC; + pub const ELAST: Errno = Errno::EASYNC; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; + pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; } pub const fn from_i32(e: i32) -> Errno { @@ -1734,7 +2108,7 @@ mod consts { libc::EXDEV => EXDEV, libc::ENODEV => ENODEV, libc::ENOTDIR => ENOTDIR, - libc::EISDIR=> EISDIR, + libc::EISDIR => EISDIR, libc::EINVAL => EINVAL, libc::ENFILE => ENFILE, libc::EMFILE => EMFILE, @@ -1808,121 +2182,120 @@ mod consts { libc::EPROTO => EPROTO, libc::ENOMEDIUM => ENOMEDIUM, libc::EASYNC => EASYNC, - _ => UnknownErrno, + _ => UnknownErrno, } } } - #[cfg(target_os = "openbsd")] mod consts { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(i32)] #[non_exhaustive] pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, EPROTONOSUPPORT = libc::EPROTONOSUPPORT, ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - EOPNOTSUPP = libc::EOPNOTSUPP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EPROCLIM = libc::EPROCLIM, - EUSERS = libc::EUSERS, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - EREMOTE = libc::EREMOTE, - EBADRPC = libc::EBADRPC, - ERPCMISMATCH = libc::ERPCMISMATCH, - EPROGUNAVAIL = libc::EPROGUNAVAIL, - EPROGMISMATCH = libc::EPROGMISMATCH, - EPROCUNAVAIL = libc::EPROCUNAVAIL, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EFTYPE = libc::EFTYPE, - EAUTH = libc::EAUTH, - ENEEDAUTH = libc::ENEEDAUTH, - EIPSEC = libc::EIPSEC, - ENOATTR = libc::ENOATTR, - EILSEQ = libc::EILSEQ, - ENOMEDIUM = libc::ENOMEDIUM, - EMEDIUMTYPE = libc::EMEDIUMTYPE, - EOVERFLOW = libc::EOVERFLOW, - ECANCELED = libc::ECANCELED, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - ENOTSUP = libc::ENOTSUP, - EBADMSG = libc::EBADMSG, + EOPNOTSUPP = libc::EOPNOTSUPP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EPROCLIM = libc::EPROCLIM, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + EBADRPC = libc::EBADRPC, + ERPCMISMATCH = libc::ERPCMISMATCH, + EPROGUNAVAIL = libc::EPROGUNAVAIL, + EPROGMISMATCH = libc::EPROGMISMATCH, + EPROCUNAVAIL = libc::EPROCUNAVAIL, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EFTYPE = libc::EFTYPE, + EAUTH = libc::EAUTH, + ENEEDAUTH = libc::ENEEDAUTH, + EIPSEC = libc::EIPSEC, + ENOATTR = libc::ENOATTR, + EILSEQ = libc::EILSEQ, + ENOMEDIUM = libc::ENOMEDIUM, + EMEDIUMTYPE = libc::EMEDIUMTYPE, + EOVERFLOW = libc::EOVERFLOW, + ECANCELED = libc::ECANCELED, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + ENOTSUP = libc::ENOTSUP, + EBADMSG = libc::EBADMSG, ENOTRECOVERABLE = libc::ENOTRECOVERABLE, - EOWNERDEAD = libc::EOWNERDEAD, - EPROTO = libc::EPROTO, + EOWNERDEAD = libc::EOWNERDEAD, + EPROTO = libc::EPROTO, } #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::ELAST instead" )] - pub const ELAST: Errno = Errno::ENOTSUP; + pub const ELAST: Errno = Errno::ENOTSUP; #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::EWOULDBLOCK instead" @@ -1930,7 +2303,7 @@ mod consts { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; impl Errno { - pub const ELAST: Errno = Errno::ENOTSUP; + pub const ELAST: Errno = Errno::ENOTSUP; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; } @@ -2033,7 +2406,7 @@ mod consts { libc::ENOTRECOVERABLE => ENOTRECOVERABLE, libc::EOWNERDEAD => EOWNERDEAD, libc::EPROTO => EPROTO, - _ => UnknownErrno, + _ => UnknownErrno, } } } @@ -2044,110 +2417,110 @@ mod consts { #[repr(i32)] #[non_exhaustive] pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - ENOTBLK = libc::ENOTBLK, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, EPROTONOSUPPORT = libc::EPROTONOSUPPORT, ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, - EOPNOTSUPP = libc::EOPNOTSUPP, - EPFNOSUPPORT = libc::EPFNOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETOOMANYREFS = libc::ETOOMANYREFS, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EPROCLIM = libc::EPROCLIM, - EUSERS = libc::EUSERS, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - EREMOTE = libc::EREMOTE, - EBADRPC = libc::EBADRPC, - ERPCMISMATCH = libc::ERPCMISMATCH, - EPROGUNAVAIL = libc::EPROGUNAVAIL, - EPROGMISMATCH = libc::EPROGMISMATCH, - EPROCUNAVAIL = libc::EPROCUNAVAIL, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EFTYPE = libc::EFTYPE, - EAUTH = libc::EAUTH, - ENEEDAUTH = libc::ENEEDAUTH, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - EOVERFLOW = libc::EOVERFLOW, - EILSEQ = libc::EILSEQ, - ENOTSUP = libc::ENOTSUP, - ECANCELED = libc::ECANCELED, - EBADMSG = libc::EBADMSG, - ENODATA = libc::ENODATA, - ENOSR = libc::ENOSR, - ENOSTR = libc::ENOSTR, - ETIME = libc::ETIME, - ENOATTR = libc::ENOATTR, - EMULTIHOP = libc::EMULTIHOP, - ENOLINK = libc::ENOLINK, - EPROTO = libc::EPROTO, + EOPNOTSUPP = libc::EOPNOTSUPP, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EPROCLIM = libc::EPROCLIM, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + EBADRPC = libc::EBADRPC, + ERPCMISMATCH = libc::ERPCMISMATCH, + EPROGUNAVAIL = libc::EPROGUNAVAIL, + EPROGMISMATCH = libc::EPROGMISMATCH, + EPROCUNAVAIL = libc::EPROCUNAVAIL, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EFTYPE = libc::EFTYPE, + EAUTH = libc::EAUTH, + ENEEDAUTH = libc::ENEEDAUTH, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + EOVERFLOW = libc::EOVERFLOW, + EILSEQ = libc::EILSEQ, + ENOTSUP = libc::ENOTSUP, + ECANCELED = libc::ECANCELED, + EBADMSG = libc::EBADMSG, + ENODATA = libc::ENODATA, + ENOSR = libc::ENOSR, + ENOSTR = libc::ENOSTR, + ETIME = libc::ETIME, + ENOATTR = libc::ENOATTR, + EMULTIHOP = libc::EMULTIHOP, + ENOLINK = libc::ENOLINK, + EPROTO = libc::EPROTO, } #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::ELAST instead" )] - pub const ELAST: Errno = Errno::ENOTSUP; + pub const ELAST: Errno = Errno::ENOTSUP; #[deprecated( since = "0.22.1", note = "use nix::errno::Errno::EWOULDBLOCK instead" @@ -2155,7 +2528,7 @@ mod consts { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; impl Errno { - pub const ELAST: Errno = Errno::ENOTSUP; + pub const ELAST: Errno = Errno::ENOTSUP; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; } @@ -2259,7 +2632,7 @@ mod consts { libc::EMULTIHOP => EMULTIHOP, libc::ENOLINK => ENOLINK, libc::EPROTO => EPROTO, - _ => UnknownErrno, + _ => UnknownErrno, } } } @@ -2604,7 +2977,7 @@ mod consts { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; impl Errno { - pub const ELAST: Errno = Errno::ESTALE; + pub const ELAST: Errno = Errno::ESTALE; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; } @@ -2744,88 +3117,88 @@ mod consts { #[repr(i32)] #[non_exhaustive] pub enum Errno { - UnknownErrno = 0, - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EDEADLK = libc::EDEADLK, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EAGAIN = libc::EAGAIN, - EINPROGRESS = libc::EINPROGRESS, - EALREADY = libc::EALREADY, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EDEADLK = libc::EDEADLK, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EAGAIN = libc::EAGAIN, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, EPROTONOSUPPORT = libc::EPROTONOSUPPORT, - ENOTSUP = libc::ENOTSUP, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ESHUTDOWN = libc::ESHUTDOWN, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - ELOOP = libc::ELOOP, - ENAMETOOLONG = libc::ENAMETOOLONG, - EHOSTDOWN = libc::EHOSTDOWN, - EHOSTUNREACH = libc::EHOSTUNREACH, - ENOTEMPTY = libc::ENOTEMPTY, - EDQUOT = libc::EDQUOT, - ESTALE = libc::ESTALE, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - EIDRM = libc::EIDRM, - ENOMSG = libc::ENOMSG, - EOVERFLOW = libc::EOVERFLOW, - ECANCELED = libc::ECANCELED, - EILSEQ = libc::EILSEQ, - ENOATTR = libc::ENOATTR, - EBADMSG = libc::EBADMSG, - EMULTIHOP = libc::EMULTIHOP, - ENOLINK = libc::ENOLINK, - EPROTO = libc::EPROTO, + ENOTSUP = libc::ENOTSUP, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + ELOOP = libc::ELOOP, + ENAMETOOLONG = libc::ENAMETOOLONG, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ENOTEMPTY = libc::ENOTEMPTY, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + EIDRM = libc::EIDRM, + ENOMSG = libc::ENOMSG, + EOVERFLOW = libc::EOVERFLOW, + ECANCELED = libc::ECANCELED, + EILSEQ = libc::EILSEQ, + ENOATTR = libc::ENOATTR, + EBADMSG = libc::EBADMSG, + EMULTIHOP = libc::EMULTIHOP, + ENOLINK = libc::ENOLINK, + EPROTO = libc::EPROTO, } impl Errno { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - pub const EDEADLOCK: Errno = Errno::EDEADLK; - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; + pub const EDEADLOCK: Errno = Errno::EDEADLK; + pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; } pub const fn from_i32(e: i32) -> Errno { @@ -2907,8 +3280,7 @@ mod consts { libc::EMULTIHOP => EMULTIHOP, libc::ENOLINK => ENOLINK, libc::EPROTO => EPROTO, - _ => UnknownErrno, + _ => UnknownErrno, } } } - diff --git a/src/fcntl.rs b/src/fcntl.rs index 6f9fa15d3f..0f0c811f34 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -6,14 +6,10 @@ use std::os::raw; use std::os::unix::ffi::OsStringExt; use std::os::unix::io::RawFd; +#[cfg(feature = "fs")] +use crate::{sys::stat::Mode, NixPath, Result}; #[cfg(any(target_os = "android", target_os = "linux"))] use std::ptr; // For splice and copy_file_range -#[cfg(feature = "fs")] -use crate::{ - NixPath, - Result, - sys::stat::Mode -}; #[cfg(any( target_os = "linux", @@ -25,7 +21,7 @@ use crate::{ target_os = "freebsd" ))] #[cfg(feature = "fs")] -pub use self::posix_fadvise::{PosixFadviseAdvice, posix_fadvise}; +pub use self::posix_fadvise::{posix_fadvise, PosixFadviseAdvice}; #[cfg(not(target_os = "redox"))] #[cfg(any(feature = "fs", feature = "process"))] @@ -241,10 +237,7 @@ pub fn renameat( } } -#[cfg(all( - target_os = "linux", - target_env = "gnu", -))] +#[cfg(all(target_os = "linux", target_env = "gnu",))] #[cfg(feature = "fs")] libc_bitflags! { #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] diff --git a/src/lib.rs b/src/lib.rs index fb6774051a..c8df1ce36d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,14 +52,14 @@ #![deny(missing_copy_implementations)] #![deny(missing_debug_implementations)] #![warn(missing_docs)] - #![cfg_attr(docsrs, feature(doc_cfg))] // Re-exported external crates pub use libc; // Private internal modules -#[macro_use] mod macros; +#[macro_use] +mod macros; // Public crates #[cfg(not(target_os = "redox"))] @@ -100,24 +100,23 @@ feature! { #[deny(missing_docs)] pub mod net; } -#[cfg(any(target_os = "android", - target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "linux"))] feature! { #![feature = "kmod"] #[allow(missing_docs)] pub mod kmod; } -#[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] feature! { #![feature = "mount"] pub mod mount; } -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd" +))] feature! { #![feature = "mqueue"] #[allow(missing_docs)] @@ -145,9 +144,10 @@ feature! { } // This can be implemented for other platforms as soon as libc // provides bindings for them. -#[cfg(all(target_os = "linux", - any(target_arch = "s390x", target_arch = "x86", - target_arch = "x86_64")))] +#[cfg(all( + target_os = "linux", + any(target_arch = "s390x", target_arch = "x86", target_arch = "x86_64") +))] feature! { #![feature = "ucontext"] #[allow(missing_docs)] @@ -191,7 +191,8 @@ pub trait NixPath { /// /// Mostly used internally by Nix. fn with_nix_path(&self, f: F) -> Result - where F: FnOnce(&CStr) -> T; + where + F: FnOnce(&CStr) -> T; } impl NixPath for str { @@ -204,9 +205,11 @@ impl NixPath for str { } fn with_nix_path(&self, f: F) -> Result - where F: FnOnce(&CStr) -> T { - OsStr::new(self).with_nix_path(f) - } + where + F: FnOnce(&CStr) -> T, + { + OsStr::new(self).with_nix_path(f) + } } impl NixPath for OsStr { @@ -219,9 +222,11 @@ impl NixPath for OsStr { } fn with_nix_path(&self, f: F) -> Result - where F: FnOnce(&CStr) -> T { - self.as_bytes().with_nix_path(f) - } + where + F: FnOnce(&CStr) -> T, + { + self.as_bytes().with_nix_path(f) + } } impl NixPath for CStr { @@ -274,7 +279,9 @@ impl NixPath for [u8] { buf_ptr.add(self.len()).write(0); } - match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, self.len() + 1) }) { + match CStr::from_bytes_with_nul(unsafe { + slice::from_raw_parts(buf_ptr, self.len() + 1) + }) { Ok(s) => Ok(f(s)), Err(_) => Err(Errno::EINVAL), } @@ -302,7 +309,10 @@ impl NixPath for Path { NixPath::len(self.as_os_str()) } - fn with_nix_path(&self, f: F) -> Result where F: FnOnce(&CStr) -> T { + fn with_nix_path(&self, f: F) -> Result + where + F: FnOnce(&CStr) -> T, + { self.as_os_str().with_nix_path(f) } } @@ -316,7 +326,10 @@ impl NixPath for PathBuf { NixPath::len(self.as_os_str()) } - fn with_nix_path(&self, f: F) -> Result where F: FnOnce(&CStr) -> T { + fn with_nix_path(&self, f: F) -> Result + where + F: FnOnce(&CStr) -> T, + { self.as_os_str().with_nix_path(f) } } diff --git a/src/sys/ioctl/bsd.rs b/src/sys/ioctl/bsd.rs index 4ce4d332a8..307994cb96 100644 --- a/src/sys/ioctl/bsd.rs +++ b/src/sys/ioctl/bsd.rs @@ -21,7 +21,7 @@ mod consts { #[allow(overflowing_literals)] pub const IN: ioctl_num_type = 0x8000_0000; #[doc(hidden)] - pub const INOUT: ioctl_num_type = IN|OUT; + pub const INOUT: ioctl_num_type = IN | OUT; #[doc(hidden)] pub const IOCPARM_MASK: ioctl_num_type = 0x1fff; } @@ -31,9 +31,14 @@ pub use self::consts::*; #[macro_export] #[doc(hidden)] macro_rules! ioc { - ($inout:expr, $group:expr, $num:expr, $len:expr) => ( - $inout | (($len as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::IOCPARM_MASK) << 16) | (($group as $crate::sys::ioctl::ioctl_num_type) << 8) | ($num as $crate::sys::ioctl::ioctl_num_type) - ) + ($inout:expr, $group:expr, $num:expr, $len:expr) => { + $inout + | (($len as $crate::sys::ioctl::ioctl_num_type + & $crate::sys::ioctl::IOCPARM_MASK) + << 16) + | (($group as $crate::sys::ioctl::ioctl_num_type) << 8) + | ($num as $crate::sys::ioctl::ioctl_num_type) + }; } /// Generate an ioctl request code for a command that passes no data. @@ -53,7 +58,9 @@ macro_rules! ioc { /// ``` #[macro_export(local_inner_macros)] macro_rules! request_code_none { - ($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, 0)) + ($g:expr, $n:expr) => { + ioc!($crate::sys::ioctl::VOID, $g, $n, 0) + }; } /// Generate an ioctl request code for a command that passes an integer @@ -64,7 +71,14 @@ macro_rules! request_code_none { /// with is "bad" and you cannot use `ioctl_write_int!()` directly. #[macro_export(local_inner_macros)] macro_rules! request_code_write_int { - ($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, ::std::mem::size_of::<$crate::libc::c_int>())) + ($g:expr, $n:expr) => { + ioc!( + $crate::sys::ioctl::VOID, + $g, + $n, + ::std::mem::size_of::<$crate::libc::c_int>() + ) + }; } /// Generate an ioctl request code for a command that reads. @@ -79,7 +93,9 @@ macro_rules! request_code_write_int { /// writing. #[macro_export(local_inner_macros)] macro_rules! request_code_read { - ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::OUT, $g, $n, $len)) + ($g:expr, $n:expr, $len:expr) => { + ioc!($crate::sys::ioctl::OUT, $g, $n, $len) + }; } /// Generate an ioctl request code for a command that writes. @@ -94,7 +110,9 @@ macro_rules! request_code_read { /// reading. #[macro_export(local_inner_macros)] macro_rules! request_code_write { - ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::IN, $g, $n, $len)) + ($g:expr, $n:expr, $len:expr) => { + ioc!($crate::sys::ioctl::IN, $g, $n, $len) + }; } /// Generate an ioctl request code for a command that reads and writes. @@ -105,5 +123,7 @@ macro_rules! request_code_write { /// with is "bad" and you cannot use `ioctl_readwrite!()` directly. #[macro_export(local_inner_macros)] macro_rules! request_code_readwrite { - ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::INOUT, $g, $n, $len)) + ($g:expr, $n:expr, $len:expr) => { + ioc!($crate::sys::ioctl::INOUT, $g, $n, $len) + }; } diff --git a/src/sys/ioctl/linux.rs b/src/sys/ioctl/linux.rs index 08cd0c33b4..0c0a209053 100644 --- a/src/sys/ioctl/linux.rs +++ b/src/sys/ioctl/linux.rs @@ -14,7 +14,13 @@ pub const NRBITS: ioctl_num_type = 8; #[doc(hidden)] pub const TYPEBITS: ioctl_num_type = 8; -#[cfg(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "sparc64"))] +#[cfg(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "sparc64" +))] mod consts { #[doc(hidden)] pub const NONE: u8 = 1; @@ -29,13 +35,15 @@ mod consts { } // "Generic" ioctl protocol -#[cfg(any(target_arch = "x86", - target_arch = "arm", - target_arch = "s390x", - target_arch = "x86_64", - target_arch = "aarch64", - target_arch = "riscv32", - target_arch = "riscv64"))] +#[cfg(any( + target_arch = "x86", + target_arch = "arm", + target_arch = "s390x", + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "riscv32", + target_arch = "riscv64" +))] mod consts { #[doc(hidden)] pub const NONE: u8 = 0; @@ -73,11 +81,20 @@ pub const DIRMASK: ioctl_num_type = (1 << DIRBITS) - 1; #[macro_export] #[doc(hidden)] macro_rules! ioc { - ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => ( - (($dir as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::DIRMASK) << $crate::sys::ioctl::DIRSHIFT) | - (($ty as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::TYPEMASK) << $crate::sys::ioctl::TYPESHIFT) | - (($nr as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::NRMASK) << $crate::sys::ioctl::NRSHIFT) | - (($sz as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::SIZEMASK) << $crate::sys::ioctl::SIZESHIFT)) + ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => { + (($dir as $crate::sys::ioctl::ioctl_num_type + & $crate::sys::ioctl::DIRMASK) + << $crate::sys::ioctl::DIRSHIFT) + | (($ty as $crate::sys::ioctl::ioctl_num_type + & $crate::sys::ioctl::TYPEMASK) + << $crate::sys::ioctl::TYPESHIFT) + | (($nr as $crate::sys::ioctl::ioctl_num_type + & $crate::sys::ioctl::NRMASK) + << $crate::sys::ioctl::NRSHIFT) + | (($sz as $crate::sys::ioctl::ioctl_num_type + & $crate::sys::ioctl::SIZEMASK) + << $crate::sys::ioctl::SIZESHIFT) + }; } /// Generate an ioctl request code for a command that passes no data. @@ -97,7 +114,9 @@ macro_rules! ioc { /// ``` #[macro_export(local_inner_macros)] macro_rules! request_code_none { - ($ty:expr, $nr:expr) => (ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0)) + ($ty:expr, $nr:expr) => { + ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0) + }; } /// Generate an ioctl request code for a command that reads. @@ -112,7 +131,9 @@ macro_rules! request_code_none { /// writing. #[macro_export(local_inner_macros)] macro_rules! request_code_read { - ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz)) + ($ty:expr, $nr:expr, $sz:expr) => { + ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz) + }; } /// Generate an ioctl request code for a command that writes. @@ -127,7 +148,9 @@ macro_rules! request_code_read { /// reading. #[macro_export(local_inner_macros)] macro_rules! request_code_write { - ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz)) + ($ty:expr, $nr:expr, $sz:expr) => { + ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz) + }; } /// Generate an ioctl request code for a command that reads and writes. @@ -138,5 +161,12 @@ macro_rules! request_code_write { /// with is "bad" and you cannot use `ioctl_readwrite!()` directly. #[macro_export(local_inner_macros)] macro_rules! request_code_readwrite { - ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, $ty, $nr, $sz)) + ($ty:expr, $nr:expr, $sz:expr) => { + ioc!( + $crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, + $ty, + $nr, + $sz + ) + }; } diff --git a/src/sys/ioctl/mod.rs b/src/sys/ioctl/mod.rs index ce9c5db072..98d6b5c99d 100644 --- a/src/sys/ioctl/mod.rs +++ b/src/sys/ioctl/mod.rs @@ -227,39 +227,45 @@ use cfg_if::cfg_if; #[macro_use] mod linux; -#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "redox" +))] pub use self::linux::*; -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "haiku", + target_os = "openbsd" +))] #[macro_use] mod bsd; -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "haiku", + target_os = "openbsd" +))] pub use self::bsd::*; /// Convert raw ioctl return value to a Nix result #[macro_export] #[doc(hidden)] macro_rules! convert_ioctl_res { - ($w:expr) => ( - { - $crate::errno::Errno::result($w) - } - ); + ($w:expr) => {{ + $crate::errno::Errno::result($w) + }}; } /// Generates a wrapper function for an ioctl that passes no data to the kernel. @@ -491,7 +497,7 @@ macro_rules! ioctl_write_ptr_bad { ) } -cfg_if!{ +cfg_if! { if #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] { /// Generates a wrapper function for a ioctl that writes an integer to the kernel. /// diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 9f0d037ecc..ddd4fdfc3b 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -1,10 +1,12 @@ //! Mostly platform-specific functionality -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - all(target_os = "linux", not(target_env = "uclibc")), - target_os = "macos", - target_os = "netbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + all(target_os = "linux", not(target_env = "uclibc")), + target_os = "macos", + target_os = "netbsd" +))] feature! { #![feature = "aio"] pub mod aio; @@ -31,16 +33,18 @@ feature! { pub mod eventfd; } -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "redox", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "redox", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd" +))] #[cfg(feature = "ioctl")] #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] #[macro_use] @@ -69,13 +73,15 @@ feature! { pub mod pthread; } -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] feature! { #![feature = "ptrace"] #[allow(missing_docs)] @@ -94,7 +100,12 @@ feature! { pub mod reboot; } -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos", target_os = "haiku")))] +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "illumos", + target_os = "haiku" +)))] feature! { #![feature = "resource"] pub mod resource; @@ -106,12 +117,14 @@ feature! { pub mod select; } -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos" +))] feature! { #![feature = "zerocopy"] pub mod sendfile; @@ -139,13 +152,14 @@ feature! { pub mod stat; } -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "openbsd" +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" ))] feature! { #![feature = "fs"] diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 9a4e90e4ce..f6a8c2d773 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -3,22 +3,22 @@ //! Operating system signals. -use crate::{Error, Result}; use crate::errno::Errno; -use std::mem; +use crate::{Error, Result}; +use cfg_if::cfg_if; use std::fmt; -use std::str::FromStr; +use std::mem; #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] use std::os::unix::io::RawFd; use std::ptr; -use cfg_if::cfg_if; +use std::str::FromStr; #[cfg(not(any(target_os = "openbsd", target_os = "redox")))] #[cfg(any(feature = "aio", feature = "signal"))] pub use self::sigevent::*; #[cfg(any(feature = "aio", feature = "process", feature = "signal"))] -libc_enum!{ +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. @@ -135,10 +135,19 @@ impl FromStr for Signal { "SIGPIPE" => Signal::SIGPIPE, "SIGALRM" => Signal::SIGALRM, "SIGTERM" => Signal::SIGTERM, - #[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"))))] + #[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" => Signal::SIGSTKFLT, "SIGCHLD" => Signal::SIGCHLD, "SIGCONT" => Signal::SIGCONT, @@ -154,17 +163,31 @@ impl FromStr for Signal { "SIGWINCH" => Signal::SIGWINCH, #[cfg(not(target_os = "haiku"))] "SIGIO" => Signal::SIGIO, - #[cfg(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux"))] + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ))] "SIGPWR" => Signal::SIGPWR, "SIGSYS" => Signal::SIGSYS, - #[cfg(not(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", - target_os = "redox", target_os = "haiku")))] + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux", + target_os = "redox", + target_os = "haiku" + )))] "SIGEMT" => Signal::SIGEMT, - #[cfg(not(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", - target_os = "redox", target_os = "haiku")))] + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux", + target_os = "redox", + target_os = "haiku" + )))] "SIGINFO" => Signal::SIGINFO, _ => return Err(Errno::EINVAL), }) @@ -195,9 +218,19 @@ impl Signal { Signal::SIGPIPE => "SIGPIPE", Signal::SIGALRM => "SIGALRM", Signal::SIGTERM => "SIGTERM", - #[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"))))] + #[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" + )) + ))] Signal::SIGSTKFLT => "SIGSTKFLT", Signal::SIGCHLD => "SIGCHLD", Signal::SIGCONT => "SIGCONT", @@ -213,17 +246,31 @@ impl Signal { Signal::SIGWINCH => "SIGWINCH", #[cfg(not(target_os = "haiku"))] Signal::SIGIO => "SIGIO", - #[cfg(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux"))] + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux" + ))] Signal::SIGPWR => "SIGPWR", Signal::SIGSYS => "SIGSYS", - #[cfg(not(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", - target_os = "redox", target_os = "haiku")))] + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux", + target_os = "redox", + target_os = "haiku" + )))] Signal::SIGEMT => "SIGEMT", - #[cfg(not(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", - target_os = "redox", target_os = "haiku")))] + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "linux", + target_os = "redox", + target_os = "haiku" + )))] Signal::SIGINFO => "SIGINFO", } } @@ -249,175 +296,70 @@ pub use self::Signal::*; #[cfg(target_os = "redox")] #[cfg(feature = "signal")] const SIGNALS: [Signal; 29] = [ - SIGHUP, - SIGINT, - SIGQUIT, - SIGILL, - SIGTRAP, - SIGABRT, - SIGBUS, - SIGFPE, - SIGKILL, - SIGUSR1, - SIGSEGV, - SIGUSR2, - SIGPIPE, - SIGALRM, - SIGTERM, - SIGCHLD, - SIGCONT, - SIGSTOP, - SIGTSTP, - SIGTTIN, - SIGTTOU, - SIGURG, - SIGXCPU, - SIGXFSZ, - SIGVTALRM, - SIGPROF, - SIGWINCH, - SIGIO, - SIGSYS]; + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, + SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, + SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, + SIGPROF, SIGWINCH, SIGIO, SIGSYS, +]; #[cfg(target_os = "haiku")] #[cfg(feature = "signal")] const SIGNALS: [Signal; 28] = [ - SIGHUP, - SIGINT, - SIGQUIT, - SIGILL, - SIGTRAP, - SIGABRT, - SIGBUS, - SIGFPE, - SIGKILL, - SIGUSR1, - SIGSEGV, - SIGUSR2, - SIGPIPE, - SIGALRM, - SIGTERM, - SIGCHLD, - SIGCONT, - SIGSTOP, - SIGTSTP, - SIGTTIN, - SIGTTOU, - SIGURG, - SIGXCPU, - SIGXFSZ, - SIGVTALRM, - SIGPROF, - SIGWINCH, - SIGSYS]; -#[cfg(all(any(target_os = "linux", target_os = "android", - target_os = "emscripten", target_os = "fuchsia"), - not(any(target_arch = "mips", target_arch = "mips64", - target_arch = "sparc64"))))] + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, + SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, + SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, + SIGPROF, SIGWINCH, SIGSYS, +]; +#[cfg(all( + any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia" + ), + not(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "sparc64" + )) +))] #[cfg(feature = "signal")] const SIGNALS: [Signal; 31] = [ - SIGHUP, - SIGINT, - SIGQUIT, - SIGILL, - SIGTRAP, - SIGABRT, - SIGBUS, - SIGFPE, - SIGKILL, - SIGUSR1, - SIGSEGV, - SIGUSR2, - SIGPIPE, - SIGALRM, - SIGTERM, - SIGSTKFLT, - SIGCHLD, - SIGCONT, - SIGSTOP, - SIGTSTP, - SIGTTIN, - SIGTTOU, - SIGURG, - SIGXCPU, - SIGXFSZ, - SIGVTALRM, - SIGPROF, - SIGWINCH, - SIGIO, - SIGPWR, - SIGSYS]; -#[cfg(all(any(target_os = "linux", target_os = "android", - target_os = "emscripten", target_os = "fuchsia"), - any(target_arch = "mips", target_arch = "mips64", - target_arch = "sparc64")))] + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, + SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD, + SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, + SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS, +]; +#[cfg(all( + any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia" + ), + any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64") +))] #[cfg(feature = "signal")] const SIGNALS: [Signal; 30] = [ - SIGHUP, - SIGINT, - SIGQUIT, - SIGILL, - SIGTRAP, - SIGABRT, - SIGBUS, - SIGFPE, - SIGKILL, - SIGUSR1, - SIGSEGV, - SIGUSR2, - SIGPIPE, - SIGALRM, - SIGTERM, - SIGCHLD, - SIGCONT, - SIGSTOP, - SIGTSTP, - SIGTTIN, - SIGTTOU, - SIGURG, - SIGXCPU, - SIGXFSZ, - SIGVTALRM, - SIGPROF, - SIGWINCH, - SIGIO, - SIGPWR, - SIGSYS]; -#[cfg(not(any(target_os = "linux", target_os = "android", - target_os = "fuchsia", target_os = "emscripten", - target_os = "redox", target_os = "haiku")))] + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, + SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, + SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, + SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS, +]; +#[cfg(not(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "emscripten", + target_os = "redox", + target_os = "haiku" +)))] #[cfg(feature = "signal")] const SIGNALS: [Signal; 31] = [ - SIGHUP, - SIGINT, - SIGQUIT, - SIGILL, - SIGTRAP, - SIGABRT, - SIGBUS, - SIGFPE, - SIGKILL, - SIGUSR1, - SIGSEGV, - SIGUSR2, - SIGPIPE, - SIGALRM, - SIGTERM, - SIGCHLD, - SIGCONT, - SIGSTOP, - SIGTSTP, - SIGTTIN, - SIGTTOU, - SIGURG, - SIGXCPU, - SIGXFSZ, - SIGVTALRM, - SIGPROF, - SIGWINCH, - SIGIO, - SIGSYS, - SIGEMT, - SIGINFO]; + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, + SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, + SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, + SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO, +]; feature! { #![feature = "signal"] @@ -469,7 +411,7 @@ cfg_if! { } #[cfg(feature = "signal")] -libc_bitflags!{ +libc_bitflags! { /// Controls the behavior of a [`SigAction`] #[cfg_attr(docsrs, doc(cfg(feature = "signal")))] pub struct SaFlags: SaFlags_t { @@ -1001,7 +943,6 @@ pub fn raise(signal: Signal) -> Result<()> { } } - feature! { #![any(feature = "aio", feature = "signal")] @@ -1161,9 +1102,9 @@ mod sigevent { #[cfg(test)] mod tests { + use super::*; #[cfg(not(target_os = "redox"))] use std::thread; - use super::*; #[test] fn test_contains() { @@ -1227,14 +1168,18 @@ mod tests { test_mask.add(SIGUSR1); assert!(test_mask.thread_set_mask().is_ok()); - let new_mask = SigSet::thread_get_mask() - .expect("Failed to get new mask!"); + let new_mask = + SigSet::thread_get_mask().expect("Failed to get new mask!"); assert!(new_mask.contains(SIGUSR1)); assert!(!new_mask.contains(SIGUSR2)); - prev_mask.thread_set_mask().expect("Failed to revert signal mask!"); - }).join().unwrap(); + prev_mask + .thread_set_mask() + .expect("Failed to revert signal mask!"); + }) + .join() + .unwrap(); } #[test] @@ -1247,7 +1192,9 @@ mod tests { assert!(mask.thread_block().is_ok()); assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); - }).join().unwrap(); + }) + .join() + .unwrap(); } #[test] @@ -1260,7 +1207,9 @@ mod tests { assert!(mask.thread_unblock().is_ok()); assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); - }).join().unwrap(); + }) + .join() + .unwrap(); } #[test] @@ -1276,14 +1225,16 @@ mod tests { let mut mask2 = SigSet::empty(); mask2.add(SIGUSR2); - let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK) - .unwrap(); + let oldmask = + mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap(); assert!(oldmask.contains(SIGUSR1)); assert!(!oldmask.contains(SIGUSR2)); assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2)); - }).join().unwrap(); + }) + .join() + .unwrap(); } #[test] @@ -1297,22 +1248,28 @@ mod tests { #[cfg(not(target_os = "redox"))] fn test_sigaction() { thread::spawn(|| { - extern fn test_sigaction_handler(_: libc::c_int) {} - extern fn test_sigaction_action(_: libc::c_int, - _: *mut libc::siginfo_t, _: *mut libc::c_void) {} + extern "C" fn test_sigaction_handler(_: libc::c_int) {} + extern "C" fn test_sigaction_action( + _: libc::c_int, + _: *mut libc::siginfo_t, + _: *mut libc::c_void, + ) { + } let handler_sig = SigHandler::Handler(test_sigaction_handler); - let flags = SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | - SaFlags::SA_SIGINFO; + let flags = + SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO; let mut mask = SigSet::empty(); mask.add(SIGUSR1); let action_sig = SigAction::new(handler_sig, flags, mask); - assert_eq!(action_sig.flags(), - SaFlags::SA_ONSTACK | SaFlags::SA_RESTART); + assert_eq!( + action_sig.flags(), + SaFlags::SA_ONSTACK | SaFlags::SA_RESTART + ); assert_eq!(action_sig.handler(), handler_sig); mask = action_sig.mask(); @@ -1328,7 +1285,9 @@ mod tests { let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask); assert_eq!(action_ign.handler(), SigHandler::SigIgn); - }).join().unwrap(); + }) + .join() + .unwrap(); } #[test] @@ -1342,6 +1301,8 @@ mod tests { raise(SIGUSR1).unwrap(); assert_eq!(mask.wait().unwrap(), SIGUSR1); - }).join().unwrap(); + }) + .join() + .unwrap(); } } diff --git a/src/sys/sysinfo.rs b/src/sys/sysinfo.rs index dc943c1adc..96f0433075 100644 --- a/src/sys/sysinfo.rs +++ b/src/sys/sysinfo.rs @@ -1,9 +1,9 @@ use libc::{self, SI_LOAD_SHIFT}; -use std::{cmp, mem}; use std::time::Duration; +use std::{cmp, mem}; -use crate::Result; use crate::errno::Errno; +use crate::Result; /// System info structure returned by `sysinfo`. #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] @@ -75,5 +75,5 @@ impl SysInfo { pub fn sysinfo() -> Result { let mut info = mem::MaybeUninit::uninit(); let res = unsafe { libc::sysinfo(info.as_mut_ptr()) }; - Errno::result(res).map(|_| unsafe{ SysInfo(info.assume_init()) }) + Errno::result(res).map(|_| unsafe { SysInfo(info.assume_init()) }) } diff --git a/src/sys/time.rs b/src/sys/time.rs index c29259b24a..c559cc4794 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -1,9 +1,10 @@ -use std::{cmp, fmt, ops}; -use std::time::Duration; -use std::convert::From; +#[cfg_attr(target_env = "musl", allow(deprecated))] +// https://github.com/rust-lang/libc/issues/1848 +pub use libc::{suseconds_t, time_t}; use libc::{timespec, timeval}; -#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 -pub use libc::{time_t, suseconds_t}; +use std::convert::From; +use std::time::Duration; +use std::{cmp, fmt, ops}; #[cfg(any( all(feature = "time", any(target_os = "android", target_os = "linux")), @@ -62,10 +63,12 @@ pub(crate) mod timer { }, it_value: *t.as_ref(), }), - Expiration::IntervalDelayed(start, interval) => TimerSpec(libc::itimerspec { - it_interval: *interval.as_ref(), - it_value: *start.as_ref(), - }), + Expiration::IntervalDelayed(start, interval) => { + TimerSpec(libc::itimerspec { + it_interval: *interval.as_ref(), + it_value: *start.as_ref(), + }) + } Expiration::Interval(t) => TimerSpec(libc::itimerspec { it_interval: *t.as_ref(), it_value: *t.as_ref(), @@ -94,7 +97,12 @@ pub(crate) mod timer { const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME; } } - #[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "dragonfly", target_os = "illumos"))] + #[cfg(any( + target_os = "freebsd", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "illumos" + ))] bitflags! { /// Flags that are used for arming the timer. pub struct TimerSetTimeFlags: libc::c_int { @@ -117,10 +125,15 @@ pub(crate) mod timer { it_interval: int_ts, it_value: val_ts, }) => { - if (int_ts.tv_sec == val_ts.tv_sec) && (int_ts.tv_nsec == val_ts.tv_nsec) { + if (int_ts.tv_sec == val_ts.tv_sec) + && (int_ts.tv_nsec == val_ts.tv_nsec) + { Expiration::Interval(int_ts.into()) } else { - Expiration::IntervalDelayed(val_ts.into(), int_ts.into()) + Expiration::IntervalDelayed( + val_ts.into(), + int_ts.into(), + ) } } } @@ -136,14 +149,16 @@ pub trait TimeValLike: Sized { #[inline] fn hours(hours: i64) -> Self { - let secs = hours.checked_mul(SECS_PER_HOUR) + let secs = hours + .checked_mul(SECS_PER_HOUR) .expect("TimeValLike::hours ouf of bounds"); Self::seconds(secs) } #[inline] fn minutes(minutes: i64) -> Self { - let secs = minutes.checked_mul(SECS_PER_MINUTE) + let secs = minutes + .checked_mul(SECS_PER_MINUTE) .expect("TimeValLike::minutes out of bounds"); Self::seconds(secs) } @@ -243,15 +258,23 @@ impl PartialOrd for TimeSpec { impl TimeValLike for TimeSpec { #[inline] fn seconds(seconds: i64) -> TimeSpec { - assert!((TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds), - "TimeSpec out of bounds; seconds={}", seconds); - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 }) + assert!( + (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds), + "TimeSpec out of bounds; seconds={}", + seconds + ); + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 + TimeSpec(timespec { + tv_sec: seconds as time_t, + tv_nsec: 0, + }) } #[inline] fn milliseconds(milliseconds: i64) -> TimeSpec { - let nanoseconds = milliseconds.checked_mul(1_000_000) + let nanoseconds = milliseconds + .checked_mul(1_000_000) .expect("TimeSpec::milliseconds out of bounds"); TimeSpec::nanoseconds(nanoseconds) @@ -260,7 +283,8 @@ impl TimeValLike for TimeSpec { /// Makes a new `TimeSpec` with given number of microseconds. #[inline] fn microseconds(microseconds: i64) -> TimeSpec { - let nanoseconds = microseconds.checked_mul(1_000) + let nanoseconds = microseconds + .checked_mul(1_000) .expect("TimeSpec::milliseconds out of bounds"); TimeSpec::nanoseconds(nanoseconds) @@ -270,11 +294,16 @@ impl TimeValLike for TimeSpec { #[inline] fn nanoseconds(nanoseconds: i64) -> TimeSpec { let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); - assert!((TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs), - "TimeSpec out of bounds"); - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - TimeSpec(timespec {tv_sec: secs as time_t, - tv_nsec: nanos as timespec_tv_nsec_t }) + assert!( + (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs), + "TimeSpec out of bounds" + ); + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 + TimeSpec(timespec { + tv_sec: secs as time_t, + tv_nsec: nanos as timespec_tv_nsec_t, + }) } fn num_seconds(&self) -> i64 { @@ -319,10 +348,11 @@ impl TimeSpec { } pub const fn from_duration(duration: Duration) -> Self { - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 TimeSpec(timespec { tv_sec: duration.as_secs() as time_t, - tv_nsec: duration.subsec_nanos() as timespec_tv_nsec_t + tv_nsec: duration.subsec_nanos() as timespec_tv_nsec_t, }) } @@ -343,8 +373,7 @@ impl ops::Add for TimeSpec { type Output = TimeSpec; fn add(self, rhs: TimeSpec) -> TimeSpec { - TimeSpec::nanoseconds( - self.num_nanoseconds() + rhs.num_nanoseconds()) + TimeSpec::nanoseconds(self.num_nanoseconds() + rhs.num_nanoseconds()) } } @@ -352,8 +381,7 @@ impl ops::Sub for TimeSpec { type Output = TimeSpec; fn sub(self, rhs: TimeSpec) -> TimeSpec { - TimeSpec::nanoseconds( - self.num_nanoseconds() - rhs.num_nanoseconds()) + TimeSpec::nanoseconds(self.num_nanoseconds() - rhs.num_nanoseconds()) } } @@ -361,7 +389,9 @@ impl ops::Mul for TimeSpec { type Output = TimeSpec; fn mul(self, rhs: i32) -> TimeSpec { - let usec = self.num_nanoseconds().checked_mul(i64::from(rhs)) + let usec = self + .num_nanoseconds() + .checked_mul(i64::from(rhs)) .expect("TimeSpec multiply out of bounds"); TimeSpec::nanoseconds(usec) @@ -407,8 +437,6 @@ impl fmt::Display for TimeSpec { } } - - #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct TimeVal(timeval); @@ -456,15 +484,23 @@ impl PartialOrd for TimeVal { impl TimeValLike for TimeVal { #[inline] fn seconds(seconds: i64) -> TimeVal { - assert!((TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds), - "TimeVal out of bounds; seconds={}", seconds); - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 }) + assert!( + (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds), + "TimeVal out of bounds; seconds={}", + seconds + ); + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 + TimeVal(timeval { + tv_sec: seconds as time_t, + tv_usec: 0, + }) } #[inline] fn milliseconds(milliseconds: i64) -> TimeVal { - let microseconds = milliseconds.checked_mul(1_000) + let microseconds = milliseconds + .checked_mul(1_000) .expect("TimeVal::milliseconds out of bounds"); TimeVal::microseconds(microseconds) @@ -474,11 +510,16 @@ impl TimeValLike for TimeVal { #[inline] fn microseconds(microseconds: i64) -> TimeVal { let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); - assert!((TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), - "TimeVal out of bounds"); - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - TimeVal(timeval {tv_sec: secs as time_t, - tv_usec: micros as suseconds_t }) + assert!( + (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), + "TimeVal out of bounds" + ); + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 + TimeVal(timeval { + tv_sec: secs as time_t, + tv_usec: micros as suseconds_t, + }) } /// Makes a new `TimeVal` with given number of nanoseconds. Some precision @@ -487,11 +528,16 @@ impl TimeValLike for TimeVal { fn nanoseconds(nanoseconds: i64) -> TimeVal { let microseconds = nanoseconds / 1000; let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); - assert!((TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), - "TimeVal out of bounds"); - #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 - TimeVal(timeval {tv_sec: secs as time_t, - tv_usec: micros as suseconds_t }) + assert!( + (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), + "TimeVal out of bounds" + ); + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 + TimeVal(timeval { + tv_sec: secs as time_t, + tv_usec: micros as suseconds_t, + }) } fn num_seconds(&self) -> i64 { @@ -548,8 +594,7 @@ impl ops::Add for TimeVal { type Output = TimeVal; fn add(self, rhs: TimeVal) -> TimeVal { - TimeVal::microseconds( - self.num_microseconds() + rhs.num_microseconds()) + TimeVal::microseconds(self.num_microseconds() + rhs.num_microseconds()) } } @@ -557,8 +602,7 @@ impl ops::Sub for TimeVal { type Output = TimeVal; fn sub(self, rhs: TimeVal) -> TimeVal { - TimeVal::microseconds( - self.num_microseconds() - rhs.num_microseconds()) + TimeVal::microseconds(self.num_microseconds() - rhs.num_microseconds()) } } @@ -566,7 +610,9 @@ impl ops::Mul for TimeVal { type Output = TimeVal; fn mul(self, rhs: i32) -> TimeVal { - let usec = self.num_microseconds().checked_mul(i64::from(rhs)) + let usec = self + .num_microseconds() + .checked_mul(i64::from(rhs)) .expect("TimeVal multiply out of bounds"); TimeVal::microseconds(usec) @@ -624,18 +670,16 @@ fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { #[inline] fn div_floor_64(this: i64, other: i64) -> i64 { match div_rem_64(this, other) { - (d, r) if (r > 0 && other < 0) - || (r < 0 && other > 0) => d - 1, - (d, _) => d, + (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1, + (d, _) => d, } } #[inline] fn mod_floor_64(this: i64, other: i64) -> i64 { match this % other { - r if (r > 0 && other < 0) - || (r < 0 && other > 0) => r + other, - r => r, + r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other, + r => r, } } @@ -652,10 +696,14 @@ mod test { #[test] pub fn test_timespec() { assert!(TimeSpec::seconds(1) != TimeSpec::zero()); - assert_eq!(TimeSpec::seconds(1) + TimeSpec::seconds(2), - TimeSpec::seconds(3)); - assert_eq!(TimeSpec::minutes(3) + TimeSpec::seconds(2), - TimeSpec::seconds(182)); + assert_eq!( + TimeSpec::seconds(1) + TimeSpec::seconds(2), + TimeSpec::seconds(3) + ); + assert_eq!( + TimeSpec::minutes(3) + TimeSpec::seconds(2), + TimeSpec::seconds(182) + ); } #[test] @@ -690,17 +738,24 @@ mod test { assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds"); assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds"); assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds"); - assert_eq!(TimeSpec::nanoseconds(42).to_string(), "0.000000042 seconds"); + assert_eq!( + TimeSpec::nanoseconds(42).to_string(), + "0.000000042 seconds" + ); assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds"); } #[test] pub fn test_timeval() { assert!(TimeVal::seconds(1) != TimeVal::zero()); - assert_eq!(TimeVal::seconds(1) + TimeVal::seconds(2), - TimeVal::seconds(3)); - assert_eq!(TimeVal::minutes(3) + TimeVal::seconds(2), - TimeVal::seconds(182)); + assert_eq!( + TimeVal::seconds(1) + TimeVal::seconds(2), + TimeVal::seconds(3) + ); + assert_eq!( + TimeVal::minutes(3) + TimeVal::seconds(2), + TimeVal::seconds(182) + ); } #[test] diff --git a/src/unistd.rs b/src/unistd.rs index 5d8a56378d..fe8ec8408a 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -1,28 +1,30 @@ //! Safe wrappers around functions found in libc "unistd.h" header -#[cfg(not(target_os = "redox"))] -use cfg_if::cfg_if; use crate::errno::{self, Errno}; -use crate::{Error, Result, NixPath}; #[cfg(not(target_os = "redox"))] #[cfg(feature = "fs")] -use crate::fcntl::{AtFlags, at_rawfd}; -use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t, - uid_t, gid_t, mode_t, PATH_MAX}; +use crate::fcntl::{at_rawfd, AtFlags}; #[cfg(feature = "fs")] -use crate::fcntl::{FdFlag, OFlag, fcntl, FcntlArg::F_SETFD}; -use std::{fmt, mem, ptr}; +use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; +#[cfg(feature = "fs")] +use crate::sys::stat::Mode; +use crate::{Error, NixPath, Result}; +#[cfg(not(target_os = "redox"))] +use cfg_if::cfg_if; +use libc::{ + self, c_char, c_int, c_long, c_uint, c_void, gid_t, mode_t, off_t, pid_t, + size_t, uid_t, PATH_MAX, +}; use std::convert::Infallible; use std::ffi::{CStr, OsString}; #[cfg(not(target_os = "redox"))] use std::ffi::{CString, OsStr}; -use std::os::unix::ffi::OsStringExt; #[cfg(not(target_os = "redox"))] use std::os::unix::ffi::OsStrExt; +use std::os::unix::ffi::OsStringExt; use std::os::unix::io::RawFd; use std::path::PathBuf; -#[cfg(feature = "fs")] -use crate::sys::stat::Mode; +use std::{fmt, mem, ptr}; feature! { #![feature = "fs"] @@ -30,18 +32,22 @@ feature! { pub use self::pivot_root::*; } -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] pub use self::setres::*; -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] pub use self::getres::*; feature! { @@ -1045,7 +1051,9 @@ pub fn close(fd: RawFd) -> Result<()> { /// /// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html) pub fn read(fd: RawFd, buf: &mut [u8]) -> Result { - let res = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) }; + let res = unsafe { + libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) + }; Errno::result(res).map(|r| r as usize) } @@ -1054,7 +1062,9 @@ pub fn read(fd: RawFd, buf: &mut [u8]) -> Result { /// /// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html) pub fn write(fd: RawFd, buf: &[u8]) -> Result { - let res = unsafe { libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) }; + let res = unsafe { + libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) + }; Errno::result(res).map(|r| r as usize) } @@ -2710,11 +2720,13 @@ mod pivot_root { } } -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] mod setres { feature! { #![feature = "user"] @@ -2757,11 +2769,13 @@ mod setres { } } -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] mod getres { feature! { #![feature = "user"] @@ -2827,7 +2841,7 @@ mod getres { } #[cfg(feature = "fs")] -libc_bitflags!{ +libc_bitflags! { /// Options for access() #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] pub struct AccessFlags : c_int { diff --git a/test/common/mod.rs b/test/common/mod.rs index caa39ab4d4..bb056aab87 100644 --- a/test/common/mod.rs +++ b/test/common/mod.rs @@ -1,6 +1,7 @@ use cfg_if::cfg_if; -#[macro_export] macro_rules! skip { +#[macro_export] +macro_rules! skip { ($($reason: expr),+) => { use ::std::io::{self, Write}; @@ -33,7 +34,8 @@ cfg_if! { /// Skip the test if we don't have the ability to mount file systems. #[cfg(target_os = "freebsd")] -#[macro_export] macro_rules! require_mount { +#[macro_export] +macro_rules! require_mount { ($name:expr) => { use ::sysctl::{CtlValue, Sysctl}; use nix::unistd::Uid; @@ -41,35 +43,40 @@ cfg_if! { let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap(); if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap() { - skip!("{} requires the ability to mount file systems. Skipping test.", $name); + skip!( + "{} requires the ability to mount file systems. Skipping test.", + $name + ); } - } + }; } -#[cfg(any(target_os = "linux", target_os= "android"))] -#[macro_export] macro_rules! skip_if_cirrus { +#[cfg(any(target_os = "linux", target_os = "android"))] +#[macro_export] +macro_rules! skip_if_cirrus { ($reason:expr) => { if std::env::var_os("CIRRUS_CI").is_some() { skip!("{}", $reason); } - } + }; } #[cfg(target_os = "freebsd")] -#[macro_export] macro_rules! skip_if_jailed { +#[macro_export] +macro_rules! skip_if_jailed { ($name:expr) => { use ::sysctl::{CtlValue, Sysctl}; let ctl = ::sysctl::Ctl::new("security.jail.jailed").unwrap(); - if let CtlValue::Int(1) = ctl.value().unwrap() - { + if let CtlValue::Int(1) = ctl.value().unwrap() { skip!("{} cannot run in a jail. Skipping test.", $name); } - } + }; } #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] -#[macro_export] macro_rules! skip_if_not_root { +#[macro_export] +macro_rules! skip_if_not_root { ($name:expr) => { use nix::unistd::Uid; diff --git a/test/sys/mod.rs b/test/sys/mod.rs index 768d4d302b..ed4ad736fb 100644 --- a/test/sys/mod.rs +++ b/test/sys/mod.rs @@ -5,43 +5,55 @@ mod test_signal; // works or not heavily depends on which pthread implementation is chosen // by the user at link time. For this reason we do not want to run aio test // cases on DragonFly. -#[cfg(any(target_os = "freebsd", - target_os = "ios", - all(target_os = "linux", not(target_env = "uclibc")), - target_os = "macos", - target_os = "netbsd"))] +#[cfg(any( + target_os = "freebsd", + target_os = "ios", + all(target_os = "linux", not(target_env = "uclibc")), + target_os = "macos", + target_os = "netbsd" +))] mod test_aio; +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] +mod test_ioctl; #[cfg(not(target_os = "redox"))] mod test_mman; +#[cfg(not(target_os = "redox"))] +mod test_select; #[cfg(target_os = "linux")] mod test_signalfd; #[cfg(not(any(target_os = "redox", target_os = "haiku")))] mod test_socket; #[cfg(not(any(target_os = "redox")))] mod test_sockopt; -#[cfg(not(target_os = "redox"))] -mod test_select; #[cfg(any(target_os = "android", target_os = "linux"))] mod test_sysinfo; -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] mod test_termios; -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] -mod test_ioctl; -mod test_wait; mod test_uio; +mod test_wait; #[cfg(any(target_os = "android", target_os = "linux"))] mod test_epoll; #[cfg(target_os = "linux")] mod test_inotify; mod test_pthread; -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] mod test_ptrace; #[cfg(any(target_os = "android", target_os = "linux"))] mod test_timerfd; diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index ca35b5f88c..b4ea6757d9 100644 --- a/test/sys/test_aio.rs +++ b/test/sys/test_aio.rs @@ -4,8 +4,7 @@ use std::{ os::unix::io::AsRawFd, pin::Pin, sync::atomic::{AtomicBool, Ordering}, - thread, - time, + thread, time, }; use libc::c_int; @@ -14,12 +13,7 @@ use nix::{ sys::{ aio::*, signal::{ - sigaction, - SaFlags, - SigAction, - SigHandler, - SigSet, - SigevNotify, + sigaction, SaFlags, SigAction, SigHandler, SigSet, SigevNotify, Signal, }, time::{TimeSpec, TimeValLike}, @@ -58,7 +52,7 @@ mod aio_fsync { AioFsyncMode::O_SYNC, 42, SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, + signal: Signal::SIGUSR2, si_value: 99, }, ); @@ -126,7 +120,7 @@ mod aio_read { &mut rbuf, 42, //priority SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, + signal: Signal::SIGUSR2, si_value: 99, }, ); @@ -254,7 +248,7 @@ mod aio_readv { &mut rbufs, 42, //priority SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, + signal: Signal::SIGUSR2, si_value: 99, }, ); @@ -314,7 +308,7 @@ mod aio_write { &wbuf, 42, //priority SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, + signal: Signal::SIGUSR2, si_value: 99, }, ); @@ -455,7 +449,7 @@ mod aio_writev { &wbufs, 42, //priority SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, + signal: Signal::SIGUSR2, si_value: 99, }, ); @@ -536,7 +530,7 @@ fn sigev_signal() { WBUF, 0, //priority SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, + signal: Signal::SIGUSR2, si_value: 0, //TODO: validate in sigfunc }, )); @@ -624,8 +618,8 @@ fn test_aio_suspend() { Ok(_) => (), }; } - if rcb.as_mut().error() != Err(Errno::EINPROGRESS) && - wcb.as_mut().error() != Err(Errno::EINPROGRESS) + if rcb.as_mut().error() != Err(Errno::EINPROGRESS) + && wcb.as_mut().error() != Err(Errno::EINPROGRESS) { break; } diff --git a/test/sys/test_aio_drop.rs b/test/sys/test_aio_drop.rs index 0836a5422d..bbe6623fd7 100644 --- a/test/sys/test_aio_drop.rs +++ b/test/sys/test_aio_drop.rs @@ -3,13 +3,17 @@ // the AIO subsystem and causes subsequent tests to fail #[test] #[should_panic(expected = "Dropped an in-progress AioCb")] -#[cfg(all(not(target_env = "musl"), - not(target_env = "uclibc"), - any(target_os = "linux", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd")))] +#[cfg(all( + not(target_env = "musl"), + not(target_env = "uclibc"), + any( + target_os = "linux", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd" + ) +))] fn test_drop() { use nix::sys::aio::*; use nix::sys::signal::*; @@ -20,10 +24,12 @@ fn test_drop() { let f = tempfile().unwrap(); f.set_len(6).unwrap(); - let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), - 2, //offset - WBUF, - 0, //priority - SigevNotify::SigevNone)); + let mut aiocb = Box::pin(AioWrite::new( + f.as_raw_fd(), + 2, //offset + WBUF, + 0, //priority + SigevNotify::SigevNone, + )); aiocb.as_mut().submit().unwrap(); } diff --git a/test/sys/test_epoll.rs b/test/sys/test_epoll.rs index 8d44cd08f0..fafbd7499d 100644 --- a/test/sys/test_epoll.rs +++ b/test/sys/test_epoll.rs @@ -1,6 +1,6 @@ -use nix::sys::epoll::{EpollCreateFlags, EpollFlags, EpollOp, EpollEvent}; -use nix::sys::epoll::{epoll_create1, epoll_ctl}; use nix::errno::Errno; +use nix::sys::epoll::{epoll_create1, epoll_ctl}; +use nix::sys::epoll::{EpollCreateFlags, EpollEvent, EpollFlags, EpollOp}; #[test] pub fn test_epoll_errno() { @@ -17,7 +17,8 @@ pub fn test_epoll_errno() { #[test] pub fn test_epoll_ctl() { let efd = epoll_create1(EpollCreateFlags::empty()).unwrap(); - let mut event = EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1); + let mut event = + EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1); epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, &mut event).unwrap(); epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None).unwrap(); } diff --git a/test/sys/test_inotify.rs b/test/sys/test_inotify.rs index 137816a352..bb5851a903 100644 --- a/test/sys/test_inotify.rs +++ b/test/sys/test_inotify.rs @@ -1,15 +1,16 @@ -use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify}; use nix::errno::Errno; +use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify}; use std::ffi::OsString; use std::fs::{rename, File}; #[test] pub fn test_inotify() { - let instance = Inotify::init(InitFlags::IN_NONBLOCK) - .unwrap(); + let instance = Inotify::init(InitFlags::IN_NONBLOCK).unwrap(); let tempdir = tempfile::tempdir().unwrap(); - instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap(); + instance + .add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS) + .unwrap(); let events = instance.read_events(); assert_eq!(events.unwrap_err(), Errno::EAGAIN); @@ -22,11 +23,12 @@ pub fn test_inotify() { #[test] pub fn test_inotify_multi_events() { - let instance = Inotify::init(InitFlags::IN_NONBLOCK) - .unwrap(); + let instance = Inotify::init(InitFlags::IN_NONBLOCK).unwrap(); let tempdir = tempfile::tempdir().unwrap(); - instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap(); + instance + .add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS) + .unwrap(); let events = instance.read_events(); assert_eq!(events.unwrap_err(), Errno::EAGAIN); diff --git a/test/sys/test_ioctl.rs b/test/sys/test_ioctl.rs index 236d24268a..7a603c5bba 100644 --- a/test/sys/test_ioctl.rs +++ b/test/sys/test_ioctl.rs @@ -32,7 +32,12 @@ ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32); mod linux { #[test] fn test_op_none() { - if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){ + if cfg!(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { assert_eq!(request_code_none!(b'q', 10) as u32, 0x2000_710A); assert_eq!(request_code_none!(b'a', 255) as u32, 0x2000_61FF); } else { @@ -43,7 +48,12 @@ mod linux { #[test] fn test_op_write() { - if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){ + if cfg!(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x8001_7A0A); assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x8200_7A0A); } else { @@ -55,19 +65,27 @@ mod linux { #[cfg(target_pointer_width = "64")] #[test] fn test_op_write_64() { - if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){ - assert_eq!(request_code_write!(b'z', 10, 1u64 << 32) as u32, - 0x8000_7A0A); + if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) { + assert_eq!( + request_code_write!(b'z', 10, 1u64 << 32) as u32, + 0x8000_7A0A + ); } else { - assert_eq!(request_code_write!(b'z', 10, 1u64 << 32) as u32, - 0x4000_7A0A); + assert_eq!( + request_code_write!(b'z', 10, 1u64 << 32) as u32, + 0x4000_7A0A + ); } - } #[test] fn test_op_read() { - if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){ + if cfg!(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc", + target_arch = "powerpc64" + )) { assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x4001_7A0A); assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x4200_7A0A); } else { @@ -79,12 +97,16 @@ mod linux { #[cfg(target_pointer_width = "64")] #[test] fn test_op_read_64() { - if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){ - assert_eq!(request_code_read!(b'z', 10, 1u64 << 32) as u32, - 0x4000_7A0A); + if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) { + assert_eq!( + request_code_read!(b'z', 10, 1u64 << 32) as u32, + 0x4000_7A0A + ); } else { - assert_eq!(request_code_read!(b'z', 10, 1u64 << 32) as u32, - 0x8000_7A0A); + assert_eq!( + request_code_read!(b'z', 10, 1u64 << 32) as u32, + 0x8000_7A0A + ); } } @@ -97,17 +119,21 @@ mod linux { #[cfg(target_pointer_width = "64")] #[test] fn test_op_read_write_64() { - assert_eq!(request_code_readwrite!(b'z', 10, 1u64 << 32) as u32, - 0xC000_7A0A); + assert_eq!( + request_code_readwrite!(b'z', 10, 1u64 << 32) as u32, + 0xC000_7A0A + ); } } -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] mod bsd { #[test] fn test_op_none() { @@ -164,8 +190,8 @@ mod linux_ioctls { use std::mem; use std::os::unix::io::AsRawFd; + use libc::{termios, TCGETS, TCSBRK, TCSETS, TIOCNXCL}; use tempfile::tempfile; - use libc::{TCGETS, TCSBRK, TCSETS, TIOCNXCL, termios}; use nix::errno::Errno; @@ -255,7 +281,7 @@ mod linux_ioctls { } // From linux/videodev2.h - ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio); + ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio); #[test] fn test_ioctl_readwrite() { let file = tempfile().unwrap(); @@ -281,7 +307,12 @@ mod linux_ioctls { } // From linux/spi/spidev.h - ioctl_write_buf!(spi_ioc_message, super::SPI_IOC_MAGIC, super::SPI_IOC_MESSAGE, spi_ioc_transfer); + ioctl_write_buf!( + spi_ioc_message, + super::SPI_IOC_MAGIC, + super::SPI_IOC_MESSAGE, + spi_ioc_transfer + ); #[test] fn test_ioctl_write_buf() { let file = tempfile().unwrap(); @@ -298,8 +329,8 @@ mod freebsd_ioctls { use std::mem; use std::os::unix::io::AsRawFd; - use tempfile::tempfile; use libc::termios; + use tempfile::tempfile; use nix::errno::Errno; diff --git a/test/sys/test_mman.rs b/test/sys/test_mman.rs index 8858375a3c..75cbf6ce8c 100644 --- a/test/sys/test_mman.rs +++ b/test/sys/test_mman.rs @@ -3,53 +3,73 @@ use nix::sys::mman::{mmap, MapFlags, ProtFlags}; #[test] fn test_mmap_anonymous() { unsafe { - let ptr = mmap(std::ptr::null_mut(), 1, - ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, -1, 0) - .unwrap() as *mut u8; - assert_eq !(*ptr, 0x00u8); + let ptr = mmap( + std::ptr::null_mut(), + 1, + ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, + MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, + -1, + 0, + ) + .unwrap() as *mut u8; + assert_eq!(*ptr, 0x00u8); *ptr = 0xffu8; - assert_eq !(*ptr, 0xffu8); + assert_eq!(*ptr, 0xffu8); } } #[test] #[cfg(any(target_os = "linux", target_os = "netbsd"))] fn test_mremap_grow() { - use nix::sys::mman::{mremap, MRemapFlags}; use nix::libc::{c_void, size_t}; + use nix::sys::mman::{mremap, MRemapFlags}; - const ONE_K : size_t = 1024; - let slice : &mut[u8] = unsafe { - let mem = mmap(std::ptr::null_mut(), ONE_K, - ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0) - .unwrap(); - std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K) + const ONE_K: size_t = 1024; + let slice: &mut [u8] = unsafe { + let mem = mmap( + std::ptr::null_mut(), + ONE_K, + ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, + MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, + -1, + 0, + ) + .unwrap(); + std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) }; - assert_eq !(slice[ONE_K - 1], 0x00); + assert_eq!(slice[ONE_K - 1], 0x00); slice[ONE_K - 1] = 0xFF; - assert_eq !(slice[ONE_K - 1], 0xFF); + assert_eq!(slice[ONE_K - 1], 0xFF); - let slice : &mut[u8] = unsafe { + let slice: &mut [u8] = unsafe { #[cfg(target_os = "linux")] - let mem = mremap(slice.as_mut_ptr() as * mut c_void, ONE_K, 10 * ONE_K, - MRemapFlags::MREMAP_MAYMOVE, None) - .unwrap(); + let mem = mremap( + slice.as_mut_ptr() as *mut c_void, + ONE_K, + 10 * ONE_K, + MRemapFlags::MREMAP_MAYMOVE, + None, + ) + .unwrap(); #[cfg(target_os = "netbsd")] - let mem = mremap(slice.as_mut_ptr() as * mut c_void, ONE_K, 10 * ONE_K, - MRemapFlags::MAP_REMAPDUP, None) - .unwrap(); - std::slice::from_raw_parts_mut(mem as * mut u8, 10 * ONE_K) + let mem = mremap( + slice.as_mut_ptr() as *mut c_void, + ONE_K, + 10 * ONE_K, + MRemapFlags::MAP_REMAPDUP, + None, + ) + .unwrap(); + std::slice::from_raw_parts_mut(mem as *mut u8, 10 * ONE_K) }; // The first KB should still have the old data in it. - assert_eq !(slice[ONE_K - 1], 0xFF); + assert_eq!(slice[ONE_K - 1], 0xFF); // The additional range should be zero-init'd and accessible. - assert_eq !(slice[10 * ONE_K - 1], 0x00); + assert_eq!(slice[10 * ONE_K - 1], 0x00); slice[10 * ONE_K - 1] = 0xFF; - assert_eq !(slice[10 * ONE_K - 1], 0xFF); + assert_eq!(slice[10 * ONE_K - 1], 0xFF); } #[test] @@ -57,31 +77,41 @@ fn test_mremap_grow() { // Segfaults for unknown reasons under QEMU for 32-bit targets #[cfg_attr(all(target_pointer_width = "32", qemu), ignore)] fn test_mremap_shrink() { - use nix::sys::mman::{mremap, MRemapFlags}; use nix::libc::{c_void, size_t}; + use nix::sys::mman::{mremap, MRemapFlags}; - const ONE_K : size_t = 1024; - let slice : &mut[u8] = unsafe { - let mem = mmap(std::ptr::null_mut(), 10 * ONE_K, - ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0) - .unwrap(); - std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K) + const ONE_K: size_t = 1024; + let slice: &mut [u8] = unsafe { + let mem = mmap( + std::ptr::null_mut(), + 10 * ONE_K, + ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, + MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, + -1, + 0, + ) + .unwrap(); + std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) }; - assert_eq !(slice[ONE_K - 1], 0x00); + assert_eq!(slice[ONE_K - 1], 0x00); slice[ONE_K - 1] = 0xFF; - assert_eq !(slice[ONE_K - 1], 0xFF); + assert_eq!(slice[ONE_K - 1], 0xFF); - let slice : &mut[u8] = unsafe { - let mem = mremap(slice.as_mut_ptr() as * mut c_void, 10 * ONE_K, ONE_K, - MRemapFlags::empty(), None) - .unwrap(); + let slice: &mut [u8] = unsafe { + let mem = mremap( + slice.as_mut_ptr() as *mut c_void, + 10 * ONE_K, + ONE_K, + MRemapFlags::empty(), + None, + ) + .unwrap(); // Since we didn't supply MREMAP_MAYMOVE, the address should be the // same. - assert_eq !(mem, slice.as_mut_ptr() as * mut c_void); - std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K) + assert_eq!(mem, slice.as_mut_ptr() as *mut c_void); + std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) }; // The first KB should still be accessible and have the old data in it. - assert_eq !(slice[ONE_K - 1], 0xFF); + assert_eq!(slice[ONE_K - 1], 0xFF); } diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs index 8556a54845..e514832b82 100644 --- a/test/sys/test_ptrace.rs +++ b/test/sys/test_ptrace.rs @@ -1,13 +1,14 @@ -#[cfg(all(target_os = "linux", - any(target_arch = "x86_64", - target_arch = "x86"), - target_env = "gnu"))] +#[cfg(all( + target_os = "linux", + any(target_arch = "x86_64", target_arch = "x86"), + target_env = "gnu" +))] use memoffset::offset_of; use nix::errno::Errno; -use nix::unistd::getpid; use nix::sys::ptrace; #[cfg(any(target_os = "android", target_os = "linux"))] use nix::sys::ptrace::Options; +use nix::unistd::getpid; #[cfg(any(target_os = "android", target_os = "linux"))] use std::mem; @@ -20,8 +21,9 @@ fn test_ptrace() { // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS require_capability!("test_ptrace", CAP_SYS_PTRACE); let err = ptrace::attach(getpid()).unwrap_err(); - assert!(err == Errno::EPERM || err == Errno::EINVAL || - err == Errno::ENOSYS); + assert!( + err == Errno::EPERM || err == Errno::EINVAL || err == Errno::ENOSYS + ); } // Just make sure ptrace_setoptions can be called at all, for now. @@ -29,7 +31,8 @@ fn test_ptrace() { #[cfg(any(target_os = "android", target_os = "linux"))] fn test_ptrace_setoptions() { require_capability!("test_ptrace_setoptions", CAP_SYS_PTRACE); - let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err(); + let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD) + .unwrap_err(); assert!(err != Errno::EOPNOTSUPP); } @@ -63,7 +66,6 @@ fn test_ptrace_setsiginfo() { } } - #[test] fn test_ptrace_cont() { use nix::sys::ptrace; @@ -87,7 +89,7 @@ fn test_ptrace_cont() { return; } - match unsafe{fork()}.expect("Error: Fork Failed") { + match unsafe { fork() }.expect("Error: Fork Failed") { Child => { ptrace::traceme().unwrap(); // As recommended by ptrace(2), raise SIGTRAP to pause the child @@ -95,15 +97,22 @@ fn test_ptrace_cont() { loop { raise(Signal::SIGTRAP).unwrap(); } - - }, + } Parent { child } => { - assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP))); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)) + ); ptrace::cont(child, None).unwrap(); - assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP))); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)) + ); ptrace::cont(child, Some(Signal::SIGKILL)).unwrap(); match waitpid(child, None) { - Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => { + Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) + if pid == child => + { // FIXME It's been observed on some systems (apple) the // tracee may not be killed but remain as a zombie process // affecting other wait based tests. Add an extra kill just @@ -115,7 +124,7 @@ fn test_ptrace_cont() { } _ => panic!("The process should have been killed"), } - }, + } } } @@ -134,22 +143,28 @@ fn test_ptrace_interrupt() { let _m = crate::FORK_MTX.lock(); - match unsafe{fork()}.expect("Error: Fork Failed") { - Child => { - loop { - sleep(Duration::from_millis(1000)); - } - + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => loop { + sleep(Duration::from_millis(1000)); }, Parent { child } => { - ptrace::seize(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap(); + ptrace::seize(child, ptrace::Options::PTRACE_O_TRACESYSGOOD) + .unwrap(); ptrace::interrupt(child).unwrap(); - assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, Signal::SIGTRAP, 128))); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::PtraceEvent(child, Signal::SIGTRAP, 128)) + ); ptrace::syscall(child, None).unwrap(); - assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::PtraceSyscall(child)) + ); ptrace::detach(child, Some(Signal::SIGKILL)).unwrap(); match waitpid(child, None) { - Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => { + Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) + if pid == child => + { let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); @@ -157,19 +172,20 @@ fn test_ptrace_interrupt() { } _ => panic!("The process should have been killed"), } - }, + } } } // ptrace::{setoptions, getregs} are only available in these platforms -#[cfg(all(target_os = "linux", - any(target_arch = "x86_64", - target_arch = "x86"), - target_env = "gnu"))] +#[cfg(all( + target_os = "linux", + any(target_arch = "x86_64", target_arch = "x86"), + target_env = "gnu" +))] #[test] fn test_ptrace_syscall() { - use nix::sys::signal::kill; use nix::sys::ptrace; + use nix::sys::signal::kill; use nix::sys::signal::Signal; use nix::sys::wait::{waitpid, WaitStatus}; use nix::unistd::fork; @@ -180,27 +196,35 @@ fn test_ptrace_syscall() { let _m = crate::FORK_MTX.lock(); - match unsafe{fork()}.expect("Error: Fork Failed") { + match unsafe { fork() }.expect("Error: Fork Failed") { Child => { ptrace::traceme().unwrap(); // first sigstop until parent is ready to continue let pid = getpid(); kill(pid, Signal::SIGSTOP).unwrap(); kill(pid, Signal::SIGTERM).unwrap(); - unsafe { ::libc::_exit(0); } - }, + unsafe { + ::libc::_exit(0); + } + } Parent { child } => { - assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGSTOP))); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Stopped(child, Signal::SIGSTOP)) + ); // set this option to recognize syscall-stops - ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap(); + ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD) + .unwrap(); #[cfg(target_arch = "x86_64")] - let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as libc::c_long; + let get_syscall_id = + || ptrace::getregs(child).unwrap().orig_rax as libc::c_long; #[cfg(target_arch = "x86")] - let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as libc::c_long; + let get_syscall_id = + || ptrace::getregs(child).unwrap().orig_eax as libc::c_long; // this duplicates `get_syscall_id` for the purpose of testing `ptrace::read_user`. #[cfg(target_arch = "x86_64")] @@ -211,28 +235,41 @@ fn test_ptrace_syscall() { let get_syscall_from_user_area = || { // Find the offset of `user.regs.rax` (or `user.regs.eax` for x86) let rax_offset = offset_of!(libc::user, regs) + rax_offset; - ptrace::read_user(child, rax_offset as _).unwrap() as libc::c_long + ptrace::read_user(child, rax_offset as _).unwrap() + as libc::c_long }; // kill entry ptrace::syscall(child, None).unwrap(); - assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::PtraceSyscall(child)) + ); assert_eq!(get_syscall_id(), ::libc::SYS_kill); assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill); // kill exit ptrace::syscall(child, None).unwrap(); - assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::PtraceSyscall(child)) + ); assert_eq!(get_syscall_id(), ::libc::SYS_kill); assert_eq!(get_syscall_from_user_area(), ::libc::SYS_kill); // receive signal ptrace::syscall(child, None).unwrap(); - assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTERM))); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Stopped(child, Signal::SIGTERM)) + ); // inject signal ptrace::syscall(child, Signal::SIGTERM).unwrap(); - assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false))); - }, + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false)) + ); + } } } diff --git a/test/sys/test_select.rs b/test/sys/test_select.rs index 2f7396b189..40bda4d90a 100644 --- a/test/sys/test_select.rs +++ b/test/sys/test_select.rs @@ -1,7 +1,7 @@ use nix::sys::select::*; -use nix::unistd::{pipe, write}; use nix::sys::signal::SigSet; use nix::sys::time::{TimeSpec, TimeValLike}; +use nix::unistd::{pipe, write}; #[test] pub fn test_pselect() { @@ -45,7 +45,8 @@ pub fn test_pselect_nfds2() { None, &timeout, None - ).unwrap() + ) + .unwrap() ); assert!(fd_set.contains(r1)); assert!(!fd_set.contains(r2)); diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs index fdd2568df4..3ad14f40c7 100644 --- a/test/sys/test_signal.rs +++ b/test/sys/test_signal.rs @@ -52,9 +52,12 @@ fn test_sigprocmask() { // Make sure the old set doesn't contain the signal, otherwise the following // test don't make sense. - assert!(!old_signal_set.contains(SIGNAL), - "the {:?} signal is already blocked, please change to a \ - different one", SIGNAL); + assert!( + !old_signal_set.contains(SIGNAL), + "the {:?} signal is already blocked, please change to a \ + different one", + SIGNAL + ); // Now block the signal. let mut signal_set = SigSet::empty(); @@ -66,8 +69,11 @@ fn test_sigprocmask() { old_signal_set.clear(); sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) .expect("expect to be able to retrieve old signals"); - assert!(old_signal_set.contains(SIGNAL), - "expected the {:?} to be blocked", SIGNAL); + assert!( + old_signal_set.contains(SIGNAL), + "expected the {:?} to be blocked", + SIGNAL + ); // Reset the signal. sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None) @@ -78,13 +84,18 @@ lazy_static! { static ref SIGNALED: AtomicBool = AtomicBool::new(false); } -extern fn test_sigaction_handler(signal: libc::c_int) { +extern "C" fn test_sigaction_handler(signal: libc::c_int) { let signal = Signal::try_from(signal).unwrap(); SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); } #[cfg(not(target_os = "redox"))] -extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) {} +extern "C" fn test_sigaction_action( + _: libc::c_int, + _: *mut libc::siginfo_t, + _: *mut libc::c_void, +) { +} #[test] #[cfg(not(target_os = "redox"))] @@ -92,7 +103,10 @@ fn test_signal_sigaction() { let _m = crate::SIGNAL_MTX.lock(); let action_handler = SigHandler::SigAction(test_sigaction_action); - assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Errno::ENOTSUP); + assert_eq!( + unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), + Errno::ENOTSUP + ); } #[test] @@ -101,20 +115,32 @@ fn test_signal() { unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); raise(Signal::SIGINT).unwrap(); - assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), SigHandler::SigIgn); + assert_eq!( + unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), + SigHandler::SigIgn + ); let handler = SigHandler::Handler(test_sigaction_handler); - assert_eq!(unsafe { signal(Signal::SIGINT, handler) }.unwrap(), SigHandler::SigDfl); + assert_eq!( + unsafe { signal(Signal::SIGINT, handler) }.unwrap(), + SigHandler::SigDfl + ); raise(Signal::SIGINT).unwrap(); assert!(SIGNALED.load(Ordering::Relaxed)); #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] - assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), handler); + assert_eq!( + unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), + handler + ); // System V based OSes (e.g. illumos and Solaris) always resets the // disposition to SIG_DFL prior to calling the signal handler #[cfg(any(target_os = "illumos", target_os = "solaris"))] - assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), SigHandler::SigDfl); + assert_eq!( + unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), + SigHandler::SigDfl + ); // Restore default signal handler unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(); diff --git a/test/sys/test_signalfd.rs b/test/sys/test_signalfd.rs index b6f748b46a..87153c9572 100644 --- a/test/sys/test_signalfd.rs +++ b/test/sys/test_signalfd.rs @@ -2,8 +2,8 @@ use std::convert::TryFrom; #[test] fn test_signalfd() { + use nix::sys::signal::{self, raise, SigSet, Signal}; use nix::sys::signalfd::SignalFd; - use nix::sys::signal::{self, raise, Signal, SigSet}; // Grab the mutex for altering signals so we don't interfere with other tests. let _m = crate::SIGNAL_MTX.lock(); diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index c742960ae8..067717bb1d 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1,7 +1,11 @@ +#[cfg(any(target_os = "linux", target_os = "android"))] +use crate::*; +use libc::{c_char, sockaddr_storage}; #[allow(deprecated)] use nix::sys::socket::InetAddr; -use nix::sys::socket::{AddressFamily, - UnixAddr, getsockname, sockaddr, sockaddr_in6}; +use nix::sys::socket::{ + getsockname, sockaddr, sockaddr_in6, AddressFamily, UnixAddr, +}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::mem::{self, MaybeUninit}; @@ -10,9 +14,6 @@ use std::os::unix::io::RawFd; use std::path::Path; use std::slice; use std::str::FromStr; -use libc::{c_char, sockaddr_storage}; -#[cfg(any(target_os = "linux", target_os= "android"))] -use crate::*; #[allow(deprecated)] #[test] @@ -41,7 +42,7 @@ pub fn test_inetv4_addr_to_sock_addr() { #[allow(deprecated)] #[test] pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() { - use nix::sys::socket::{SockAddr, sockaddr_storage_to_addr}; + use nix::sys::socket::{sockaddr_storage_to_addr, SockAddr}; let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); let addr = InetAddr::from_std(&actual); @@ -58,9 +59,12 @@ pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() { } }; - let from_storage = sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); + let from_storage = + sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); assert_eq!(from_storage, sockaddr); - let from_storage = sockaddr_storage_to_addr(&storage, mem::size_of::()).unwrap(); + let from_storage = + sockaddr_storage_to_addr(&storage, mem::size_of::()) + .unwrap(); assert_eq!(from_storage, sockaddr); } @@ -69,8 +73,9 @@ pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() { #[test] pub fn test_timestamping() { use nix::sys::socket::{ - recvmsg, sendmsg, setsockopt, socket, sockopt::Timestamping, ControlMessageOwned, MsgFlags, - SockaddrIn, SockFlag, SockType, TimestampingFlag, + recvmsg, sendmsg, setsockopt, socket, sockopt::Timestamping, + ControlMessageOwned, MsgFlags, SockFlag, SockType, SockaddrIn, + TimestampingFlag, }; use std::io::{IoSlice, IoSliceMut}; @@ -112,7 +117,9 @@ pub fn test_timestamping() { } } let ts = ts.expect("ScmTimestampns is present"); - let sys_time = ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME).unwrap(); + let sys_time = + ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME) + .unwrap(); let diff = if ts > sys_time { ts - sys_time } else { @@ -124,14 +131,15 @@ pub fn test_timestamping() { #[allow(deprecated)] #[test] pub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr() { - use nix::sys::socket::{SockAddr, sockaddr_storage_to_addr}; + use nix::sys::socket::{sockaddr_storage_to_addr, SockAddr}; let port: u16 = 3000; let flowinfo: u32 = 1; let scope_id: u32 = 2; let ip: Ipv6Addr = "fe80::1".parse().unwrap(); - let actual = SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id)); + let actual = + SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id)); let addr = InetAddr::from_std(&actual); let sockaddr = SockAddr::new_inet(addr); @@ -141,14 +149,20 @@ pub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr() { let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); assert_eq!(mem::size_of::(), ffi_size as usize); unsafe { - storage_ptr.copy_from_nonoverlapping((ffi_ptr as *const sockaddr).cast::(), 1); + storage_ptr.copy_from_nonoverlapping( + (ffi_ptr as *const sockaddr).cast::(), + 1, + ); (storage.assume_init(), ffi_size) } }; - let from_storage = sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); + let from_storage = + sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); assert_eq!(from_storage, sockaddr); - let from_storage = sockaddr_storage_to_addr(&storage, mem::size_of::()).unwrap(); + let from_storage = + sockaddr_storage_to_addr(&storage, mem::size_of::()) + .unwrap(); assert_eq!(from_storage, sockaddr); } @@ -220,7 +234,8 @@ pub fn test_abstract_uds_addr() { let name = String::from("nix\0abstract\0test"); let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); let sun_path = [ - 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116 + 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, + 115, 116, ]; assert_eq!(addr.as_abstract(), Some(&sun_path[..])); assert_eq!(addr.path(), None); @@ -231,13 +246,18 @@ pub fn test_abstract_uds_addr() { #[test] pub fn test_getsockname() { - use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag}; use nix::sys::socket::bind; + use nix::sys::socket::{socket, AddressFamily, SockFlag, SockType}; let tempdir = tempfile::tempdir().unwrap(); let sockname = tempdir.path().join("sock"); - let sock = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None) - .expect("socket failed"); + let sock = socket( + AddressFamily::Unix, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); let sockaddr = UnixAddr::new(&sockname).unwrap(); bind(sock, &sockaddr).expect("bind failed"); assert_eq!(sockaddr, getsockname(sock).expect("getsockname failed")); @@ -245,13 +265,18 @@ pub fn test_getsockname() { #[test] pub fn test_socketpair() { + use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType}; use nix::unistd::{read, write}; - use nix::sys::socket::{socketpair, AddressFamily, SockType, SockFlag}; - let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) - .unwrap(); + let (fd1, fd2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); write(fd1, b"hello").unwrap(); - let mut buf = [0;5]; + let mut buf = [0; 5]; read(fd2, &mut buf).unwrap(); assert_eq!(&buf[..], b"hello"); @@ -271,17 +296,22 @@ pub fn test_std_conversions() { } mod recvfrom { - use nix::Result; + use super::*; use nix::sys::socket::*; + use nix::Result; use std::thread; - use super::*; const MSG: &[u8] = b"Hello, World!"; - fn sendrecv(rsock: RawFd, ssock: RawFd, f_send: Fs, mut f_recv: Fr) -> Option - where - Fs: Fn(RawFd, &[u8], MsgFlags) -> Result + Send + 'static, - Fr: FnMut(usize, Option), + fn sendrecv( + rsock: RawFd, + ssock: RawFd, + f_send: Fs, + mut f_recv: Fr, + ) -> Option + where + Fs: Fn(RawFd, &[u8], MsgFlags) -> Result + Send + 'static, + Fr: FnMut(usize, Option), { let mut buf: [u8; 13] = [0u8; 13]; let mut l = 0; @@ -307,33 +337,42 @@ mod recvfrom { #[test] pub fn stream() { - let (fd2, fd1) = socketpair(AddressFamily::Unix, SockType::Stream, - None, SockFlag::empty()).unwrap(); + let (fd2, fd1) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); // Ignore from for stream sockets - let _ = sendrecv(fd1, fd2, |s, m, flags| { - send(s, m, flags) - }, |_, _| {}); + let _ = sendrecv(fd1, fd2, |s, m, flags| send(s, m, flags), |_, _| {}); } #[test] pub fn udp() { let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap(); let sock_addr = SockaddrIn::from(std_sa); - let rsock = socket(AddressFamily::Inet, + let rsock = socket( + AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), - None - ).unwrap(); + None, + ) + .unwrap(); bind(rsock, &sock_addr).unwrap(); let ssock = socket( AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None, - ).expect("send socket failed"); - let from = sendrecv(rsock, ssock, move |s, m, flags| { - sendto(s, m, &sock_addr, flags) - },|_, _| {}); + ) + .expect("send socket failed"); + let from = sendrecv( + rsock, + ssock, + move |s, m, flags| sendto(s, m, &sock_addr, flags), + |_, _| {}, + ); // UDP sockets should set the from address assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); } @@ -357,11 +396,13 @@ mod recvfrom { let segment_size: u16 = 2; let sock_addr = SockaddrIn::new(127, 0, 0, 1, 6791); - let rsock = socket(AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None - ).unwrap(); + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); setsockopt(rsock, UdpGsoSegment, &(segment_size as _)) .expect("setsockopt UDP_SEGMENT failed"); @@ -372,24 +413,30 @@ mod recvfrom { SockType::Datagram, SockFlag::empty(), None, - ).expect("send socket failed"); + ) + .expect("send socket failed"); let mut num_packets_received: i32 = 0; - sendrecv(rsock, ssock, move |s, m, flags| { - let iov = [IoSlice::new(m)]; - let cmsg = ControlMessage::UdpGsoSegments(&segment_size); - sendmsg(s, &iov, &[cmsg], flags, Some(&sock_addr)) - }, { - let num_packets_received_ref = &mut num_packets_received; - - move |len, _| { - // check that we receive UDP packets with payload size - // less or equal to segment size - assert!(len <= segment_size as usize); - *num_packets_received_ref += 1; - } - }); + sendrecv( + rsock, + ssock, + move |s, m, flags| { + let iov = [IoSlice::new(m)]; + let cmsg = ControlMessage::UdpGsoSegments(&segment_size); + sendmsg(s, &iov, &[cmsg], flags, Some(&sock_addr)) + }, + { + let num_packets_received_ref = &mut num_packets_received; + + move |len, _| { + // check that we receive UDP packets with payload size + // less or equal to segment size + assert!(len <= segment_size as usize); + *num_packets_received_ref += 1; + } + }, + ); // Buffer size is 13, we will receive six packets of size 2, // and one packet of size 1. @@ -406,11 +453,13 @@ mod recvfrom { // It's hard to guarantee receiving GRO packets. Just checking // that `setsockopt` doesn't fail with error - let rsock = socket(AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None - ).unwrap(); + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); setsockopt(rsock, UdpGroSegment, &true) .expect("setsockopt UDP_GRO failed"); @@ -432,51 +481,54 @@ mod recvfrom { let sock_addr = SockaddrIn::from(std_sa); let sock_addr2 = SockaddrIn::from(std_sa2); - let rsock = socket(AddressFamily::Inet, + let rsock = socket( + AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), - None - ).unwrap(); + None, + ) + .unwrap(); bind(rsock, &sock_addr).unwrap(); let ssock = socket( AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None, - ).expect("send socket failed"); + ) + .expect("send socket failed"); - let from = sendrecv(rsock, ssock, move |s, m, flags| { - let iov = [IoSlice::new(m)]; - let mut msgs = vec![ - SendMmsgData { + let from = sendrecv( + rsock, + ssock, + move |s, m, flags| { + let iov = [IoSlice::new(m)]; + let mut msgs = vec![SendMmsgData { iov: &iov, cmsgs: &[], addr: Some(sock_addr), _lt: Default::default(), - } - ]; + }]; - let batch_size = 15; + let batch_size = 15; - for _ in 0..batch_size { - msgs.push( - SendMmsgData { + for _ in 0..batch_size { + msgs.push(SendMmsgData { iov: &iov, cmsgs: &[], addr: Some(sock_addr2), _lt: Default::default(), - } - ); - } - sendmmsg(s, msgs.iter(), flags) - .map(move |sent_bytes| { + }); + } + sendmmsg(s, msgs.iter(), flags).map(move |sent_bytes| { assert!(!sent_bytes.is_empty()); for sent in &sent_bytes { assert_eq!(*sent, m.len()); } sent_bytes.len() }) - }, |_, _ | {}); + }, + |_, _| {}, + ); // UDP sockets should set the from address assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); } @@ -489,31 +541,35 @@ mod recvfrom { ))] #[test] pub fn udp_recvmmsg() { + use nix::sys::socket::{recvmmsg, MsgFlags}; use std::io::IoSliceMut; - use nix::sys::socket::{MsgFlags, recvmmsg}; const NUM_MESSAGES_SENT: usize = 2; - const DATA: [u8; 2] = [1,2]; + const DATA: [u8; 2] = [1, 2]; let inet_addr = SocketAddrV4::from_str("127.0.0.1:6798").unwrap(); let sock_addr = SockaddrIn::from(inet_addr); - let rsock = socket(AddressFamily::Inet, + let rsock = socket( + AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), - None - ).unwrap(); + None, + ) + .unwrap(); bind(rsock, &sock_addr).unwrap(); let ssock = socket( AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None, - ).expect("send socket failed"); + ) + .expect("send socket failed"); let send_thread = thread::spawn(move || { for _ in 0..NUM_MESSAGES_SENT { - sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()).unwrap(); + sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()) + .unwrap(); } }); @@ -521,18 +577,21 @@ mod recvfrom { // Buffers to receive exactly `NUM_MESSAGES_SENT` messages let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT]; - let iovs: Vec<_> = receive_buffers.iter_mut().map(|buf| { - [IoSliceMut::new(&mut buf[..])] - }).collect(); + let iovs: Vec<_> = receive_buffers + .iter_mut() + .map(|buf| [IoSliceMut::new(&mut buf[..])]) + .collect(); for iov in &iovs { msgs.push_back(RecvMmsgData { iov, cmsg_buffer: None, }) - }; + } - let res: Vec> = recvmmsg(rsock, &mut msgs, MsgFlags::empty(), None).expect("recvmmsg"); + let res: Vec> = + recvmmsg(rsock, &mut msgs, MsgFlags::empty(), None) + .expect("recvmmsg"); assert_eq!(res.len(), DATA.len()); for RecvMsg { address, bytes, .. } in res.into_iter() { @@ -555,31 +614,35 @@ mod recvfrom { ))] #[test] pub fn udp_recvmmsg_dontwait_short_read() { - use nix::sys::socket::{MsgFlags, recvmmsg}; + use nix::sys::socket::{recvmmsg, MsgFlags}; use std::io::IoSliceMut; const NUM_MESSAGES_SENT: usize = 2; - const DATA: [u8; 4] = [1,2,3,4]; + const DATA: [u8; 4] = [1, 2, 3, 4]; let inet_addr = SocketAddrV4::from_str("127.0.0.1:6799").unwrap(); let sock_addr = SockaddrIn::from(inet_addr); - let rsock = socket(AddressFamily::Inet, + let rsock = socket( + AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), - None - ).unwrap(); + None, + ) + .unwrap(); bind(rsock, &sock_addr).unwrap(); let ssock = socket( AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None, - ).expect("send socket failed"); + ) + .expect("send socket failed"); let send_thread = thread::spawn(move || { for _ in 0..NUM_MESSAGES_SENT { - sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()).unwrap(); + sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()) + .unwrap(); } }); // Ensure we've sent all the messages before continuing so `recvmmsg` @@ -592,18 +655,21 @@ mod recvfrom { // will return when there are fewer than requested messages in the // kernel buffers when using `MSG_DONTWAIT`. let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2]; - let iovs: Vec<_> = receive_buffers.iter_mut().map(|buf| { - [IoSliceMut::new(&mut buf[..])] - }).collect(); + let iovs: Vec<_> = receive_buffers + .iter_mut() + .map(|buf| [IoSliceMut::new(&mut buf[..])]) + .collect(); for iov in &iovs { msgs.push_back(RecvMmsgData { iov, cmsg_buffer: None, }) - }; + } - let res: Vec> = recvmmsg(rsock, &mut msgs, MsgFlags::MSG_DONTWAIT, None).expect("recvmmsg"); + let res: Vec> = + recvmmsg(rsock, &mut msgs, MsgFlags::MSG_DONTWAIT, None) + .expect("recvmmsg"); assert_eq!(res.len(), NUM_MESSAGES_SENT); for RecvMsg { address, bytes, .. } in res.into_iter() { @@ -621,13 +687,13 @@ mod recvfrom { #[test] pub fn test_recvmsg_ebadf() { use nix::errno::Errno; - use nix::sys::socket::{MsgFlags, recvmsg}; + use nix::sys::socket::{recvmsg, MsgFlags}; use std::io::IoSliceMut; let mut buf = [0u8; 5]; let mut iov = [IoSliceMut::new(&mut buf[..])]; - let fd = -1; // Bad file descriptor + let fd = -1; // Bad file descriptor let r = recvmsg::<()>(fd, &mut iov, None, MsgFlags::empty()); assert_eq!(r.err().unwrap(), Errno::EBADF); @@ -638,14 +704,20 @@ pub fn test_recvmsg_ebadf() { #[cfg_attr(qemu, ignore)] #[test] pub fn test_scm_rights() { - use nix::unistd::{pipe, read, write, close}; - use nix::sys::socket::{socketpair, sendmsg, recvmsg, - AddressFamily, SockType, SockFlag, - ControlMessage, ControlMessageOwned, MsgFlags}; + use nix::sys::socket::{ + recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage, + ControlMessageOwned, MsgFlags, SockFlag, SockType, + }; + use nix::unistd::{close, pipe, read, write}; use std::io::{IoSlice, IoSliceMut}; - let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) - .unwrap(); + let (fd1, fd2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); let (r, w) = pipe().unwrap(); let mut received_r: Option = None; @@ -653,7 +725,10 @@ pub fn test_scm_rights() { let iov = [IoSlice::new(b"hello")]; let fds = [r]; let cmsg = ControlMessage::ScmRights(&fds); - assert_eq!(sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); + assert_eq!( + sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), + 5 + ); close(r).unwrap(); close(fd1).unwrap(); } @@ -663,7 +738,13 @@ pub fn test_scm_rights() { let mut iov = [IoSliceMut::new(&mut buf[..])]; let mut cmsgspace = cmsg_space!([RawFd; 1]); - let msg = recvmsg::<()>(fd2, &mut iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>( + fd2, + &mut iov, + Some(&mut cmsgspace), + MsgFlags::empty(), + ) + .unwrap(); for cmsg in msg.cmsgs() { if let ControlMessageOwned::ScmRights(fd) = cmsg { @@ -675,7 +756,9 @@ pub fn test_scm_rights() { } } assert_eq!(msg.bytes, 5); - assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); close(fd2).unwrap(); } @@ -690,15 +773,16 @@ 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(any(target_os = "linux", target_os= "android"))] +#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg_attr(qemu, ignore)] #[test] pub fn test_af_alg_cipher() { - use nix::unistd::read; - use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt, - AddressFamily, SockType, SockFlag, AlgAddr, - ControlMessage, MsgFlags}; use nix::sys::socket::sockopt::AlgSetKey; + use nix::sys::socket::{ + accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr, + ControlMessage, MsgFlags, SockFlag, SockType, + }; + use nix::unistd::read; use std::io::IoSlice; skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352"); @@ -717,8 +801,13 @@ pub fn test_af_alg_cipher() { let payload_len = 256; let payload = vec![2u8; payload_len]; - let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None) - .expect("socket failed"); + let sock = socket( + AddressFamily::Alg, + SockType::SeqPacket, + SockFlag::empty(), + None, + ) + .expect("socket failed"); let sockaddr = AlgAddr::new(alg_type, alg_name); bind(sock, &sockaddr).expect("bind failed"); @@ -729,9 +818,13 @@ pub fn test_af_alg_cipher() { setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt"); let session_socket = accept(sock).expect("accept failed"); - let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), ControlMessage::AlgSetIv(iv.as_slice())]; + let msgs = [ + ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), + ControlMessage::AlgSetIv(iv.as_slice()), + ]; let iov = IoSlice::new(&payload); - sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) + .expect("sendmsg encrypt"); // allocate buffer for encrypted data let mut encrypted = vec![0u8; payload_len]; @@ -742,8 +835,12 @@ pub fn test_af_alg_cipher() { let iv = vec![1u8; iv_len]; - let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT), ControlMessage::AlgSetIv(iv.as_slice())]; - sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt"); + let msgs = [ + ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT), + ControlMessage::AlgSetIv(iv.as_slice()), + ]; + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) + .expect("sendmsg decrypt"); // allocate buffer for decrypted data let mut decrypted = vec![0u8; payload_len]; @@ -755,17 +852,18 @@ pub fn test_af_alg_cipher() { // Disable the test on emulated platforms due to not enabled support of AF_ALG // in QEMU from rust cross -#[cfg(any(target_os = "linux", target_os= "android"))] +#[cfg(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}; use nix::fcntl::{fcntl, FcntlArg, OFlag}; - use nix::unistd::{read, close}; - use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt, - AddressFamily, SockType, SockFlag, AlgAddr, - ControlMessage, MsgFlags}; - use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize}; + use nix::sys::socket::sockopt::{AlgSetAeadAuthSize, AlgSetKey}; + use nix::sys::socket::{ + accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr, + ControlMessage, MsgFlags, SockFlag, SockType, + }; + use nix::unistd::{close, read}; use std::io::IoSlice; skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352"); @@ -785,7 +883,8 @@ pub fn test_af_alg_aead() { let iv = vec![1u8; iv_len]; // 256-bytes plain payload let payload_len = 256; - let mut payload = vec![2u8; payload_len + (assoc_size as usize) + auth_size]; + let mut payload = + vec![2u8; payload_len + (assoc_size as usize) + auth_size]; for i in 0..assoc_size { payload[i as usize] = 10; @@ -797,26 +896,35 @@ pub fn test_af_alg_aead() { payload[len - 1 - i] = 0; } - let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None) - .expect("socket failed"); + let sock = socket( + AddressFamily::Alg, + SockType::SeqPacket, + SockFlag::empty(), + None, + ) + .expect("socket failed"); let sockaddr = AlgAddr::new(alg_type, alg_name); bind(sock, &sockaddr).expect("bind failed"); - setsockopt(sock, AlgSetAeadAuthSize, &auth_size).expect("setsockopt AlgSetAeadAuthSize"); + setsockopt(sock, AlgSetAeadAuthSize, &auth_size) + .expect("setsockopt AlgSetAeadAuthSize"); setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt AlgSetKey"); let session_socket = accept(sock).expect("accept failed"); let msgs = [ ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT), ControlMessage::AlgSetIv(iv.as_slice()), - ControlMessage::AlgSetAeadAssoclen(&assoc_size)]; + ControlMessage::AlgSetAeadAssoclen(&assoc_size), + ]; let iov = IoSlice::new(&payload); - sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) + .expect("sendmsg encrypt"); // allocate buffer for encrypted data - let mut encrypted = vec![0u8; (assoc_size as usize) + payload_len + auth_size]; + let mut encrypted = + vec![0u8; (assoc_size as usize) + payload_len + auth_size]; let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt"); assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize)); close(session_socket).expect("close"); @@ -836,19 +944,25 @@ pub fn test_af_alg_aead() { ControlMessage::AlgSetIv(iv.as_slice()), ControlMessage::AlgSetAeadAssoclen(&assoc_size), ]; - sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt"); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) + .expect("sendmsg decrypt"); // allocate buffer for decrypted data - let mut decrypted = vec![0u8; payload_len + (assoc_size as usize) + auth_size]; + let mut decrypted = + vec![0u8; payload_len + (assoc_size as usize) + auth_size]; // Starting with kernel 4.9, the interface changed slightly such that the // authentication tag memory is only needed in the output buffer for encryption // and in the input buffer for decryption. // Do not block on read, as we may have fewer bytes than buffer size - fcntl(session_socket,FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).expect("fcntl non_blocking"); + fcntl(session_socket, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)) + .expect("fcntl non_blocking"); let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt"); assert!(num_bytes >= payload_len + (assoc_size as usize)); - assert_eq!(decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], payload[(assoc_size as usize)..payload_len + (assoc_size as usize)]); + assert_eq!( + decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], + payload[(assoc_size as usize)..payload_len + (assoc_size as usize)] + ); } // Verify `ControlMessage::Ipv4PacketInfo` for `sendmsg`. @@ -858,24 +972,25 @@ pub fn test_af_alg_aead() { // This would be a more interesting test if we could assume that the test host // has more than one IP address (since we could select a different address to // test from). -#[cfg(any(target_os = "linux", - target_os = "macos", - target_os = "netbsd"))] +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd"))] #[test] pub fn test_sendmsg_ipv4packetinfo() { use cfg_if::cfg_if; - use nix::sys::socket::{socket, sendmsg, bind, - AddressFamily, SockType, SockFlag, SockaddrIn, - ControlMessage, MsgFlags}; + use nix::sys::socket::{ + bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags, + SockFlag, SockType, SockaddrIn, + }; use std::io::IoSlice; - let sock = socket(AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None) - .expect("socket failed"); + let sock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("socket failed"); - let sock_addr = SockaddrIn::new(127,0,0,1, 4000); + let sock_addr = SockaddrIn::new(127, 0, 0, 1, 4000); bind(sock, &sock_addr).expect("bind failed"); @@ -911,23 +1026,28 @@ pub fn test_sendmsg_ipv4packetinfo() { // This would be a more interesting test if we could assume that the test host // has more than one IP address (since we could select a different address to // test from). -#[cfg(any(target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "freebsd"))] +#[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "freebsd" +))] #[test] pub fn test_sendmsg_ipv6packetinfo() { use nix::errno::Errno; - use nix::sys::socket::{socket, sendmsg, bind, - AddressFamily, SockType, SockFlag, SockaddrIn6, - ControlMessage, MsgFlags}; + use nix::sys::socket::{ + bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags, + SockFlag, SockType, SockaddrIn6, + }; use std::io::IoSlice; - let sock = socket(AddressFamily::Inet6, - SockType::Datagram, - SockFlag::empty(), - None) - .expect("socket failed"); + let sock = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("socket failed"); let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap(); let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa); @@ -947,8 +1067,14 @@ pub fn test_sendmsg_ipv6packetinfo() { let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)]; - sendmsg::(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) - .expect("sendmsg"); + sendmsg::( + sock, + &iov, + &cmsg, + MsgFlags::empty(), + Some(&sock_addr), + ) + .expect("sendmsg"); } /// Tests that passing multiple fds using a single `ControlMessage` works. @@ -957,12 +1083,13 @@ pub fn test_sendmsg_ipv6packetinfo() { #[cfg_attr(qemu, ignore)] #[test] fn test_scm_rights_single_cmsg_multiple_fds() { + use nix::sys::socket::{ + recvmsg, sendmsg, ControlMessage, ControlMessageOwned, MsgFlags, + }; + use std::io::{IoSlice, IoSliceMut}; + use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::net::UnixDatagram; - use std::os::unix::io::{RawFd, AsRawFd}; use std::thread; - use nix::sys::socket::{ControlMessage, ControlMessageOwned, MsgFlags, - sendmsg, recvmsg}; - use std::io::{IoSlice, IoSliceMut}; let (send, receive) = UnixDatagram::pair().unwrap(); let thread = thread::spawn(move || { @@ -974,17 +1101,23 @@ fn test_scm_rights_single_cmsg_multiple_fds() { receive.as_raw_fd(), &mut iovec, Some(&mut space), - MsgFlags::empty() - ).unwrap(); - assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + MsgFlags::empty(), + ) + .unwrap(); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); let mut cmsgs = msg.cmsgs(); match cmsgs.next() { Some(ControlMessageOwned::ScmRights(fds)) => { - assert_eq!(fds.len(), 2, - "unexpected fd count (expected 2 fds, got {})", - fds.len()); - }, + assert_eq!( + fds.len(), + 2, + "unexpected fd count (expected 2 fds, got {})", + fds.len() + ); + } _ => panic!(), } assert!(cmsgs.next().is_none(), "unexpected control msg"); @@ -995,9 +1128,10 @@ fn test_scm_rights_single_cmsg_multiple_fds() { let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; let iov = [IoSlice::new(&slice)]; - let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout + let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout let cmsg = [ControlMessage::ScmRights(&fds)]; - sendmsg::<()>(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None).unwrap(); + sendmsg::<()>(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None) + .unwrap(); thread.join().unwrap(); } @@ -1007,17 +1141,27 @@ fn test_scm_rights_single_cmsg_multiple_fds() { // raw `sendmsg`. #[test] pub fn test_sendmsg_empty_cmsgs() { + use nix::sys::socket::{ + recvmsg, sendmsg, socketpair, AddressFamily, MsgFlags, SockFlag, + SockType, + }; use nix::unistd::close; - use nix::sys::socket::{socketpair, sendmsg, recvmsg, - AddressFamily, SockType, SockFlag, MsgFlags}; use std::io::{IoSlice, IoSliceMut}; - let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) - .unwrap(); + let (fd1, fd2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); { let iov = [IoSlice::new(b"hello")]; - assert_eq!(sendmsg::<()>(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5); + assert_eq!( + sendmsg::<()>(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), + 5 + ); close(fd1).unwrap(); } @@ -1026,12 +1170,20 @@ pub fn test_sendmsg_empty_cmsgs() { let mut iov = [IoSliceMut::new(&mut buf[..])]; let mut cmsgspace = cmsg_space!([RawFd; 1]); - let msg = recvmsg::<()>(fd2, &mut iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>( + fd2, + &mut iov, + Some(&mut cmsgspace), + MsgFlags::empty(), + ) + .unwrap(); for _ in msg.cmsgs() { panic!("unexpected cmsg"); } - assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); assert_eq!(msg.bytes, 5); close(fd2).unwrap(); } @@ -1045,17 +1197,22 @@ pub fn test_sendmsg_empty_cmsgs() { ))] #[test] fn test_scm_credentials() { - use nix::unistd::{close, getpid, getuid, getgid}; - use nix::sys::socket::{socketpair, sendmsg, recvmsg, - AddressFamily, SockType, SockFlag, - ControlMessage, ControlMessageOwned, MsgFlags, - UnixCredentials}; + use nix::sys::socket::{ + recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage, + ControlMessageOwned, MsgFlags, SockFlag, SockType, UnixCredentials, + }; #[cfg(any(target_os = "android", target_os = "linux"))] use nix::sys::socket::{setsockopt, sockopt::PassCred}; + use nix::unistd::{close, getgid, getpid, getuid}; use std::io::{IoSlice, IoSliceMut}; - let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) - .unwrap(); + let (send, recv) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); #[cfg(any(target_os = "android", target_os = "linux"))] setsockopt(recv, PassCred, &true).unwrap(); @@ -1067,7 +1224,11 @@ fn test_scm_credentials() { let cmsg = ControlMessage::ScmCredentials(&cred); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] let cmsg = ControlMessage::ScmCreds; - assert_eq!(sendmsg::<()>(send, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); + assert_eq!( + sendmsg::<()>(send, &iov, &[cmsg], MsgFlags::empty(), None) + .unwrap(), + 5 + ); close(send).unwrap(); } @@ -1076,7 +1237,13 @@ fn test_scm_credentials() { let mut iov = [IoSliceMut::new(&mut buf[..])]; let mut cmsgspace = cmsg_space!(UnixCredentials); - let msg = recvmsg::<()>(recv, &mut iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>( + recv, + &mut iov, + Some(&mut cmsgspace), + MsgFlags::empty(), + ) + .unwrap(); let mut received_cred = None; for cmsg in msg.cmsgs() { @@ -1095,7 +1262,9 @@ fn test_scm_credentials() { } received_cred.expect("no creds received"); assert_eq!(msg.bytes, 5); - assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); close(recv).unwrap(); } } @@ -1127,15 +1296,21 @@ fn test_too_large_cmsgspace() { #[cfg(any(target_os = "android", target_os = "linux"))] fn test_impl_scm_credentials_and_rights(mut space: Vec) { use libc::ucred; - use nix::unistd::{pipe, write, close, getpid, getuid, getgid}; - use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt, - SockType, SockFlag, - ControlMessage, ControlMessageOwned, MsgFlags}; use nix::sys::socket::sockopt::PassCred; + use nix::sys::socket::{ + recvmsg, sendmsg, setsockopt, socketpair, ControlMessage, + ControlMessageOwned, MsgFlags, SockFlag, SockType, + }; + use nix::unistd::{close, getgid, getpid, getuid, pipe, write}; use std::io::{IoSlice, IoSliceMut}; - let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()) - .unwrap(); + let (send, recv) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); setsockopt(recv, PassCred, &true).unwrap(); let (r, w) = pipe().unwrap(); @@ -1147,13 +1322,17 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { pid: getpid().as_raw(), uid: getuid().as_raw(), gid: getgid().as_raw(), - }.into(); + } + .into(); let fds = [r]; let cmsgs = [ ControlMessage::ScmCredentials(&cred), ControlMessage::ScmRights(&fds), ]; - assert_eq!(sendmsg::<()>(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(), 5); + assert_eq!( + sendmsg::<()>(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(), + 5 + ); close(r).unwrap(); close(send).unwrap(); } @@ -1161,7 +1340,9 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { { let mut buf = [0u8; 5]; let mut iov = [IoSliceMut::new(&mut buf[..])]; - let msg = recvmsg::<()>(recv, &mut iov, Some(&mut space), MsgFlags::empty()).unwrap(); + let msg = + recvmsg::<()>(recv, &mut iov, Some(&mut space), MsgFlags::empty()) + .unwrap(); let mut received_cred = None; assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs"); @@ -1185,7 +1366,9 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { } received_cred.expect("no creds received"); assert_eq!(msg.bytes, 5); - assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); close(recv).unwrap(); } @@ -1202,22 +1385,32 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { // Test creating and using named unix domain sockets #[test] pub fn test_unixdomain() { - use nix::sys::socket::{SockType, SockFlag}; - use nix::sys::socket::{bind, socket, connect, listen, accept, UnixAddr}; - use nix::unistd::{read, write, close}; + use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr}; + use nix::sys::socket::{SockFlag, SockType}; + use nix::unistd::{close, read, write}; use std::thread; let tempdir = tempfile::tempdir().unwrap(); let sockname = tempdir.path().join("sock"); - let s1 = socket(AddressFamily::Unix, SockType::Stream, - SockFlag::empty(), None).expect("socket failed"); + let s1 = socket( + AddressFamily::Unix, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); let sockaddr = UnixAddr::new(&sockname).unwrap(); bind(s1, &sockaddr).expect("bind failed"); listen(s1, 10).expect("listen failed"); let thr = thread::spawn(move || { - let s2 = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None) - .expect("socket failed"); + let s2 = socket( + AddressFamily::Unix, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); connect(s2, &sockaddr).expect("connect failed"); write(s2, b"hello").expect("write failed"); close(s2).unwrap(); @@ -1225,7 +1418,7 @@ pub fn test_unixdomain() { let s3 = accept(s1).expect("accept failed"); - let mut buf = [0;5]; + let mut buf = [0; 5]; read(s3, &mut buf).unwrap(); close(s3).unwrap(); close(s1).unwrap(); @@ -1239,14 +1432,23 @@ pub fn test_unixdomain() { #[test] pub fn test_syscontrol() { use nix::errno::Errno; - use nix::sys::socket::{socket, SysControlAddr, SockType, SockFlag, SockProtocol}; + use nix::sys::socket::{ + socket, SockFlag, SockProtocol, SockType, SysControlAddr, + }; - let fd = socket(AddressFamily::System, SockType::Datagram, - SockFlag::empty(), SockProtocol::KextControl) - .expect("socket failed"); + let fd = socket( + AddressFamily::System, + SockType::Datagram, + SockFlag::empty(), + SockProtocol::KextControl, + ) + .expect("socket failed"); SysControlAddr::from_name(fd, "com.apple.net.utun_control", 0) .expect("resolving sys_control name failed"); - assert_eq!(SysControlAddr::from_name(fd, "foo.bar.lol", 0).err(), Some(Errno::ENOENT)); + assert_eq!( + SysControlAddr::from_name(fd, "foo.bar.lol", 0).err(), + Some(Errno::ENOENT) + ); // requires root privileges // connect(fd, &sockaddr).expect("connect failed"); @@ -1261,12 +1463,14 @@ pub fn test_syscontrol() { target_os = "netbsd", target_os = "openbsd", ))] -fn loopback_address(family: AddressFamily) -> Option { - use std::io; - use std::io::Write; +fn loopback_address( + family: AddressFamily, +) -> Option { use nix::ifaddrs::getifaddrs; use nix::net::if_::*; use nix::sys::socket::SockaddrLike; + use std::io; + use std::io::Write; let addrs = match getifaddrs() { Ok(iter) => iter, @@ -1275,14 +1479,15 @@ fn loopback_address(family: AddressFamily) -> Option Option (ifaddr.interface_name, - ifaddr.address.expect("Expect IPv4 address on interface")), + Some(ifaddr) => ( + ifaddr.interface_name, + ifaddr.address.expect("Expect IPv4 address on interface"), + ), None => return, }; let receive = socket( - AddressFamily::Inet, - SockType::Datagram, - SockFlag::empty(), - None, - ).expect("receive socket failed"); + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("receive socket failed"); bind(receive, &lo).expect("bind failed"); let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); setsockopt(receive, Ipv4PacketInfo, &true).expect("setsockopt failed"); @@ -1338,8 +1549,10 @@ pub fn test_recv_ipv4pktinfo() { SockType::Datagram, SockFlag::empty(), None, - ).expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)).expect("sendmsg failed"); + ) + .expect("send socket failed"); + sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + .expect("sendmsg failed"); } { @@ -1352,29 +1565,25 @@ pub fn test_recv_ipv4pktinfo() { &mut iovec, Some(&mut space), MsgFlags::empty(), - ).expect("recvmsg failed"); - assert!( - !msg.flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC) - ); + ) + .expect("recvmsg failed"); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); let mut cmsgs = msg.cmsgs(); - if let Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) = cmsgs.next() { + if let Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) = cmsgs.next() + { let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); assert_eq!( - pktinfo.ipi_ifindex as libc::c_uint, - i, + pktinfo.ipi_ifindex as libc::c_uint, i, "unexpected ifindex (expected {}, got {})", - i, - pktinfo.ipi_ifindex + i, pktinfo.ipi_ifindex ); } assert!(cmsgs.next().is_none(), "unexpected additional control msg"); assert_eq!(msg.bytes, 8); - assert_eq!( - *iovec[0], - [1u8, 2, 3, 4, 5, 6, 7, 8] - ); + assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); } } @@ -1386,27 +1595,32 @@ pub fn test_recv_ipv4pktinfo() { target_os = "openbsd", ))] // qemu doesn't seem to be emulating this correctly in these architectures -#[cfg_attr(all( - qemu, - any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc64", - ) -), ignore)] +#[cfg_attr( + all( + qemu, + any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + ) + ), + ignore +)] #[test] pub fn test_recvif() { use nix::net::if_::*; - use nix::sys::socket::sockopt::{Ipv4RecvIf, Ipv4RecvDstAddr}; - use nix::sys::socket::{bind, SockaddrIn, SockFlag, SockType}; + use nix::sys::socket::sockopt::{Ipv4RecvDstAddr, Ipv4RecvIf}; + use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn}; use nix::sys::socket::{getsockname, setsockopt, socket}; use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; use std::io::{IoSlice, IoSliceMut}; let lo_ifaddr = loopback_address(AddressFamily::Inet); let (lo_name, lo) = match lo_ifaddr { - Some(ifaddr) => (ifaddr.interface_name, - ifaddr.address.expect("Expect IPv4 address on interface")), + Some(ifaddr) => ( + ifaddr.interface_name, + ifaddr.address.expect("Expect IPv4 address on interface"), + ), None => return, }; let receive = socket( @@ -1414,11 +1628,14 @@ pub fn test_recvif() { SockType::Datagram, SockFlag::empty(), None, - ).expect("receive socket failed"); + ) + .expect("receive socket failed"); bind(receive, &lo).expect("bind failed"); let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); - setsockopt(receive, Ipv4RecvIf, &true).expect("setsockopt IP_RECVIF failed"); - setsockopt(receive, Ipv4RecvDstAddr, &true).expect("setsockopt IP_RECVDSTADDR failed"); + setsockopt(receive, Ipv4RecvIf, &true) + .expect("setsockopt IP_RECVIF failed"); + setsockopt(receive, Ipv4RecvDstAddr, &true) + .expect("setsockopt IP_RECVDSTADDR failed"); { let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; @@ -1429,8 +1646,10 @@ pub fn test_recvif() { SockType::Datagram, SockFlag::empty(), None, - ).expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)).expect("sendmsg failed"); + ) + .expect("send socket failed"); + sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + .expect("sendmsg failed"); } { @@ -1442,11 +1661,11 @@ pub fn test_recvif() { &mut iovec, Some(&mut space), MsgFlags::empty(), - ).expect("recvmsg failed"); - assert!( - !msg.flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC) - ); + ) + .expect("recvmsg failed"); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs"); let mut rx_recvif = false; @@ -1455,15 +1674,14 @@ pub fn test_recvif() { match cmsg { ControlMessageOwned::Ipv4RecvIf(dl) => { rx_recvif = true; - let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); + let i = if_nametoindex(lo_name.as_bytes()) + .expect("if_nametoindex"); assert_eq!( - dl.sdl_index as libc::c_uint, - i, + dl.sdl_index as libc::c_uint, i, "unexpected ifindex (expected {}, got {})", - i, - dl.sdl_index + i, dl.sdl_index ); - }, + } ControlMessageOwned::Ipv4RecvDstAddr(addr) => { rx_recvdstaddr = true; if let Some(sin) = lo.as_sockaddr_in() { @@ -1475,17 +1693,14 @@ pub fn test_recvif() { } else { panic!("unexpected Sockaddr"); } - }, + } _ => panic!("unexpected additional control msg"), } } assert!(rx_recvif); assert!(rx_recvdstaddr); assert_eq!(msg.bytes, 8); - assert_eq!( - *iovec[0], - [1u8, 2, 3, 4, 5, 6, 7, 8] - ); + assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); } } @@ -1499,27 +1714,32 @@ pub fn test_recvif() { target_os = "openbsd", ))] // qemu doesn't seem to be emulating this correctly in these architectures -#[cfg_attr(all( - qemu, - any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc64", - ) -), ignore)] +#[cfg_attr( + all( + qemu, + any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc64", + ) + ), + ignore +)] #[test] pub fn test_recv_ipv6pktinfo() { use nix::net::if_::*; use nix::sys::socket::sockopt::Ipv6RecvPacketInfo; - use nix::sys::socket::{bind, SockaddrIn6, SockFlag, SockType}; + use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6}; use nix::sys::socket::{getsockname, setsockopt, socket}; use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; use std::io::{IoSlice, IoSliceMut}; let lo_ifaddr = loopback_address(AddressFamily::Inet6); let (lo_name, lo) = match lo_ifaddr { - Some(ifaddr) => (ifaddr.interface_name, - ifaddr.address.expect("Expect IPv4 address on interface")), + Some(ifaddr) => ( + ifaddr.interface_name, + ifaddr.address.expect("Expect IPv4 address on interface"), + ), None => return, }; let receive = socket( @@ -1527,7 +1747,8 @@ pub fn test_recv_ipv6pktinfo() { SockType::Datagram, SockFlag::empty(), None, - ).expect("receive socket failed"); + ) + .expect("receive socket failed"); bind(receive, &lo).expect("bind failed"); let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed"); setsockopt(receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed"); @@ -1541,8 +1762,10 @@ pub fn test_recv_ipv6pktinfo() { SockType::Datagram, SockFlag::empty(), None, - ).expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)).expect("sendmsg failed"); + ) + .expect("send socket failed"); + sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + .expect("sendmsg failed"); } { @@ -1555,30 +1778,25 @@ pub fn test_recv_ipv6pktinfo() { &mut iovec, Some(&mut space), MsgFlags::empty(), - ).expect("recvmsg failed"); - assert!( - !msg.flags - .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC) - ); + ) + .expect("recvmsg failed"); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); let mut cmsgs = msg.cmsgs(); if let Some(ControlMessageOwned::Ipv6PacketInfo(pktinfo)) = cmsgs.next() { let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex"); assert_eq!( - pktinfo.ipi6_ifindex as libc::c_uint, - i, + pktinfo.ipi6_ifindex as libc::c_uint, i, "unexpected ifindex (expected {}, got {})", - i, - pktinfo.ipi6_ifindex + i, pktinfo.ipi6_ifindex ); } assert!(cmsgs.next().is_none(), "unexpected additional control msg"); assert_eq!(msg.bytes, 8); - assert_eq!( - *iovec[0], - [1u8, 2, 3, 4, 5, 6, 7, 8] - ); + assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); } } @@ -1587,21 +1805,26 @@ pub fn test_recv_ipv6pktinfo() { #[test] pub fn test_vsock() { use nix::errno::Errno; - use nix::sys::socket::{AddressFamily, socket, bind, connect, listen, - SockType, SockFlag, VsockAddr}; - use nix::unistd::{close}; + use nix::sys::socket::{ + bind, connect, listen, socket, AddressFamily, SockFlag, SockType, + VsockAddr, + }; + use nix::unistd::close; use std::thread; let port: u32 = 3000; - let s1 = socket(AddressFamily::Vsock, SockType::Stream, - SockFlag::empty(), None) - .expect("socket failed"); + let s1 = socket( + AddressFamily::Vsock, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error. let sockaddr_hv = VsockAddr::new(libc::VMADDR_CID_HYPERVISOR, port); - assert_eq!(bind(s1, &sockaddr_hv).err(), - Some(Errno::EADDRNOTAVAIL)); + assert_eq!(bind(s1, &sockaddr_hv).err(), Some(Errno::EADDRNOTAVAIL)); let sockaddr_any = VsockAddr::new(libc::VMADDR_CID_ANY, port); assert_eq!(bind(s1, &sockaddr_any), Ok(())); @@ -1610,9 +1833,13 @@ pub fn test_vsock() { let thr = thread::spawn(move || { let cid: u32 = libc::VMADDR_CID_HOST; - let s2 = socket(AddressFamily::Vsock, SockType::Stream, - SockFlag::empty(), None) - .expect("socket failed"); + let s2 = socket( + AddressFamily::Vsock, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); let sockaddr_host = VsockAddr::new(cid, port); @@ -1634,8 +1861,8 @@ pub fn test_vsock() { #[test] fn test_recvmsg_timestampns() { use nix::sys::socket::*; - use std::io::{IoSlice, IoSliceMut}; use nix::sys::time::*; + use std::io::{IoSlice, IoSliceMut}; use std::time::*; // Set up @@ -1644,7 +1871,9 @@ fn test_recvmsg_timestampns() { AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), - None).unwrap(); + None, + ) + .unwrap(); setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); let localhost = SockaddrIn::new(127, 0, 0, 1, 0); bind(in_socket, &localhost).unwrap(); @@ -1661,18 +1890,19 @@ fn test_recvmsg_timestampns() { let mut cmsgspace = nix::cmsg_space!(TimeSpec); let mut iov = [IoSliceMut::new(&mut buffer)]; - let r = recvmsg::<()>(in_socket, &mut iov, Some(&mut cmsgspace), flags).unwrap(); + let r = recvmsg::<()>(in_socket, &mut iov, Some(&mut cmsgspace), flags) + .unwrap(); let rtime = match r.cmsgs().next() { Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, Some(_) => panic!("Unexpected control message"), - None => panic!("No control message") + None => panic!("No control message"), }; // Check the final time let time1 = SystemTime::now(); // the packet's received timestamp should lie in-between the two system // times, unless the system clock was adjusted in the meantime. - let rduration = Duration::new(rtime.tv_sec() as u64, - rtime.tv_nsec() as u32); + let rduration = + Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32); assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); // Close socket @@ -1686,8 +1916,8 @@ fn test_recvmsg_timestampns() { #[test] fn test_recvmmsg_timestampns() { use nix::sys::socket::*; - use std::io::{IoSlice, IoSliceMut}; use nix::sys::time::*; + use std::io::{IoSlice, IoSliceMut}; use std::time::*; // Set up @@ -1696,7 +1926,9 @@ fn test_recvmmsg_timestampns() { AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), - None).unwrap(); + None, + ) + .unwrap(); setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); bind(in_socket, &localhost).unwrap(); @@ -1712,24 +1944,23 @@ fn test_recvmmsg_timestampns() { let mut buffer = vec![0u8; message.len()]; let mut cmsgspace = nix::cmsg_space!(TimeSpec); let iov = [IoSliceMut::new(&mut buffer)]; - let mut data = vec![ - RecvMmsgData { - iov, - cmsg_buffer: Some(&mut cmsgspace), - }, - ]; - let r: Vec> = recvmmsg(in_socket, &mut data, flags, None).unwrap(); + let mut data = vec![RecvMmsgData { + iov, + cmsg_buffer: Some(&mut cmsgspace), + }]; + let r: Vec> = + recvmmsg(in_socket, &mut data, flags, None).unwrap(); let rtime = match r[0].cmsgs().next() { Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, Some(_) => panic!("Unexpected control message"), - None => panic!("No control message") + None => panic!("No control message"), }; // Check the final time let time1 = SystemTime::now(); // the packet's received timestamp should lie in-between the two system // times, unless the system clock was adjusted in the meantime. - let rduration = Duration::new(rtime.tv_sec() as u64, - rtime.tv_nsec() as u32); + let rduration = + Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32); assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); // Close socket @@ -1742,10 +1973,10 @@ fn test_recvmmsg_timestampns() { #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] #[test] fn test_recvmsg_rxq_ovfl() { - use nix::Error; + use nix::sys::socket::sockopt::{RcvBuf, RxqOvfl}; use nix::sys::socket::*; + use nix::Error; use std::io::{IoSlice, IoSliceMut}; - use nix::sys::socket::sockopt::{RxqOvfl, RcvBuf}; let message = [0u8; 2048]; let bufsize = message.len() * 2; @@ -1754,12 +1985,16 @@ fn test_recvmsg_rxq_ovfl() { AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), - None).unwrap(); + None, + ) + .unwrap(); let out_socket = socket( AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), - None).unwrap(); + None, + ) + .unwrap(); let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); bind(in_socket, &localhost).unwrap(); @@ -1782,7 +2017,8 @@ fn test_recvmsg_rxq_ovfl() { // Send the 3 messages (the receiver buffer can only hold 2 messages) // to create an overflow. for _ in 0..3 { - let l = sendmsg(out_socket, &iov, &[], flags, Some(&address)).unwrap(); + let l = + sendmsg(out_socket, &iov, &[], flags, Some(&address)).unwrap(); assert_eq!(message.len(), l); } @@ -1797,16 +2033,23 @@ fn test_recvmsg_rxq_ovfl() { in_socket, &mut iov, Some(&mut cmsgspace), - MsgFlags::MSG_DONTWAIT) { + MsgFlags::MSG_DONTWAIT, + ) { Ok(r) => { drop_counter = match r.cmsgs().next() { - Some(ControlMessageOwned::RxqOvfl(drop_counter)) => drop_counter, + Some(ControlMessageOwned::RxqOvfl(drop_counter)) => { + drop_counter + } Some(_) => panic!("Unexpected control message"), None => 0, }; - }, - Err(Error::EAGAIN) => { break; }, - _ => { panic!("unknown recvmsg() error"); }, + } + Err(Error::EAGAIN) => { + break; + } + _ => { + panic!("unknown recvmsg() error"); + } } } } @@ -1819,13 +2062,10 @@ fn test_recvmsg_rxq_ovfl() { nix::unistd::close(out_socket).unwrap(); } -#[cfg(any( - target_os = "linux", - target_os = "android", -))] +#[cfg(any(target_os = "linux", target_os = "android",))] mod linux_errqueue { - use nix::sys::socket::*; use super::FromStr; + use nix::sys::socket::*; // Send a UDP datagram to a bogus destination address and observe an ICMP error (v4). // @@ -1853,11 +2093,16 @@ mod linux_errqueue { // Closure handles protocol-specific testing and returns generic sock_extended_err for // protocol-independent test impl. |cmsg| { - if let ControlMessageOwned::Ipv4RecvErr(ext_err, err_addr) = cmsg { + if let ControlMessageOwned::Ipv4RecvErr(ext_err, err_addr) = + cmsg + { if let Some(origin) = err_addr { // Validate that our network error originated from 127.0.0.1:0. assert_eq!(origin.sin_family, AddressFamily::Inet as _); - assert_eq!(origin.sin_addr.s_addr, u32::from_be(0x7f000001)); + assert_eq!( + origin.sin_addr.s_addr, + u32::from_be(0x7f000001) + ); assert_eq!(origin.sin_port, 0); } else { panic!("Expected some error origin"); @@ -1896,10 +2141,15 @@ mod linux_errqueue { // Closure handles protocol-specific testing and returns generic sock_extended_err for // protocol-independent test impl. |cmsg| { - if let ControlMessageOwned::Ipv6RecvErr(ext_err, err_addr) = cmsg { + if let ControlMessageOwned::Ipv6RecvErr(ext_err, err_addr) = + cmsg + { if let Some(origin) = err_addr { // Validate that our network error originated from localhost:0. - assert_eq!(origin.sin6_family, AddressFamily::Inet6 as _); + assert_eq!( + origin.sin6_family, + AddressFamily::Inet6 as _ + ); assert_eq!( origin.sin6_addr.s6_addr, std::net::Ipv6Addr::LOCALHOST.octets() @@ -1916,16 +2166,17 @@ mod linux_errqueue { ) } - fn test_recverr_impl(sa: &str, - af: AddressFamily, - opt: OPT, - ee_origin: u8, - ee_type: u8, - ee_code: u8, - testf: TESTF) - where - OPT: SetSockOpt, - TESTF: FnOnce(&ControlMessageOwned) -> libc::sock_extended_err, + fn test_recverr_impl( + sa: &str, + af: AddressFamily, + opt: OPT, + ee_origin: u8, + ee_type: u8, + ee_code: u8, + testf: TESTF, + ) where + OPT: SetSockOpt, + TESTF: FnOnce(&ControlMessageOwned) -> libc::sock_extended_err, { use nix::errno::Errno; use std::io::IoSliceMut; @@ -1933,9 +2184,15 @@ mod linux_errqueue { const MESSAGE_CONTENTS: &str = "ABCDEF"; let std_sa = std::net::SocketAddr::from_str(sa).unwrap(); let sock_addr = SockaddrStorage::from(std_sa); - let sock = socket(af, SockType::Datagram, SockFlag::SOCK_CLOEXEC, None).unwrap(); + let sock = socket(af, SockType::Datagram, SockFlag::SOCK_CLOEXEC, None) + .unwrap(); setsockopt(sock, opt, &true).unwrap(); - if let Err(e) = sendto(sock, MESSAGE_CONTENTS.as_bytes(), &sock_addr, MsgFlags::empty()) { + if let Err(e) = sendto( + sock, + MESSAGE_CONTENTS.as_bytes(), + &sock_addr, + MsgFlags::empty(), + ) { assert_eq!(e, Errno::EADDRNOTAVAIL); println!("{:?} not available, skipping test.", af); return; @@ -1945,7 +2202,13 @@ mod linux_errqueue { let mut iovec = [IoSliceMut::new(&mut buf)]; let mut cspace = cmsg_space!(libc::sock_extended_err, SA); - let msg = recvmsg(sock, &mut iovec, Some(&mut cspace), MsgFlags::MSG_ERRQUEUE).unwrap(); + let msg = recvmsg( + sock, + &mut iovec, + Some(&mut cspace), + MsgFlags::MSG_ERRQUEUE, + ) + .unwrap(); // The sent message / destination associated with the error is returned: assert_eq!(msg.bytes, MESSAGE_CONTENTS.as_bytes().len()); // recvmsg(2): "The original destination address of the datagram that caused the error is @@ -1982,10 +2245,10 @@ mod linux_errqueue { pub fn test_txtime() { use nix::sys::socket::{ bind, recvmsg, sendmsg, setsockopt, socket, sockopt, ControlMessage, - MsgFlags, SockaddrIn, SockFlag, SockType, + MsgFlags, SockFlag, SockType, SockaddrIn, }; use nix::sys::time::TimeValLike; - use nix::time::{ClockId, clock_gettime}; + use nix::time::{clock_gettime, ClockId}; require_kernel_version!(test_txtime, ">= 5.8"); @@ -2022,7 +2285,8 @@ pub fn test_txtime() { let txtime = (now + delay).num_nanoseconds() as u64; let cmsg = ControlMessage::TxTime(&txtime); - sendmsg(ssock, &iov1, &[cmsg], MsgFlags::empty(), Some(&sock_addr)).unwrap(); + sendmsg(ssock, &iov1, &[cmsg], MsgFlags::empty(), Some(&sock_addr)) + .unwrap(); let mut rbuf = [0u8; 2048]; let mut iov2 = [std::io::IoSliceMut::new(&mut rbuf)]; diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index a17bc09f68..2ddbf77b83 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -1,22 +1,27 @@ -use rand::{thread_rng, Rng}; -use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, SockType, SockFlag, SockProtocol}; #[cfg(any(target_os = "android", target_os = "linux"))] use crate::*; +use nix::sys::socket::{ + getsockopt, setsockopt, socket, sockopt, AddressFamily, SockFlag, + SockProtocol, SockType, +}; +use rand::{thread_rng, Rng}; // NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not. -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", -))] +#[cfg(any(target_os = "dragonfly", target_os = "freebsd",))] #[test] pub fn test_local_peercred_seqpacket() { use nix::{ + sys::socket::socketpair, unistd::{Gid, Uid}, - sys::socket::socketpair }; - let (fd1, _fd2) = socketpair(AddressFamily::Unix, SockType::SeqPacket, None, - SockFlag::empty()).unwrap(); + let (fd1, _fd2) = socketpair( + AddressFamily::Unix, + SockType::SeqPacket, + None, + SockFlag::empty(), + ) + .unwrap(); let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap(); assert_eq!(xucred.version(), 0); assert_eq!(Uid::from_raw(xucred.uid()), Uid::current()); @@ -24,20 +29,25 @@ pub fn test_local_peercred_seqpacket() { } #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "ios" ))] #[test] pub fn test_local_peercred_stream() { use nix::{ + sys::socket::socketpair, unistd::{Gid, Uid}, - sys::socket::socketpair }; - let (fd1, _fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, - SockFlag::empty()).unwrap(); + let (fd1, _fd2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap(); assert_eq!(xucred.version(), 0); assert_eq!(Uid::from_raw(xucred.uid()), Uid::current()); @@ -51,7 +61,13 @@ fn is_so_mark_functional() { require_capability!("is_so_mark_functional", CAP_NET_ADMIN); - let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); + let s = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + None, + ) + .unwrap(); setsockopt(s, sockopt::Mark, &1337).unwrap(); let mark = getsockopt(s, sockopt::Mark).unwrap(); assert_eq!(mark, 1337); @@ -59,8 +75,13 @@ fn is_so_mark_functional() { #[test] fn test_so_buf() { - let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), SockProtocol::Udp) - .unwrap(); + let fd = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + SockProtocol::Udp, + ) + .unwrap(); let bufsize: usize = thread_rng().gen_range(4096..131_072); setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap(); let actual = getsockopt(fd, sockopt::SndBuf).unwrap(); @@ -72,16 +93,21 @@ fn test_so_buf() { #[test] fn test_so_tcp_maxseg() { - use std::net::SocketAddrV4; - use std::str::FromStr; use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn}; use nix::unistd::{close, write}; + use std::net::SocketAddrV4; + use std::str::FromStr; let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap(); let sock_addr = SockaddrIn::from(std_sa); - let rsock = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp) - .unwrap(); + let rsock = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); bind(rsock, &sock_addr).unwrap(); listen(rsock, 10).unwrap(); let initial = getsockopt(rsock, sockopt::TcpMaxSeg).unwrap(); @@ -99,8 +125,13 @@ fn test_so_tcp_maxseg() { } // Connect and check the MSS that was advertised - let ssock = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp) - .unwrap(); + let ssock = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); connect(ssock, &sock_addr).unwrap(); let rsess = accept(rsock).unwrap(); write(rsess, b"hello").unwrap(); @@ -132,17 +163,25 @@ fn test_so_tcp_maxseg() { fn test_tcp_congestion() { use std::ffi::OsString; - let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + None, + ) + .unwrap(); let val = getsockopt(fd, sockopt::TcpCongestion).unwrap(); setsockopt(fd, sockopt::TcpCongestion, &val).unwrap(); - setsockopt(fd, sockopt::TcpCongestion, &OsString::from("tcp_congestion_does_not_exist")).unwrap_err(); + setsockopt( + fd, + sockopt::TcpCongestion, + &OsString::from("tcp_congestion_does_not_exist"), + ) + .unwrap_err(); - assert_eq!( - getsockopt(fd, sockopt::TcpCongestion).unwrap(), - val - ); + assert_eq!(getsockopt(fd, sockopt::TcpCongestion).unwrap(), val); } #[test] @@ -150,27 +189,39 @@ fn test_tcp_congestion() { fn test_bindtodevice() { skip_if_not_root!("test_bindtodevice"); - let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + None, + ) + .unwrap(); let val = getsockopt(fd, sockopt::BindToDevice).unwrap(); setsockopt(fd, sockopt::BindToDevice, &val).unwrap(); - assert_eq!( - getsockopt(fd, sockopt::BindToDevice).unwrap(), - val - ); + assert_eq!(getsockopt(fd, sockopt::BindToDevice).unwrap(), val); } #[test] fn test_so_tcp_keepalive() { - let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp).unwrap(); + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); setsockopt(fd, sockopt::KeepAlive, &true).unwrap(); assert!(getsockopt(fd, sockopt::KeepAlive).unwrap()); - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux"))] { + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux" + ))] + { let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap(); setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap(); assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1); @@ -188,10 +239,22 @@ fn test_so_tcp_keepalive() { #[test] #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] fn test_ttl_opts() { - let fd4 = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap(); + let fd4 = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); setsockopt(fd4, sockopt::Ipv4Ttl, &1) .expect("setting ipv4ttl on an inet socket should succeed"); - let fd6 = socket(AddressFamily::Inet6, SockType::Datagram, SockFlag::empty(), None).unwrap(); + let fd6 = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); setsockopt(fd6, sockopt::Ipv6Ttl, &1) .expect("setting ipv6ttl on an inet6 socket should succeed"); } @@ -199,38 +262,68 @@ fn test_ttl_opts() { #[test] #[cfg(any(target_os = "ios", target_os = "macos"))] fn test_dontfrag_opts() { - let fd4 = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp).unwrap(); + let fd4 = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); setsockopt(fd4, sockopt::IpDontFrag, &true) .expect("setting IP_DONTFRAG on an inet stream socket should succeed"); - setsockopt(fd4, sockopt::IpDontFrag, &false) - .expect("unsetting IP_DONTFRAG on an inet stream socket should succeed"); - let fd4d = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap(); - setsockopt(fd4d, sockopt::IpDontFrag, &true) - .expect("setting IP_DONTFRAG on an inet datagram socket should succeed"); - setsockopt(fd4d, sockopt::IpDontFrag, &false) - .expect("unsetting IP_DONTFRAG on an inet datagram socket should succeed"); + setsockopt(fd4, sockopt::IpDontFrag, &false).expect( + "unsetting IP_DONTFRAG on an inet stream socket should succeed", + ); + let fd4d = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(fd4d, sockopt::IpDontFrag, &true).expect( + "setting IP_DONTFRAG on an inet datagram socket should succeed", + ); + setsockopt(fd4d, sockopt::IpDontFrag, &false).expect( + "unsetting IP_DONTFRAG on an inet datagram socket should succeed", + ); } #[test] #[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "linux", - target_os = "macos", - ) -)] + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", +))] // Disable the test under emulation because it fails in Cirrus-CI. Lack // of QEMU support is suspected. #[cfg_attr(qemu, ignore)] fn test_v6dontfrag_opts() { - let fd6 = socket(AddressFamily::Inet6, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp).unwrap(); - setsockopt(fd6, sockopt::Ipv6DontFrag, &true) - .expect("setting IPV6_DONTFRAG on an inet6 stream socket should succeed"); - setsockopt(fd6, sockopt::Ipv6DontFrag, &false) - .expect("unsetting IPV6_DONTFRAG on an inet6 stream socket should succeed"); - let fd6d = socket(AddressFamily::Inet6, SockType::Datagram, SockFlag::empty(), None).unwrap(); - setsockopt(fd6d, sockopt::Ipv6DontFrag, &true) - .expect("setting IPV6_DONTFRAG on an inet6 datagram socket should succeed"); - setsockopt(fd6d, sockopt::Ipv6DontFrag, &false) - .expect("unsetting IPV6_DONTFRAG on an inet6 datagram socket should succeed"); + let fd6 = socket( + AddressFamily::Inet6, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + setsockopt(fd6, sockopt::Ipv6DontFrag, &true).expect( + "setting IPV6_DONTFRAG on an inet6 stream socket should succeed", + ); + setsockopt(fd6, sockopt::Ipv6DontFrag, &false).expect( + "unsetting IPV6_DONTFRAG on an inet6 stream socket should succeed", + ); + let fd6d = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); + setsockopt(fd6d, sockopt::Ipv6DontFrag, &true).expect( + "setting IPV6_DONTFRAG on an inet6 datagram socket should succeed", + ); + setsockopt(fd6d, sockopt::Ipv6DontFrag, &false).expect( + "unsetting IPV6_DONTFRAG on an inet6 datagram socket should succeed", + ); } diff --git a/test/sys/test_sysinfo.rs b/test/sys/test_sysinfo.rs index 73e6586f62..2897366eff 100644 --- a/test/sys/test_sysinfo.rs +++ b/test/sys/test_sysinfo.rs @@ -9,10 +9,12 @@ fn sysinfo_works() { assert!(l5 >= 0.0); assert!(l15 >= 0.0); - info.uptime(); // just test Duration construction + info.uptime(); // just test Duration construction - assert!(info.swap_free() <= info.swap_total(), - "more swap available than installed (free: {}, total: {})", - info.swap_free(), - info.swap_total()); + assert!( + info.swap_free() <= info.swap_total(), + "more swap available than installed (free: {}, total: {})", + info.swap_free(), + info.swap_total() + ); } diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs index 4a8615437e..e567a52c07 100644 --- a/test/sys/test_termios.rs +++ b/test/sys/test_termios.rs @@ -1,11 +1,11 @@ use std::os::unix::prelude::*; use tempfile::tempfile; -use nix::fcntl; use nix::errno::Errno; +use nix::fcntl; use nix::pty::openpty; -use nix::sys::termios::{self, LocalFlags, OutputFlags, tcgetattr}; -use nix::unistd::{read, write, close}; +use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags}; +use nix::unistd::{close, read, write}; /// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s fn write_all(f: RawFd, buf: &[u8]) { @@ -31,15 +31,16 @@ fn test_tcgetattr_pty() { #[test] fn test_tcgetattr_enotty() { let file = tempfile().unwrap(); - assert_eq!(termios::tcgetattr(file.as_raw_fd()).err(), - Some(Errno::ENOTTY)); + assert_eq!( + termios::tcgetattr(file.as_raw_fd()).err(), + Some(Errno::ENOTTY) + ); } // Test tcgetattr on an invalid file descriptor #[test] fn test_tcgetattr_ebadf() { - assert_eq!(termios::tcgetattr(-1).err(), - Some(Errno::EBADF)); + assert_eq!(termios::tcgetattr(-1).err(), Some(Errno::EBADF)); } // Test modifying output flags @@ -60,11 +61,15 @@ fn test_output_flags() { }; // Make sure postprocessing '\r' isn't specified by default or this test is useless. - assert!(!termios.output_flags.contains(OutputFlags::OPOST | OutputFlags::OCRNL)); + assert!(!termios + .output_flags + .contains(OutputFlags::OPOST | OutputFlags::OCRNL)); // Specify that '\r' characters should be transformed to '\n' // OPOST is specified to enable post-processing - termios.output_flags.insert(OutputFlags::OPOST | OutputFlags::OCRNL); + termios + .output_flags + .insert(OutputFlags::OPOST | OutputFlags::OCRNL); // Open a pty let pty = openpty(None, &termios).unwrap(); @@ -114,7 +119,8 @@ fn test_local_flags() { // Set the master is in nonblocking mode or reading will never return. let flags = fcntl::fcntl(pty.master, fcntl::F_GETFL).unwrap(); - let new_flags = fcntl::OFlag::from_bits_truncate(flags) | fcntl::OFlag::O_NONBLOCK; + let new_flags = + fcntl::OFlag::from_bits_truncate(flags) | fcntl::OFlag::O_NONBLOCK; fcntl::fcntl(pty.master, fcntl::F_SETFL(new_flags)).unwrap(); // Write into the master diff --git a/test/sys/test_timerfd.rs b/test/sys/test_timerfd.rs index 24fb2ac002..927cc70d1d 100644 --- a/test/sys/test_timerfd.rs +++ b/test/sys/test_timerfd.rs @@ -1,10 +1,13 @@ use nix::sys::time::{TimeSpec, TimeValLike}; -use nix::sys::timerfd::{ClockId, Expiration, TimerFd, TimerFlags, TimerSetTimeFlags}; +use nix::sys::timerfd::{ + ClockId, Expiration, TimerFd, TimerFlags, TimerSetTimeFlags, +}; use std::time::Instant; #[test] pub fn test_timerfd_oneshot() { - let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); + let timer = + TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); let before = Instant::now(); @@ -23,12 +26,16 @@ pub fn test_timerfd_oneshot() { #[test] pub fn test_timerfd_interval() { - let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); + let timer = + TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); let before = Instant::now(); timer .set( - Expiration::IntervalDelayed(TimeSpec::seconds(1), TimeSpec::seconds(2)), + Expiration::IntervalDelayed( + TimeSpec::seconds(1), + TimeSpec::seconds(2), + ), TimerSetTimeFlags::empty(), ) .unwrap(); @@ -46,7 +53,8 @@ pub fn test_timerfd_interval() { #[test] pub fn test_timerfd_unset() { - let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); + let timer = + TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap(); timer .set( diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index fc2dfabeef..f46b1940c0 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -1,18 +1,18 @@ use nix::sys::uio::*; use nix::unistd::*; -use rand::{thread_rng, Rng}; use rand::distributions::Alphanumeric; -use std::{cmp, iter}; -use std::fs::{OpenOptions}; +use rand::{thread_rng, Rng}; +use std::fs::OpenOptions; use std::io::IoSlice; use std::os::unix::io::AsRawFd; +use std::{cmp, iter}; #[cfg(not(target_os = "redox"))] use std::io::IoSliceMut; +use tempfile::tempdir; #[cfg(not(target_os = "redox"))] use tempfile::tempfile; -use tempfile::tempdir; #[test] fn test_writev() { @@ -31,8 +31,12 @@ fn test_writev() { let mut consumed = 0; while consumed < to_write.len() { let left = to_write.len() - consumed; - let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64..cmp::min(256, left)) }; - let b = &to_write[consumed..consumed+slice_len]; + let slice_len = if left <= 64 { + left + } else { + thread_rng().gen_range(64..cmp::min(256, left)) + }; + let b = &to_write[consumed..consumed + slice_len]; iovecs.push(IoSlice::new(b)); consumed += slice_len; } @@ -65,7 +69,7 @@ fn test_writev() { #[test] #[cfg(not(target_os = "redox"))] fn test_readv() { - let s:String = thread_rng() + let s: String = thread_rng() .sample_iter(&Alphanumeric) .map(char::from) .take(128) @@ -75,7 +79,11 @@ fn test_readv() { let mut allocated = 0; while allocated < to_write.len() { let left = to_write.len() - allocated; - let vec_len = if left <= 64 { left } else { thread_rng().gen_range(64..cmp::min(256, left)) }; + let vec_len = if left <= 64 { + left + } else { + thread_rng().gen_range(64..cmp::min(256, left)) + }; let v: Vec = iter::repeat(0u8).take(vec_len).collect(); storage.push(v); allocated += vec_len; @@ -117,12 +125,12 @@ fn test_pwrite() { use std::io::Read; let mut file = tempfile().unwrap(); - let buf = [1u8;8]; + let buf = [1u8; 8]; assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8)); let mut file_content = Vec::new(); file.read_to_end(&mut file_content).unwrap(); - let mut expected = vec![0u8;8]; - expected.extend(vec![1;8]); + let mut expected = vec![0u8; 8]; + expected.extend(vec![1; 8]); assert_eq!(file_content, expected); } @@ -133,12 +141,17 @@ fn test_pread() { let tempdir = tempdir().unwrap(); let path = tempdir.path().join("pread_test_file"); - let mut file = OpenOptions::new().write(true).read(true).create(true) - .truncate(true).open(path).unwrap(); + let mut file = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); let file_content: Vec = (0..64).collect(); file.write_all(&file_content).unwrap(); - let mut buf = [0u8;16]; + let mut buf = [0u8; 16]; assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16)); let expected: Vec<_> = (16..32).collect(); assert_eq!(&buf[..], &expected[..]); @@ -150,7 +163,7 @@ fn test_pwritev() { use std::io::Read; let to_write: Vec = (0..128).collect(); - let expected: Vec = [vec![0;100], to_write.clone()].concat(); + let expected: Vec = [vec![0; 100], to_write.clone()].concat(); let iovecs = [ IoSlice::new(&to_write[0..17]), @@ -162,8 +175,13 @@ fn test_pwritev() { // pwritev them into a temporary file let path = tempdir.path().join("pwritev_test_file"); - let mut file = OpenOptions::new().write(true).read(true).create(true) - .truncate(true).open(path).unwrap(); + let mut file = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap(); assert_eq!(written, to_write.len()); @@ -186,20 +204,23 @@ fn test_preadv() { let path = tempdir.path().join("preadv_test_file"); - let mut file = OpenOptions::new().read(true).write(true).create(true) - .truncate(true).open(path).unwrap(); + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); file.write_all(&to_write).unwrap(); - let mut buffers: Vec> = vec![ - vec![0; 24], - vec![0; 1], - vec![0; 75], - ]; + let mut buffers: Vec> = vec![vec![0; 24], vec![0; 1], vec![0; 75]]; { // Borrow the buffers into IoVecs and preadv into them - let mut iovecs: Vec<_> = buffers.iter_mut().map( - |buf| IoSliceMut::new(&mut buf[..])).collect(); + let mut iovecs: Vec<_> = buffers + .iter_mut() + .map(|buf| IoSliceMut::new(&mut buf[..])) + .collect(); assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100)); } @@ -208,14 +229,15 @@ fn test_preadv() { } #[test] -#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] // uclibc doesn't implement process_vm_readv +#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] +// uclibc doesn't implement process_vm_readv // qemu-user doesn't implement process_vm_readv/writev on most arches #[cfg_attr(qemu, ignore)] fn test_process_vm_readv() { - use nix::unistd::ForkResult::*; + use crate::*; use nix::sys::signal::*; use nix::sys::wait::*; - use crate::*; + use nix::unistd::ForkResult::*; require_capability!("test_process_vm_readv", CAP_SYS_PTRACE); let _m = crate::FORK_MTX.lock(); @@ -225,7 +247,7 @@ fn test_process_vm_readv() { let mut vector = vec![1u8, 2, 3, 4, 5]; let (r, w) = pipe().unwrap(); - match unsafe{fork()}.expect("Error: Fork Failed") { + match unsafe { fork() }.expect("Error: Fork Failed") { Parent { child } => { close(w).unwrap(); // wait for child @@ -236,16 +258,18 @@ fn test_process_vm_readv() { let remote_iov = RemoteIoVec { base: ptr, len: 5 }; let mut buf = vec![0u8; 5]; - let ret = process_vm_readv(child, - &mut [IoSliceMut::new(&mut buf)], - &[remote_iov]); + let ret = process_vm_readv( + child, + &mut [IoSliceMut::new(&mut buf)], + &[remote_iov], + ); kill(child, SIGTERM).unwrap(); waitpid(child, None).unwrap(); assert_eq!(Ok(5), ret); assert_eq!(20u8, buf.iter().sum()); - }, + } Child => { let _ = close(r); for i in &mut vector { @@ -253,7 +277,9 @@ fn test_process_vm_readv() { } let _ = write(w, b"\0"); let _ = close(w); - loop { pause(); } - }, + loop { + pause(); + } + } } } diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs index 058573a178..1a4a0f879e 100644 --- a/test/sys/test_wait.rs +++ b/test/sys/test_wait.rs @@ -1,9 +1,9 @@ +use libc::_exit; use nix::errno::Errno; -use nix::unistd::*; -use nix::unistd::ForkResult::*; use nix::sys::signal::*; use nix::sys::wait::*; -use libc::_exit; +use nix::unistd::ForkResult::*; +use nix::unistd::*; #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] @@ -11,15 +11,18 @@ fn test_wait_signal() { let _m = crate::FORK_MTX.lock(); // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe. - match unsafe{fork()}.expect("Error: Fork Failed") { - Child => { - pause(); - unsafe { _exit(123) } - }, - Parent { child } => { - kill(child, Some(SIGKILL)).expect("Error: Kill Failed"); - assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, SIGKILL, false))); - }, + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => { + pause(); + unsafe { _exit(123) } + } + Parent { child } => { + kill(child, Some(SIGKILL)).expect("Error: Kill Failed"); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Signaled(child, SIGKILL, false)) + ); + } } } @@ -35,18 +38,18 @@ fn test_waitid_signal() { let _m = crate::FORK_MTX.lock(); // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe. - match unsafe{fork()}.expect("Error: Fork Failed") { - Child => { - pause(); - unsafe { _exit(123) } - }, - Parent { child } => { - kill(child, Some(SIGKILL)).expect("Error: Kill Failed"); - assert_eq!( - waitid(Id::Pid(child), WaitPidFlag::WEXITED), - Ok(WaitStatus::Signaled(child, SIGKILL, false)), - ); - }, + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => { + pause(); + unsafe { _exit(123) } + } + Parent { child } => { + kill(child, Some(SIGKILL)).expect("Error: Kill Failed"); + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::Signaled(child, SIGKILL, false)), + ); + } } } @@ -55,11 +58,13 @@ fn test_wait_exit() { let _m = crate::FORK_MTX.lock(); // Safe: Child only calls `_exit`, which is async-signal-safe. - match unsafe{fork()}.expect("Error: Fork Failed") { - Child => unsafe { _exit(12); }, - Parent { child } => { - assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12))); - }, + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => unsafe { + _exit(12); + }, + Parent { child } => { + assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12))); + } } } @@ -76,22 +81,30 @@ fn test_waitid_exit() { let _m = crate::FORK_MTX.lock(); // Safe: Child only calls `_exit`, which is async-signal-safe. - match unsafe{fork()}.expect("Error: Fork Failed") { - Child => unsafe { _exit(12); }, - Parent { child } => { - assert_eq!( - waitid(Id::Pid(child), WaitPidFlag::WEXITED), - Ok(WaitStatus::Exited(child, 12)), - ); - } + match unsafe { fork() }.expect("Error: Fork Failed") { + Child => unsafe { + _exit(12); + }, + Parent { child } => { + assert_eq!( + waitid(Id::Pid(child), WaitPidFlag::WEXITED), + Ok(WaitStatus::Exited(child, 12)), + ); + } } } #[test] fn test_waitstatus_from_raw() { let pid = Pid::from_raw(1); - assert_eq!(WaitStatus::from_raw(pid, 0x0002), Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false))); - assert_eq!(WaitStatus::from_raw(pid, 0x0200), Ok(WaitStatus::Exited(pid, 2))); + assert_eq!( + WaitStatus::from_raw(pid, 0x0002), + Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)) + ); + assert_eq!( + WaitStatus::from_raw(pid, 0x0200), + Ok(WaitStatus::Exited(pid, 2)) + ); assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Errno::EINVAL)); } @@ -99,7 +112,7 @@ fn test_waitstatus_from_raw() { fn test_waitstatus_pid() { let _m = crate::FORK_MTX.lock(); - match unsafe{fork()}.unwrap() { + match unsafe { fork() }.unwrap() { Child => unsafe { _exit(0) }, Parent { child } => { let status = waitpid(child, None).unwrap(); @@ -131,13 +144,13 @@ fn test_waitid_pid() { // FIXME: qemu-user doesn't implement ptrace on most arches #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] mod ptrace { - use nix::sys::ptrace::{self, Options, Event}; + use crate::*; + use libc::_exit; + use nix::sys::ptrace::{self, Event, Options}; use nix::sys::signal::*; use nix::sys::wait::*; - use nix::unistd::*; use nix::unistd::ForkResult::*; - use libc::_exit; - use crate::*; + use nix::unistd::*; fn ptrace_child() -> ! { ptrace::traceme().unwrap(); @@ -149,16 +162,30 @@ mod ptrace { fn ptrace_wait_parent(child: Pid) { // Wait for the raised SIGTRAP - assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, SIGTRAP))); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::Stopped(child, SIGTRAP)) + ); // We want to test a syscall stop and a PTRACE_EVENT stop - assert!(ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT).is_ok()); + assert!(ptrace::setoptions( + child, + Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT + ) + .is_ok()); // First, stop on the next system call, which will be exit() assert!(ptrace::syscall(child, None).is_ok()); assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); // Then get the ptrace event for the process exiting assert!(ptrace::cont(child, None).is_ok()); - assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, Event::PTRACE_EVENT_EXIT as i32))); + assert_eq!( + waitpid(child, None), + Ok(WaitStatus::PtraceEvent( + child, + SIGTRAP, + Event::PTRACE_EVENT_EXIT as i32 + )) + ); // Finally get the normal wait() result, now that the process has exited assert!(ptrace::cont(child, None).is_ok()); assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0))); @@ -175,7 +202,11 @@ mod ptrace { Ok(WaitStatus::PtraceEvent(child, SIGTRAP, 0)), ); // We want to test a syscall stop and a PTRACE_EVENT stop - assert!(ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT).is_ok()); + assert!(ptrace::setoptions( + child, + Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT + ) + .is_ok()); // First, stop on the next system call, which will be exit() assert!(ptrace::syscall(child, None).is_ok()); @@ -187,7 +218,11 @@ mod ptrace { assert!(ptrace::cont(child, None).is_ok()); assert_eq!( waitid(Id::Pid(child), WaitPidFlag::WEXITED), - Ok(WaitStatus::PtraceEvent(child, SIGTRAP, Event::PTRACE_EVENT_EXIT as i32)), + Ok(WaitStatus::PtraceEvent( + child, + SIGTRAP, + Event::PTRACE_EVENT_EXIT as i32 + )), ); // Finally get the normal wait() result, now that the process has exited assert!(ptrace::cont(child, None).is_ok()); @@ -202,7 +237,7 @@ mod ptrace { require_capability!("test_wait_ptrace", CAP_SYS_PTRACE); let _m = crate::FORK_MTX.lock(); - match unsafe{fork()}.expect("Error: Fork Failed") { + match unsafe { fork() }.expect("Error: Fork Failed") { Child => ptrace_child(), Parent { child } => ptrace_wait_parent(child), } @@ -214,7 +249,7 @@ mod ptrace { require_capability!("test_waitid_ptrace", CAP_SYS_PTRACE); let _m = crate::FORK_MTX.lock(); - match unsafe{fork()}.expect("Error: Fork Failed") { + match unsafe { fork() }.expect("Error: Fork Failed") { Child => ptrace_child(), Parent { child } => ptrace_waitid_parent(child), } diff --git a/test/test.rs b/test/test.rs index 240d6e37c4..f725ef97a0 100644 --- a/test/test.rs +++ b/test/test.rs @@ -10,38 +10,46 @@ mod sys; #[cfg(not(target_os = "redox"))] mod test_dir; mod test_fcntl; -#[cfg(any(target_os = "android", - target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "linux"))] mod test_kmod; -#[cfg(target_os = "freebsd")] -mod test_nmount; -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "fushsia", - target_os = "linux", - target_os = "netbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fushsia", + target_os = "linux", + target_os = "netbsd" +))] mod test_mq; #[cfg(not(target_os = "redox"))] mod test_net; mod test_nix_path; -mod test_resource; +#[cfg(target_os = "freebsd")] +mod test_nmount; mod test_poll; -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] mod test_pty; -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "linux"))] +mod test_resource; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "linux" +))] mod test_sched; -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos" +))] mod test_sendfile; mod test_stat; mod test_time; -mod test_unistd; #[cfg(all( any( target_os = "freebsd", @@ -53,15 +61,15 @@ mod test_unistd; feature = "signal" ))] mod test_timer; +mod test_unistd; +use nix::unistd::{chdir, getcwd, read}; +use parking_lot::{Mutex, RwLock, RwLockWriteGuard}; use std::os::unix::io::RawFd; use std::path::PathBuf; -use parking_lot::{Mutex, RwLock, RwLockWriteGuard}; -use nix::unistd::{chdir, getcwd, read}; - /// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s -fn read_exact(f: RawFd, buf: &mut [u8]) { +fn read_exact(f: RawFd, buf: &mut [u8]) { let mut len = 0; while len < buf.len() { // get_mut would be better than split_at_mut, but it requires nightly @@ -92,13 +100,13 @@ lazy_static! { /// RAII object that restores a test's original directory on drop struct DirRestore<'a> { d: PathBuf, - _g: RwLockWriteGuard<'a, ()> + _g: RwLockWriteGuard<'a, ()>, } impl<'a> DirRestore<'a> { fn new() -> Self { let guard = crate::CWD_LOCK.write(); - DirRestore{ + DirRestore { _g: guard, d: getcwd().unwrap(), } diff --git a/test/test_dir.rs b/test/test_dir.rs index aaef34e4d6..9d2780c0e6 100644 --- a/test/test_dir.rs +++ b/test/test_dir.rs @@ -4,7 +4,6 @@ use nix::sys::stat::Mode; use std::fs::File; use tempfile::tempdir; - #[cfg(test)] fn flags() -> OFlag { #[cfg(target_os = "illumos")] @@ -17,7 +16,7 @@ fn flags() -> OFlag { } #[test] -#[allow(clippy::unnecessary_sort_by)] // False positive +#[allow(clippy::unnecessary_sort_by)] // False positive fn read() { let tmp = tempdir().unwrap(); File::create(&tmp.path().join("foo")).unwrap(); @@ -43,9 +42,18 @@ fn read() { fn rewind() { let tmp = tempdir().unwrap(); let mut dir = Dir::open(tmp.path(), flags(), Mode::empty()).unwrap(); - let entries1: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect(); - let entries2: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect(); - let entries3: Vec<_> = dir.into_iter().map(|e| e.unwrap().file_name().to_owned()).collect(); + let entries1: Vec<_> = dir + .iter() + .map(|e| e.unwrap().file_name().to_owned()) + .collect(); + let entries2: Vec<_> = dir + .iter() + .map(|e| e.unwrap().file_name().to_owned()) + .collect(); + let entries3: Vec<_> = dir + .into_iter() + .map(|e| e.unwrap().file_name().to_owned()) + .collect(); assert_eq!(entries1, entries2); assert_eq!(entries2, entries3); } diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 5f2e53bd9b..d4a12718d9 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -1,7 +1,7 @@ #[cfg(not(target_os = "redox"))] use nix::errno::*; #[cfg(not(target_os = "redox"))] -use nix::fcntl::{open, OFlag, readlink}; +use nix::fcntl::{open, readlink, OFlag}; #[cfg(not(target_os = "redox"))] use nix::fcntl::{openat, readlinkat, renameat}; #[cfg(all( @@ -14,19 +14,19 @@ use nix::fcntl::{openat, readlinkat, renameat}; target_arch = "s390x" ) ))] -use nix::fcntl::{RenameFlags, renameat2}; +use nix::fcntl::{renameat2, RenameFlags}; #[cfg(not(target_os = "redox"))] use nix::sys::stat::Mode; #[cfg(not(target_os = "redox"))] use nix::unistd::{close, read}; #[cfg(not(target_os = "redox"))] -use tempfile::{self, NamedTempFile}; -#[cfg(not(target_os = "redox"))] use std::fs::File; #[cfg(not(target_os = "redox"))] use std::io::prelude::*; #[cfg(not(target_os = "redox"))] use std::os::unix::fs; +#[cfg(not(target_os = "redox"))] +use tempfile::{self, NamedTempFile}; #[test] #[cfg(not(target_os = "redox"))] @@ -38,13 +38,16 @@ fn test_openat() { let mut tmp = NamedTempFile::new().unwrap(); tmp.write_all(CONTENTS).unwrap(); - let dirfd = open(tmp.path().parent().unwrap(), - OFlag::empty(), - Mode::empty()).unwrap(); - let fd = openat(dirfd, - tmp.path().file_name().unwrap(), - OFlag::O_RDONLY, - Mode::empty()).unwrap(); + let dirfd = + open(tmp.path().parent().unwrap(), OFlag::empty(), Mode::empty()) + .unwrap(); + let fd = openat( + dirfd, + tmp.path().file_name().unwrap(), + OFlag::O_RDONLY, + Mode::empty(), + ) + .unwrap(); let mut buf = [0u8; 1024]; assert_eq!(4, read(fd, &mut buf).unwrap()); @@ -58,14 +61,18 @@ fn test_openat() { #[cfg(not(target_os = "redox"))] fn test_renameat() { let old_dir = tempfile::tempdir().unwrap(); - let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let old_dirfd = + open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); let old_path = old_dir.path().join("old"); File::create(&old_path).unwrap(); let new_dir = tempfile::tempdir().unwrap(); - let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let new_dirfd = + open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap(); - assert_eq!(renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(), - Errno::ENOENT); + assert_eq!( + renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(), + Errno::ENOENT + ); close(old_dirfd).unwrap(); close(new_dirfd).unwrap(); assert!(new_dir.path().join("new").exists()); @@ -84,11 +91,13 @@ fn test_renameat() { ))] fn test_renameat2_behaves_like_renameat_with_no_flags() { let old_dir = tempfile::tempdir().unwrap(); - let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let old_dirfd = + open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); let old_path = old_dir.path().join("old"); File::create(&old_path).unwrap(); let new_dir = tempfile::tempdir().unwrap(); - let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let new_dirfd = + open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); renameat2( Some(old_dirfd), "old", @@ -126,14 +135,16 @@ fn test_renameat2_behaves_like_renameat_with_no_flags() { ))] fn test_renameat2_exchange() { let old_dir = tempfile::tempdir().unwrap(); - let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let old_dirfd = + open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); let old_path = old_dir.path().join("old"); { let mut old_f = File::create(&old_path).unwrap(); old_f.write_all(b"old").unwrap(); } let new_dir = tempfile::tempdir().unwrap(); - let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let new_dirfd = + open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); let new_path = new_dir.path().join("new"); { let mut new_f = File::create(&new_path).unwrap(); @@ -172,11 +183,13 @@ fn test_renameat2_exchange() { ))] fn test_renameat2_noreplace() { let old_dir = tempfile::tempdir().unwrap(); - let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let old_dirfd = + open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); let old_path = old_dir.path().join("old"); File::create(&old_path).unwrap(); let new_dir = tempfile::tempdir().unwrap(); - let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let new_dirfd = + open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); let new_path = new_dir.path().join("new"); File::create(&new_path).unwrap(); assert_eq!( @@ -196,7 +209,6 @@ fn test_renameat2_noreplace() { assert!(old_dir.path().join("old").exists()); } - #[test] #[cfg(not(target_os = "redox"))] fn test_readlink() { @@ -205,22 +217,22 @@ fn test_readlink() { let dst = tempdir.path().join("b"); println!("a: {:?}, b: {:?}", &src, &dst); fs::symlink(&src.as_path(), &dst.as_path()).unwrap(); - let dirfd = open(tempdir.path(), - OFlag::empty(), - Mode::empty()).unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); let expected_dir = src.to_str().unwrap(); assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir); - assert_eq!(readlinkat(dirfd, "b").unwrap().to_str().unwrap(), expected_dir); - + assert_eq!( + readlinkat(dirfd, "b").unwrap().to_str().unwrap(), + expected_dir + ); } #[cfg(any(target_os = "linux", target_os = "android"))] mod linux_android { + use libc::loff_t; use std::io::prelude::*; use std::io::{IoSlice, SeekFrom}; use std::os::unix::prelude::*; - use libc::loff_t; use nix::fcntl::*; use nix::unistd::{close, pipe, read, write}; @@ -275,8 +287,15 @@ mod linux_android { let (rd, wr) = pipe().unwrap(); let mut offset: loff_t = 5; - let res = splice(tmp.as_raw_fd(), Some(&mut offset), - wr, None, 2, SpliceFFlags::empty()).unwrap(); + let res = splice( + tmp.as_raw_fd(), + Some(&mut offset), + wr, + None, + 2, + SpliceFFlags::empty(), + ) + .unwrap(); assert_eq!(2, res); @@ -321,10 +340,7 @@ mod linux_android { let buf1 = b"abcdef"; let buf2 = b"defghi"; - let iovecs = vec![ - IoSlice::new(&buf1[0..3]), - IoSlice::new(&buf2[0..3]) - ]; + let iovecs = vec![IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])]; let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap(); @@ -359,7 +375,7 @@ mod linux_android { #[test] #[cfg(all(target_os = "linux", not(target_env = "musl")))] - #[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile + #[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile fn test_ofd_write_lock() { use nix::sys::stat::fstat; use std::mem; @@ -377,7 +393,7 @@ mod linux_android { let inode = fstat(fd).expect("fstat failed").st_ino as usize; let mut flock: libc::flock = unsafe { - mem::zeroed() // required for Linux/mips + mem::zeroed() // required for Linux/mips }; flock.l_type = libc::F_WRLCK as libc::c_short; flock.l_whence = libc::SEEK_SET as libc::c_short; @@ -397,7 +413,7 @@ mod linux_android { #[test] #[cfg(all(target_os = "linux", not(target_env = "musl")))] - #[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile + #[cfg_attr(target_env = "uclibc", ignore)] // uclibc doesn't support OFD locks, but the test should still compile fn test_ofd_read_lock() { use nix::sys::stat::fstat; use std::mem; @@ -415,7 +431,7 @@ mod linux_android { let inode = fstat(fd).expect("fstat failed").st_ino as usize; let mut flock: libc::flock = unsafe { - mem::zeroed() // required for Linux/mips + mem::zeroed() // required for Linux/mips }; flock.l_type = libc::F_RDLCK as libc::c_short; flock.l_whence = libc::SEEK_SET as libc::c_short; @@ -435,10 +451,7 @@ mod linux_android { #[cfg(all(target_os = "linux", not(target_env = "musl")))] fn lock_info(inode: usize) -> Option<(String, String)> { - use std::{ - fs::File, - io::BufReader - }; + use std::{fs::File, io::BufReader}; let file = File::open("/proc/locks").expect("open /proc/locks failed"); let buf = BufReader::new(file); @@ -458,26 +471,29 @@ mod linux_android { } } -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "wasi", - target_env = "uclibc", - target_os = "freebsd"))] +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "wasi", + target_env = "uclibc", + target_os = "freebsd" +))] mod test_posix_fadvise { - use tempfile::NamedTempFile; - use std::os::unix::io::{RawFd, AsRawFd}; use nix::errno::Errno; use nix::fcntl::*; use nix::unistd::pipe; + use std::os::unix::io::{AsRawFd, RawFd}; + use tempfile::NamedTempFile; #[test] fn test_success() { let tmp = NamedTempFile::new().unwrap(); let fd = tmp.as_raw_fd(); - let res = posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED); + let res = + posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED); assert!(res.is_ok()); } @@ -485,25 +501,35 @@ mod test_posix_fadvise { #[test] fn test_errno() { let (rd, _wr) = pipe().unwrap(); - let res = posix_fadvise(rd as RawFd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED); + let res = posix_fadvise( + rd as RawFd, + 0, + 100, + PosixFadviseAdvice::POSIX_FADV_WILLNEED, + ); assert_eq!(res, Err(Errno::ESPIPE)); } } -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "wasi", - target_os = "freebsd"))] +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "wasi", + target_os = "freebsd" +))] mod test_posix_fallocate { - use tempfile::NamedTempFile; - use std::{io::Read, os::unix::io::{RawFd, AsRawFd}}; use nix::errno::Errno; use nix::fcntl::*; use nix::unistd::pipe; + use std::{ + io::Read, + os::unix::io::{AsRawFd, RawFd}, + }; + use tempfile::NamedTempFile; #[test] fn success() { @@ -535,11 +561,7 @@ mod test_posix_fallocate { let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err(); match err { Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (), - errno => - panic!( - "unexpected errno {}", - errno, - ), + errno => panic!("unexpected errno {}", errno,), } } } diff --git a/test/test_kmod/mod.rs b/test/test_kmod/mod.rs index 8eef5384a3..5ebc2423db 100644 --- a/test/test_kmod/mod.rs +++ b/test/test_kmod/mod.rs @@ -1,22 +1,25 @@ +use crate::*; use std::fs::copy; use std::path::PathBuf; use std::process::Command; use tempfile::{tempdir, TempDir}; -use crate::*; fn compile_kernel_module() -> (PathBuf, String, TempDir) { let _m = crate::FORK_MTX.lock(); - let tmp_dir = tempdir().expect("unable to create temporary build directory"); + let tmp_dir = + tempdir().expect("unable to create temporary build directory"); copy( "test/test_kmod/hello_mod/hello.c", &tmp_dir.path().join("hello.c"), - ).expect("unable to copy hello.c to temporary build directory"); + ) + .expect("unable to copy hello.c to temporary build directory"); copy( "test/test_kmod/hello_mod/Makefile", &tmp_dir.path().join("Makefile"), - ).expect("unable to copy Makefile to temporary build directory"); + ) + .expect("unable to copy Makefile to temporary build directory"); let status = Command::new("make") .current_dir(tmp_dir.path()) @@ -51,12 +54,16 @@ fn test_finit_and_delete_module() { delete_module( &CString::new(kmod_name).unwrap(), DeleteModuleFlags::empty(), - ).expect("unable to unload kernel module"); + ) + .expect("unable to unload kernel module"); } #[test] fn test_finit_and_delete_module_with_params() { - require_capability!("test_finit_and_delete_module_with_params", CAP_SYS_MODULE); + require_capability!( + "test_finit_and_delete_module_with_params", + CAP_SYS_MODULE + ); let _m0 = crate::KMOD_MTX.lock(); let _m1 = crate::CWD_LOCK.read(); @@ -67,12 +74,14 @@ fn test_finit_and_delete_module_with_params() { &f, &CString::new("who=Rust number=2018").unwrap(), ModuleInitFlags::empty(), - ).expect("unable to load kernel module"); + ) + .expect("unable to load kernel module"); delete_module( &CString::new(kmod_name).unwrap(), DeleteModuleFlags::empty(), - ).expect("unable to unload kernel module"); + ) + .expect("unable to unload kernel module"); } #[test] @@ -87,17 +96,22 @@ fn test_init_and_delete_module() { let mut contents: Vec = Vec::new(); f.read_to_end(&mut contents) .expect("unable to read kernel module content to buffer"); - init_module(&contents, &CString::new("").unwrap()).expect("unable to load kernel module"); + init_module(&contents, &CString::new("").unwrap()) + .expect("unable to load kernel module"); delete_module( &CString::new(kmod_name).unwrap(), DeleteModuleFlags::empty(), - ).expect("unable to unload kernel module"); + ) + .expect("unable to unload kernel module"); } #[test] fn test_init_and_delete_module_with_params() { - require_capability!("test_init_and_delete_module_with_params", CAP_SYS_MODULE); + require_capability!( + "test_init_and_delete_module_with_params", + CAP_SYS_MODULE + ); let _m0 = crate::KMOD_MTX.lock(); let _m1 = crate::CWD_LOCK.read(); @@ -113,7 +127,8 @@ fn test_init_and_delete_module_with_params() { delete_module( &CString::new(kmod_name).unwrap(), DeleteModuleFlags::empty(), - ).expect("unable to unload kernel module"); + ) + .expect("unable to unload kernel module"); } #[test] @@ -125,14 +140,18 @@ fn test_finit_module_invalid() { let kmod_path = "/dev/zero"; let f = File::open(kmod_path).expect("unable to open kernel module"); - let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); + let result = + finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); assert_eq!(result.unwrap_err(), Errno::EINVAL); } #[test] fn test_finit_module_twice_and_delete_module() { - require_capability!("test_finit_module_twice_and_delete_module", CAP_SYS_MODULE); + require_capability!( + "test_finit_module_twice_and_delete_module", + CAP_SYS_MODULE + ); let _m0 = crate::KMOD_MTX.lock(); let _m1 = crate::CWD_LOCK.read(); @@ -142,14 +161,16 @@ fn test_finit_module_twice_and_delete_module() { finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()) .expect("unable to load kernel module"); - let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); + let result = + finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()); assert_eq!(result.unwrap_err(), Errno::EEXIST); delete_module( &CString::new(kmod_name).unwrap(), DeleteModuleFlags::empty(), - ).expect("unable to unload kernel module"); + ) + .expect("unable to unload kernel module"); } #[test] @@ -158,7 +179,10 @@ fn test_delete_module_not_loaded() { let _m0 = crate::KMOD_MTX.lock(); let _m1 = crate::CWD_LOCK.read(); - let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty()); + let result = delete_module( + &CString::new("hello").unwrap(), + DeleteModuleFlags::empty(), + ); assert_eq!(result.unwrap_err(), Errno::ENOENT); } diff --git a/test/test_mount.rs b/test/test_mount.rs index 1ddfcfe932..febcadfbca 100644 --- a/test/test_mount.rs +++ b/test/test_mount.rs @@ -27,16 +27,18 @@ exit 23"; const EXPECTED_STATUS: i32 = 23; const NONE: Option<&'static [u8]> = None; - #[allow(clippy::bind_instead_of_map)] // False positive + #[allow(clippy::bind_instead_of_map)] // False positive pub fn test_mount_tmpfs_without_flags_allows_rwx() { let tempdir = tempfile::tempdir().unwrap(); - mount(NONE, - tempdir.path(), - Some(b"tmpfs".as_ref()), - MsFlags::empty(), - NONE) - .unwrap_or_else(|e| panic!("mount failed: {}", e)); + mount( + NONE, + tempdir.path(), + Some(b"tmpfs".as_ref()), + MsFlags::empty(), + NONE, + ) + .unwrap_or_else(|e| panic!("mount failed: {}", e)); let test_path = tempdir.path().join("test"); @@ -46,8 +48,10 @@ exit 23"; .write(true) .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) .open(&test_path) - .or_else(|e| - if Errno::from_i32(e.raw_os_error().unwrap()) == Errno::EOVERFLOW { + .or_else(|e| { + if Errno::from_i32(e.raw_os_error().unwrap()) + == Errno::EOVERFLOW + { // Skip tests on certain Linux kernels which have a bug // regarding tmpfs in namespaces. // Ubuntu 14.04 and 16.04 are known to be affected; 16.10 is @@ -56,13 +60,16 @@ exit 23"; // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1659087 let stderr = io::stderr(); let mut handle = stderr.lock(); - writeln!(handle, "Buggy Linux kernel detected. Skipping test.") + writeln!( + handle, + "Buggy Linux kernel detected. Skipping test." + ) .unwrap(); process::exit(0); - } else { - panic!("open failed: {}", e); - } - ) + } else { + panic!("open failed: {}", e); + } + }) .and_then(|mut f| f.write(SCRIPT_CONTENTS)) .unwrap_or_else(|e| panic!("write failed: {}", e)); @@ -74,42 +81,55 @@ exit 23"; assert_eq!(buf, SCRIPT_CONTENTS); // Verify execute. - assert_eq!(EXPECTED_STATUS, - Command::new(&test_path) - .status() - .unwrap_or_else(|e| panic!("exec failed: {}", e)) - .code() - .unwrap_or_else(|| panic!("child killed by signal"))); - - umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e)); + assert_eq!( + EXPECTED_STATUS, + Command::new(&test_path) + .status() + .unwrap_or_else(|e| panic!("exec failed: {}", e)) + .code() + .unwrap_or_else(|| panic!("child killed by signal")) + ); + + umount(tempdir.path()) + .unwrap_or_else(|e| panic!("umount failed: {}", e)); } pub fn test_mount_rdonly_disallows_write() { let tempdir = tempfile::tempdir().unwrap(); - mount(NONE, - tempdir.path(), - Some(b"tmpfs".as_ref()), - MsFlags::MS_RDONLY, - NONE) - .unwrap_or_else(|e| panic!("mount failed: {}", e)); + mount( + NONE, + tempdir.path(), + Some(b"tmpfs".as_ref()), + MsFlags::MS_RDONLY, + NONE, + ) + .unwrap_or_else(|e| panic!("mount failed: {}", e)); // EROFS: Read-only file system - assert_eq!(EROFS as i32, - File::create(tempdir.path().join("test")).unwrap_err().raw_os_error().unwrap()); - - umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e)); + assert_eq!( + EROFS as i32, + File::create(tempdir.path().join("test")) + .unwrap_err() + .raw_os_error() + .unwrap() + ); + + umount(tempdir.path()) + .unwrap_or_else(|e| panic!("umount failed: {}", e)); } pub fn test_mount_noexec_disallows_exec() { let tempdir = tempfile::tempdir().unwrap(); - mount(NONE, - tempdir.path(), - Some(b"tmpfs".as_ref()), - MsFlags::MS_NOEXEC, - NONE) - .unwrap_or_else(|e| panic!("mount failed: {}", e)); + mount( + NONE, + tempdir.path(), + Some(b"tmpfs".as_ref()), + MsFlags::MS_NOEXEC, + NONE, + ) + .unwrap_or_else(|e| panic!("mount failed: {}", e)); let test_path = tempdir.path().join("test"); @@ -122,21 +142,30 @@ exit 23"; .unwrap_or_else(|e| panic!("write failed: {}", e)); // Verify that we cannot execute despite a+x permissions being set. - let mode = stat::Mode::from_bits_truncate(fs::metadata(&test_path) - .map(|md| md.permissions().mode()) - .unwrap_or_else(|e| { - panic!("metadata failed: {}", e) - })); - - assert!(mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH), - "{:?} did not have execute permissions", - &test_path); + let mode = stat::Mode::from_bits_truncate( + fs::metadata(&test_path) + .map(|md| md.permissions().mode()) + .unwrap_or_else(|e| panic!("metadata failed: {}", e)), + ); + + assert!( + mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH), + "{:?} did not have execute permissions", + &test_path + ); // EACCES: Permission denied - assert_eq!(EACCES as i32, - Command::new(&test_path).status().unwrap_err().raw_os_error().unwrap()); - - umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e)); + assert_eq!( + EACCES as i32, + Command::new(&test_path) + .status() + .unwrap_err() + .raw_os_error() + .unwrap() + ); + + umount(tempdir.path()) + .unwrap_or_else(|e| panic!("umount failed: {}", e)); } pub fn test_mount_bind() { @@ -146,12 +175,14 @@ exit 23"; { let mount_point = tempfile::tempdir().unwrap(); - mount(Some(tempdir.path()), - mount_point.path(), - NONE, - MsFlags::MS_BIND, - NONE) - .unwrap_or_else(|e| panic!("mount failed: {}", e)); + mount( + Some(tempdir.path()), + mount_point.path(), + NONE, + MsFlags::MS_BIND, + NONE, + ) + .unwrap_or_else(|e| panic!("mount failed: {}", e)); fs::OpenOptions::new() .create(true) @@ -161,7 +192,8 @@ exit 23"; .and_then(|mut f| f.write(SCRIPT_CONTENTS)) .unwrap_or_else(|e| panic!("write failed: {}", e)); - umount(mount_point.path()).unwrap_or_else(|e| panic!("umount failed: {}", e)); + umount(mount_point.path()) + .unwrap_or_else(|e| panic!("umount failed: {}", e)); } // Verify the file written in the mount shows up in source directory, even @@ -199,7 +231,6 @@ exit 23"; } } - // Test runner /// Mimic normal test output (hackishly). @@ -220,16 +251,20 @@ macro_rules! run_tests { #[cfg(target_os = "linux")] fn main() { - use test_mount::{setup_namespaces, test_mount_tmpfs_without_flags_allows_rwx, - test_mount_rdonly_disallows_write, test_mount_noexec_disallows_exec, - test_mount_bind}; + use test_mount::{ + setup_namespaces, test_mount_bind, test_mount_noexec_disallows_exec, + test_mount_rdonly_disallows_write, + test_mount_tmpfs_without_flags_allows_rwx, + }; skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1351"); setup_namespaces(); - run_tests!(test_mount_tmpfs_without_flags_allows_rwx, - test_mount_rdonly_disallows_write, - test_mount_noexec_disallows_exec, - test_mount_bind); + run_tests!( + test_mount_tmpfs_without_flags_allows_rwx, + test_mount_rdonly_disallows_write, + test_mount_noexec_disallows_exec, + test_mount_bind + ); } #[cfg(not(target_os = "linux"))] diff --git a/test/test_mq.rs b/test/test_mq.rs index 8aff840ddc..7b48e7ac78 100644 --- a/test/test_mq.rs +++ b/test/test_mq.rs @@ -3,8 +3,8 @@ use std::ffi::CString; use std::str; use nix::errno::Errno; -use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive, mq_attr_member_t}; -use nix::mqueue::{MqAttr, MQ_OFlag}; +use nix::mqueue::{mq_attr_member_t, mq_close, mq_open, mq_receive, mq_send}; +use nix::mqueue::{MQ_OFlag, MqAttr}; use nix::sys::stat::Mode; // Defined as a macro such that the error source is reported as the caller's location. @@ -29,8 +29,8 @@ macro_rules! assert_attr_eq { #[test] fn test_mq_send_and_receive() { const MSG_SIZE: mq_attr_member_t = 32; - let attr = MqAttr::new(0, 10, MSG_SIZE, 0); - let mq_name= &CString::new(b"/a_nix_test_queue".as_ref()).unwrap(); + let attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let mq_name = &CString::new(b"/a_nix_test_queue".as_ref()).unwrap(); let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; @@ -55,12 +55,11 @@ fn test_mq_send_and_receive() { assert_eq!(msg_to_send, str::from_utf8(&buf[0..len]).unwrap()); } - #[test] fn test_mq_getattr() { use nix::mqueue::mq_getattr; const MSG_SIZE: mq_attr_member_t = 32; - let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; @@ -78,15 +77,14 @@ fn test_mq_getattr() { // FIXME: Fix failures for mips in QEMU #[test] -#[cfg_attr(all( - qemu, - 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; - let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; @@ -109,7 +107,12 @@ fn test_mq_setattr() { assert_ne!(new_attr_get, new_attr); } - let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t, 10, MSG_SIZE, 0); + let new_attr_non_blocking = MqAttr::new( + MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t, + 10, + MSG_SIZE, + 0, + ); mq_setattr(&mqd, &new_attr_non_blocking).unwrap(); let new_attr_get = mq_getattr(&mqd).unwrap(); @@ -124,15 +127,14 @@ fn test_mq_setattr() { // FIXME: Fix failures for mips in QEMU #[test] -#[cfg_attr(all( - qemu, - 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}; + use nix::mqueue::{mq_getattr, mq_remove_nonblock, mq_set_nonblock}; const MSG_SIZE: mq_attr_member_t = 32; - let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; @@ -156,10 +158,11 @@ fn test_mq_set_nonblocking() { fn test_mq_unlink() { use nix::mqueue::mq_unlink; const MSG_SIZE: mq_attr_member_t = 32; - let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] - let mq_name_not_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); + let mq_name_not_opened = + &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; let r = mq_open(mq_name_opened, oflag, mode, Some(&initial_attr)); @@ -170,7 +173,7 @@ fn test_mq_unlink() { let mqd = r.unwrap(); let res_unlink = mq_unlink(mq_name_opened); - assert_eq!(res_unlink, Ok(()) ); + assert_eq!(res_unlink, Ok(())); // NetBSD (and others which inherit its implementation) defer removing the message // queue name until all references are closed, whereas Linux and others remove the @@ -178,10 +181,10 @@ fn test_mq_unlink() { #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] { let res_unlink_not_opened = mq_unlink(mq_name_not_opened); - assert_eq!(res_unlink_not_opened, Err(Errno::ENOENT) ); + assert_eq!(res_unlink_not_opened, Err(Errno::ENOENT)); } mq_close(mqd).unwrap(); let res_unlink_after_close = mq_unlink(mq_name_opened); - assert_eq!(res_unlink_after_close, Err(Errno::ENOENT) ); + assert_eq!(res_unlink_after_close, Err(Errno::ENOENT)); } diff --git a/test/test_net.rs b/test/test_net.rs index 78a09b6c63..d1050c16d7 100644 --- a/test/test_net.rs +++ b/test/test_net.rs @@ -3,7 +3,11 @@ use nix::net::if_::*; #[cfg(any(target_os = "android", target_os = "linux"))] const LOOPBACK: &[u8] = b"lo"; -#[cfg(not(any(target_os = "android", target_os = "linux", target_os = "haiku")))] +#[cfg(not(any( + target_os = "android", + target_os = "linux", + target_os = "haiku" +)))] const LOOPBACK: &[u8] = b"lo0"; #[cfg(target_os = "haiku")] diff --git a/test/test_nix_path.rs b/test/test_nix_path.rs index e69de29bb2..8b13789179 100644 --- a/test/test_nix_path.rs +++ b/test/test_nix_path.rs @@ -0,0 +1 @@ + diff --git a/test/test_nmount.rs b/test/test_nmount.rs index 4c74ecf627..dec806a55f 100644 --- a/test/test_nmount.rs +++ b/test/test_nmount.rs @@ -1,13 +1,9 @@ use crate::*; use nix::{ errno::Errno, - mount::{MntFlags, Nmount, unmount} -}; -use std::{ - ffi::CString, - fs::File, - path::Path + mount::{unmount, MntFlags, Nmount}, }; +use std::{ffi::CString, fs::File, path::Path}; use tempfile::tempdir; #[test] @@ -24,14 +20,15 @@ fn ok() { .str_opt(&fstype, &nullfs) .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) .str_opt_owned("target", target.path().to_str().unwrap()) - .nmount(MntFlags::empty()).unwrap(); - + .nmount(MntFlags::empty()) + .unwrap(); + // Now check that the sentry is visible through the mountpoint let exists = Path::exists(&mountpoint.path().join("sentry")); // Cleanup the mountpoint before asserting unmount(mountpoint.path(), MntFlags::empty()).unwrap(); - + assert!(exists); } @@ -44,8 +41,9 @@ fn bad_fstype() { let e = Nmount::new() .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) .str_opt_owned("target", target.path().to_str().unwrap()) - .nmount(MntFlags::empty()).unwrap_err(); - + .nmount(MntFlags::empty()) + .unwrap_err(); + assert_eq!(e.error(), Errno::EINVAL); assert_eq!(e.errmsg(), Some("Invalid fstype")); } diff --git a/test/test_poll.rs b/test/test_poll.rs index 120e8e56f5..53964e26bb 100644 --- a/test/test_poll.rs +++ b/test/test_poll.rs @@ -1,7 +1,7 @@ use nix::{ errno::Errno, - poll::{PollFlags, poll, PollFd}, - unistd::{write, pipe} + poll::{poll, PollFd, PollFlags}, + unistd::{pipe, write}, }; macro_rules! loop_while_eintr { @@ -10,10 +10,10 @@ macro_rules! loop_while_eintr { match $poll_expr { Ok(nfds) => break nfds, Err(Errno::EINTR) => (), - Err(e) => panic!("{}", e) + Err(e) => panic!("{}", e), } } - } + }; } #[test] @@ -37,10 +37,12 @@ fn test_poll() { // ppoll(2) is the same as poll except for how it handles timeouts and signals. // Repeating the test for poll(2) should be sufficient to check that our // bindings are correct. -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux" +))] #[test] fn test_ppoll() { use nix::poll::ppoll; diff --git a/test/test_pty.rs b/test/test_pty.rs index 1a7cab81a0..3b52289e5c 100644 --- a/test/test_pty.rs +++ b/test/test_pty.rs @@ -1,15 +1,15 @@ use std::fs::File; use std::io::{Read, Write}; -use std::path::Path; use std::os::unix::prelude::*; +use std::path::Path; use tempfile::tempfile; use libc::{_exit, STDOUT_FILENO}; -use nix::fcntl::{OFlag, open}; +use nix::fcntl::{open, OFlag}; use nix::pty::*; use nix::sys::stat; use nix::sys::termios::*; -use nix::unistd::{write, close, pause}; +use nix::unistd::{close, pause, write}; /// Regression test for Issue #659 /// This is the correct way to explicitly close a `PtyMaster` @@ -36,7 +36,7 @@ fn test_ptsname_equivalence() { assert!(master_fd.as_raw_fd() > 0); // Get the name of the slave - let slave_name = unsafe { ptsname(&master_fd) }.unwrap() ; + let slave_name = unsafe { ptsname(&master_fd) }.unwrap(); let slave_name_r = ptsname_r(&master_fd).unwrap(); assert_eq!(slave_name, slave_name_r); } @@ -111,7 +111,9 @@ fn open_ptty_pair() -> (PtyMaster, File) { let slave_name = unsafe { ptsname(&master) }.expect("ptsname failed"); // Open the slave device - let slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()).unwrap(); + let slave_fd = + open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()) + .unwrap(); #[cfg(target_os = "illumos")] // TODO: rewrite using ioctl! @@ -279,9 +281,9 @@ fn test_openpty_with_termios() { #[test] fn test_forkpty() { - use nix::unistd::ForkResult::*; use nix::sys::signal::*; use nix::sys::wait::wait; + use nix::unistd::ForkResult::*; // forkpty calls openpty which uses ptname(3) internally. let _m0 = crate::PTSNAME_MTX.lock(); // forkpty spawns a child process @@ -289,15 +291,15 @@ fn test_forkpty() { let string = "naninani\n"; let echoed_string = "naninani\r\n"; - let pty = unsafe { - forkpty(None, None).unwrap() - }; + let pty = unsafe { forkpty(None, None).unwrap() }; match pty.fork_result { Child => { write(STDOUT_FILENO, string.as_bytes()).unwrap(); - pause(); // we need the child to stay alive until the parent calls read - unsafe { _exit(0); } - }, + pause(); // we need the child to stay alive until the parent calls read + unsafe { + _exit(0); + } + } Parent { child } => { let mut buf = [0u8; 10]; assert!(child.as_raw() > 0); @@ -306,6 +308,6 @@ fn test_forkpty() { wait().unwrap(); // keep other tests using generic wait from getting our child assert_eq!(&buf, echoed_string.as_bytes()); close(pty.master).unwrap(); - }, + } } } diff --git a/test/test_ptymaster_drop.rs b/test/test_ptymaster_drop.rs index a68f81ee1e..ffbaa56977 100644 --- a/test/test_ptymaster_drop.rs +++ b/test/test_ptymaster_drop.rs @@ -15,6 +15,6 @@ mod t { fn test_double_close() { let m = posix_openpt(OFlag::O_RDWR).unwrap(); close(m.as_raw_fd()).unwrap(); - drop(m); // should panic here + drop(m); // should panic here } } diff --git a/test/test_resource.rs b/test/test_resource.rs index f96bf90341..2ab581ba29 100644 --- a/test/test_resource.rs +++ b/test/test_resource.rs @@ -1,4 +1,9 @@ -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos", target_os = "haiku")))] +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "illumos", + target_os = "haiku" +)))] use nix::sys::resource::{getrlimit, setrlimit, Resource}; /// Tests the RLIMIT_NOFILE functionality of getrlimit(), where the resource RLIMIT_NOFILE refers @@ -10,9 +15,15 @@ use nix::sys::resource::{getrlimit, setrlimit, Resource}; /// to put the new soft limit in effect, and then getrlimit() once more to ensure the limits have /// been updated. #[test] -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos", target_os = "haiku")))] +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "illumos", + target_os = "haiku" +)))] pub fn test_resource_limits_nofile() { - let (mut soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); + let (mut soft_limit, hard_limit) = + getrlimit(Resource::RLIMIT_NOFILE).unwrap(); soft_limit -= 1; assert_ne!(soft_limit, hard_limit); diff --git a/test/test_sched.rs b/test/test_sched.rs index 922196a3db..ebf346db16 100644 --- a/test/test_sched.rs +++ b/test/test_sched.rs @@ -24,7 +24,10 @@ fn test_sched_affinity() { let updated_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap(); for field in 0..CpuSet::count() { // Should be set only for the CPU we set previously - assert_eq!(updated_affinity.is_set(field).unwrap(), field==last_valid_cpu) + assert_eq!( + updated_affinity.is_set(field).unwrap(), + field == last_valid_cpu + ) } // Finally, reset the initial CPU set diff --git a/test/test_sendfile.rs b/test/test_sendfile.rs index e56ff12faf..f73a3b56c3 100644 --- a/test/test_sendfile.rs +++ b/test/test_sendfile.rs @@ -62,7 +62,8 @@ fn test_sendfile64_linux() { #[test] fn test_sendfile_freebsd() { // Declare the content - let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; + let header_strings = + vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; let body = "Xabcdef123456"; let body_offset = 1; let trailer_strings = vec!["\n", "Served by Make Believe\n"]; @@ -72,8 +73,10 @@ fn test_sendfile_freebsd() { tmp.write_all(body.as_bytes()).unwrap(); // Prepare headers and trailers for sendfile - let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect(); - let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect(); + let headers: Vec<&[u8]> = + header_strings.iter().map(|s| s.as_bytes()).collect(); + let trailers: Vec<&[u8]> = + trailer_strings.iter().map(|s| s.as_bytes()).collect(); // Prepare socket pair let (mut rd, wr) = UnixStream::pair().unwrap(); @@ -93,8 +96,9 @@ fn test_sendfile_freebsd() { wr.shutdown(Shutdown::Both).unwrap(); // Prepare the expected result - let expected_string = - header_strings.concat() + &body[body_offset..] + &trailer_strings.concat(); + let expected_string = header_strings.concat() + + &body[body_offset..] + + &trailer_strings.concat(); // Verify the message that was sent assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); @@ -109,7 +113,8 @@ fn test_sendfile_freebsd() { #[test] fn test_sendfile_dragonfly() { // Declare the content - let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; + let header_strings = + vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; let body = "Xabcdef123456"; let body_offset = 1; let trailer_strings = vec!["\n", "Served by Make Believe\n"]; @@ -119,8 +124,10 @@ fn test_sendfile_dragonfly() { tmp.write_all(body.as_bytes()).unwrap(); // Prepare headers and trailers for sendfile - let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect(); - let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect(); + let headers: Vec<&[u8]> = + header_strings.iter().map(|s| s.as_bytes()).collect(); + let trailers: Vec<&[u8]> = + trailer_strings.iter().map(|s| s.as_bytes()).collect(); // Prepare socket pair let (mut rd, wr) = UnixStream::pair().unwrap(); @@ -138,8 +145,9 @@ fn test_sendfile_dragonfly() { wr.shutdown(Shutdown::Both).unwrap(); // Prepare the expected result - let expected_string = - header_strings.concat() + &body[body_offset..] + &trailer_strings.concat(); + let expected_string = header_strings.concat() + + &body[body_offset..] + + &trailer_strings.concat(); // Verify the message that was sent assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); @@ -154,7 +162,8 @@ fn test_sendfile_dragonfly() { #[test] fn test_sendfile_darwin() { // Declare the content - let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; + let header_strings = + vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; let body = "Xabcdef123456"; let body_offset = 1; let trailer_strings = vec!["\n", "Served by Make Believe\n"]; @@ -164,8 +173,10 @@ fn test_sendfile_darwin() { tmp.write_all(body.as_bytes()).unwrap(); // Prepare headers and trailers for sendfile - let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect(); - let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect(); + let headers: Vec<&[u8]> = + header_strings.iter().map(|s| s.as_bytes()).collect(); + let trailers: Vec<&[u8]> = + trailer_strings.iter().map(|s| s.as_bytes()).collect(); // Prepare socket pair let (mut rd, wr) = UnixStream::pair().unwrap(); @@ -183,8 +194,9 @@ fn test_sendfile_darwin() { wr.shutdown(Shutdown::Both).unwrap(); // Prepare the expected result - let expected_string = - header_strings.concat() + &body[body_offset..] + &trailer_strings.concat(); + let expected_string = header_strings.concat() + + &body[body_offset..] + + &trailer_strings.concat(); // Verify the message that was sent assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); diff --git a/test/test_stat.rs b/test/test_stat.rs index 3a09eca54d..de5a964ec7 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -2,43 +2,45 @@ use std::fs; use std::fs::File; #[cfg(not(target_os = "redox"))] -use std::os::unix::fs::{symlink}; +use std::os::unix::fs::symlink; #[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use std::os::unix::fs::{PermissionsExt}; +use std::os::unix::fs::PermissionsExt; use std::os::unix::prelude::AsRawFd; -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use std::time::{Duration, UNIX_EPOCH}; #[cfg(not(target_os = "redox"))] use std::path::Path; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use std::time::{Duration, UNIX_EPOCH}; -#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] -use libc::{S_IFMT, S_IFLNK}; use libc::mode_t; +#[cfg(not(any(target_os = "netbsd", target_os = "redox")))] +use libc::{S_IFLNK, S_IFMT}; +#[cfg(not(target_os = "redox"))] +use nix::errno::Errno; #[cfg(not(target_os = "redox"))] use nix::fcntl; +#[cfg(any( + target_os = "linux", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd" +))] +use nix::sys::stat::lutimes; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use nix::sys::stat::utimensat; #[cfg(not(target_os = "redox"))] -use nix::errno::Errno; +use nix::sys::stat::FchmodatFlags; +use nix::sys::stat::Mode; +#[cfg(not(any(target_os = "redox", target_os = "haiku")))] +use nix::sys::stat::UtimensatFlags; #[cfg(not(target_os = "redox"))] use nix::sys::stat::{self}; -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use nix::sys::stat::{futimens, utimes}; use nix::sys::stat::{fchmod, stat}; #[cfg(not(target_os = "redox"))] use nix::sys::stat::{fchmodat, mkdirat}; #[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use nix::sys::stat::{utimensat}; -#[cfg(any(target_os = "linux", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd"))] -use nix::sys::stat::lutimes; -#[cfg(not(target_os = "redox"))] -use nix::sys::stat::{FchmodatFlags}; -#[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use nix::sys::stat::{UtimensatFlags}; -use nix::sys::stat::Mode; +use nix::sys::stat::{futimens, utimes}; #[cfg(not(any(target_os = "netbsd", target_os = "redox")))] use nix::sys::stat::FileStat; @@ -54,32 +56,35 @@ use nix::Result; #[cfg(not(any(target_os = "netbsd", target_os = "redox")))] fn assert_stat_results(stat_result: Result) { let stats = stat_result.expect("stat call failed"); - assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent - assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent - assert!(stats.st_mode > 0); // must be positive integer - assert_eq!(stats.st_nlink, 1); // there links created, must be 1 - assert_eq!(stats.st_size, 0); // size is 0 because we did not write anything to the file - assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent - assert!(stats.st_blocks <= 16); // Up to 16 blocks can be allocated for a blank file + assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent + assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent + assert!(stats.st_mode > 0); // must be positive integer + assert_eq!(stats.st_nlink, 1); // there links created, must be 1 + assert_eq!(stats.st_size, 0); // size is 0 because we did not write anything to the file + assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent + assert!(stats.st_blocks <= 16); // Up to 16 blocks can be allocated for a blank file } #[cfg(not(any(target_os = "netbsd", target_os = "redox")))] // (Android's st_blocks is ulonglong which is always non-negative.) #[cfg_attr(target_os = "android", allow(unused_comparisons))] -#[allow(clippy::absurd_extreme_comparisons)] // Not absurd on all OSes +#[allow(clippy::absurd_extreme_comparisons)] // Not absurd on all OSes fn assert_lstat_results(stat_result: Result) { let stats = stat_result.expect("stat call failed"); - assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent - assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent - assert!(stats.st_mode > 0); // must be positive integer + assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent + assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent + assert!(stats.st_mode > 0); // must be positive integer // st_mode is c_uint (u32 on Android) while S_IFMT is mode_t // (u16 on Android), and that will be a compile error. // On other platforms they are the same (either both are u16 or u32). - assert_eq!((stats.st_mode as usize) & (S_IFMT as usize), S_IFLNK as usize); // should be a link - assert_eq!(stats.st_nlink, 1); // there links created, must be 1 - assert!(stats.st_size > 0); // size is > 0 because it points to another file - assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent + assert_eq!( + (stats.st_mode as usize) & (S_IFMT as usize), + S_IFLNK as usize + ); // should be a link + assert_eq!(stats.st_nlink, 1); // there links created, must be 1 + assert!(stats.st_size > 0); // size is > 0 because it points to another file + assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent // st_blocks depends on whether the machine's file system uses fast // or slow symlinks, so just make sure it's not negative @@ -108,13 +113,11 @@ fn test_fstatat() { let tempdir = tempfile::tempdir().unwrap(); let filename = tempdir.path().join("foo.txt"); File::create(&filename).unwrap(); - let dirfd = fcntl::open(tempdir.path(), - fcntl::OFlag::empty(), - stat::Mode::empty()); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()); - let result = stat::fstatat(dirfd.unwrap(), - &filename, - fcntl::AtFlags::empty()); + let result = + stat::fstatat(dirfd.unwrap(), &filename, fcntl::AtFlags::empty()); assert_stat_results(result); } @@ -174,12 +177,15 @@ fn test_fchmodat() { let fullpath = tempdir.path().join(filename); File::create(&fullpath).unwrap(); - let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); let mut mode1 = Mode::empty(); mode1.insert(Mode::S_IRUSR); mode1.insert(Mode::S_IWUSR); - fchmodat(Some(dirfd), filename, mode1, FchmodatFlags::FollowSymlink).unwrap(); + fchmodat(Some(dirfd), filename, mode1, FchmodatFlags::FollowSymlink) + .unwrap(); let file_stat1 = stat(&fullpath).unwrap(); assert_eq!(file_stat1.st_mode as mode_t & 0o7777, mode1.bits()); @@ -199,13 +205,19 @@ fn test_fchmodat() { /// The atime and mtime are expressed with a resolution of seconds because some file systems /// (like macOS's HFS+) do not have higher granularity. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] -fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata) { +fn assert_times_eq( + exp_atime_sec: u64, + exp_mtime_sec: u64, + attr: &fs::Metadata, +) { assert_eq!( Duration::new(exp_atime_sec, 0), - attr.accessed().unwrap().duration_since(UNIX_EPOCH).unwrap()); + attr.accessed().unwrap().duration_since(UNIX_EPOCH).unwrap() + ); assert_eq!( Duration::new(exp_mtime_sec, 0), - attr.modified().unwrap().duration_since(UNIX_EPOCH).unwrap()); + attr.modified().unwrap().duration_since(UNIX_EPOCH).unwrap() + ); } #[test] @@ -215,16 +227,19 @@ fn test_utimes() { let fullpath = tempdir.path().join("file"); drop(File::create(&fullpath).unwrap()); - utimes(&fullpath, &TimeVal::seconds(9990), &TimeVal::seconds(5550)).unwrap(); + utimes(&fullpath, &TimeVal::seconds(9990), &TimeVal::seconds(5550)) + .unwrap(); assert_times_eq(9990, 5550, &fs::metadata(&fullpath).unwrap()); } #[test] -#[cfg(any(target_os = "linux", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd"))] +#[cfg(any( + target_os = "linux", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd" +))] fn test_lutimes() { let tempdir = tempfile::tempdir().unwrap(); let target = tempdir.path().join("target"); @@ -233,14 +248,21 @@ fn test_lutimes() { symlink(&target, &fullpath).unwrap(); let exp_target_metadata = fs::symlink_metadata(&target).unwrap(); - lutimes(&fullpath, &TimeVal::seconds(4560), &TimeVal::seconds(1230)).unwrap(); + lutimes(&fullpath, &TimeVal::seconds(4560), &TimeVal::seconds(1230)) + .unwrap(); assert_times_eq(4560, 1230, &fs::symlink_metadata(&fullpath).unwrap()); let target_metadata = fs::symlink_metadata(&target).unwrap(); - assert_eq!(exp_target_metadata.accessed().unwrap(), target_metadata.accessed().unwrap(), - "atime of symlink target was unexpectedly modified"); - assert_eq!(exp_target_metadata.modified().unwrap(), target_metadata.modified().unwrap(), - "mtime of symlink target was unexpectedly modified"); + assert_eq!( + exp_target_metadata.accessed().unwrap(), + target_metadata.accessed().unwrap(), + "atime of symlink target was unexpectedly modified" + ); + assert_eq!( + exp_target_metadata.modified().unwrap(), + target_metadata.modified().unwrap(), + "mtime of symlink target was unexpectedly modified" + ); } #[test] @@ -250,7 +272,8 @@ fn test_futimens() { let fullpath = tempdir.path().join("file"); drop(File::create(&fullpath).unwrap()); - let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); futimens(fd, &TimeSpec::seconds(10), &TimeSpec::seconds(20)).unwrap(); assert_times_eq(10, 20, &fs::metadata(&fullpath).unwrap()); @@ -265,16 +288,30 @@ fn test_utimensat() { let fullpath = tempdir.path().join(filename); drop(File::create(&fullpath).unwrap()); - let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); - utimensat(Some(dirfd), filename, &TimeSpec::seconds(12345), &TimeSpec::seconds(678), - UtimensatFlags::FollowSymlink).unwrap(); + utimensat( + Some(dirfd), + filename, + &TimeSpec::seconds(12345), + &TimeSpec::seconds(678), + UtimensatFlags::FollowSymlink, + ) + .unwrap(); assert_times_eq(12345, 678, &fs::metadata(&fullpath).unwrap()); chdir(tempdir.path()).unwrap(); - utimensat(None, filename, &TimeSpec::seconds(500), &TimeSpec::seconds(800), - UtimensatFlags::FollowSymlink).unwrap(); + utimensat( + None, + filename, + &TimeSpec::seconds(500), + &TimeSpec::seconds(800), + UtimensatFlags::FollowSymlink, + ) + .unwrap(); assert_times_eq(500, 800, &fs::metadata(&fullpath).unwrap()); } @@ -283,7 +320,9 @@ fn test_utimensat() { fn test_mkdirat_success_path() { let tempdir = tempfile::tempdir().unwrap(); let filename = "example_subdir"; - let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok()); assert!(Path::exists(&tempdir.path().join(filename))); } @@ -291,12 +330,17 @@ fn test_mkdirat_success_path() { #[test] #[cfg(not(any(target_os = "redox", target_os = "haiku")))] fn test_mkdirat_success_mode() { - let expected_bits = stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits(); + let expected_bits = + stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits(); let tempdir = tempfile::tempdir().unwrap(); let filename = "example_subdir"; - let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok()); - let permissions = fs::metadata(tempdir.path().join(filename)).unwrap().permissions(); + let permissions = fs::metadata(tempdir.path().join(filename)) + .unwrap() + .permissions(); let mode = permissions.mode(); assert_eq!(mode as mode_t, expected_bits) } @@ -305,21 +349,27 @@ fn test_mkdirat_success_mode() { #[cfg(not(target_os = "redox"))] fn test_mkdirat_fail() { let tempdir = tempfile::tempdir().unwrap(); - let not_dir_filename= "example_not_dir"; + let not_dir_filename = "example_not_dir"; let filename = "example_subdir_dir"; - let dirfd = fcntl::open(&tempdir.path().join(not_dir_filename), fcntl::OFlag::O_CREAT, - stat::Mode::empty()).unwrap(); + let dirfd = fcntl::open( + &tempdir.path().join(not_dir_filename), + fcntl::OFlag::O_CREAT, + stat::Mode::empty(), + ) + .unwrap(); let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err(); assert_eq!(result, Errno::ENOTDIR); } #[test] -#[cfg(not(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "haiku", - target_os = "redox")))] +#[cfg(not(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "haiku", + target_os = "redox" +)))] fn test_mknod() { use stat::{lstat, mknod, SFlag}; @@ -333,13 +383,15 @@ fn test_mknod() { } #[test] -#[cfg(not(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "haiku", - target_os = "redox")))] +#[cfg(not(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "haiku", + target_os = "redox" +)))] fn test_mknodat() { use fcntl::{AtFlags, OFlag}; use nix::dir::Dir; @@ -347,7 +399,8 @@ fn test_mknodat() { let file_name = "test_file"; let tempdir = tempfile::tempdir().unwrap(); - let target_dir = Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap(); + let target_dir = + Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap(); mknodat( target_dir.as_raw_fd(), file_name, diff --git a/test/test_timer.rs b/test/test_timer.rs index d07d9633d0..ffd146867b 100644 --- a/test/test_timer.rs +++ b/test/test_timer.rs @@ -1,5 +1,6 @@ use nix::sys::signal::{ - sigaction, SaFlags, SigAction, SigEvent, SigHandler, SigSet, SigevNotify, Signal, + sigaction, SaFlags, SigAction, SigEvent, SigHandler, SigSet, SigevNotify, + Signal, }; use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; use nix::time::ClockId; @@ -32,9 +33,12 @@ fn alarm_fires() { // Create a handler for the test signal, `SIG`. The handler is responsible // for flipping `ALARM_CALLED`. let handler = SigHandler::Handler(handle_sigalarm); - let signal_action = SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); - let old_handler = - unsafe { sigaction(SIG, &signal_action).expect("unable to set signal handler for alarm") }; + let signal_action = + SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); + let old_handler = unsafe { + sigaction(SIG, &signal_action) + .expect("unable to set signal handler for alarm") + }; // Create the timer. We use the monotonic clock here, though any would do // really. The timer is set to fire every 250 milliseconds with no delay for @@ -44,7 +48,8 @@ fn alarm_fires() { signal: SIG, si_value: 0, }); - let mut timer = Timer::new(clockid, sigevent).expect("failed to create timer"); + let mut timer = + Timer::new(clockid, sigevent).expect("failed to create timer"); let expiration = Expiration::Interval(TIMER_PERIOD.into()); let flags = TimerSetTimeFlags::empty(); timer.set(expiration, flags).expect("could not set timer"); @@ -60,12 +65,10 @@ fn alarm_fires() { // represents a delay to the next expiration. We're only interested in the // timer still being extant. match timer.get() { - Ok(Some(exp)) => { - assert!(matches!( - exp, - Expiration::Interval(..) | Expiration::IntervalDelayed(..) - )) - } + Ok(Some(exp)) => assert!(matches!( + exp, + Expiration::Interval(..) | Expiration::IntervalDelayed(..) + )), _ => panic!("timer lost its expiration"), } diff --git a/test/test_unistd.rs b/test/test_unistd.rs index b3b69bbb0e..233928349e 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -1,17 +1,24 @@ -#[cfg(not(target_os = "redox"))] -use nix::fcntl::{self, open}; +use libc::{_exit, mode_t, off_t}; +use nix::errno::Errno; #[cfg(not(any(target_os = "redox", target_os = "haiku")))] -use nix::fcntl::{readlink}; +use nix::fcntl::readlink; use nix::fcntl::OFlag; -use nix::unistd::*; -use nix::unistd::ForkResult::*; #[cfg(not(target_os = "redox"))] -use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction}; -use nix::sys::wait::*; +use nix::fcntl::{self, open}; +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] +use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt}; +#[cfg(not(target_os = "redox"))] +use nix::sys::signal::{ + sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, +}; use nix::sys::stat::{self, Mode, SFlag}; -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] -use nix::pty::{posix_openpt, grantpt, unlockpt, ptsname}; -use nix::errno::Errno; +use nix::sys::wait::*; +use nix::unistd::ForkResult::*; +use nix::unistd::*; use std::env; #[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] use std::ffi::CString; @@ -20,10 +27,13 @@ use std::fs::DirBuilder; use std::fs::{self, File}; use std::io::Write; use std::os::unix::prelude::*; -#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "haiku")))] +#[cfg(not(any( + target_os = "fuchsia", + target_os = "redox", + target_os = "haiku" +)))] use std::path::Path; use tempfile::{tempdir, tempfile}; -use libc::{_exit, mode_t, off_t}; use crate::*; @@ -33,7 +43,7 @@ fn test_fork_and_waitpid() { let _m = crate::FORK_MTX.lock(); // Safe: Child only calls `_exit`, which is signal-safe - match unsafe{fork()}.expect("Error: Fork Failed") { + match unsafe { fork() }.expect("Error: Fork Failed") { Child => unsafe { _exit(0) }, Parent { child } => { // assert that child was created and pid > 0 @@ -42,16 +52,17 @@ fn test_fork_and_waitpid() { let wait_status = waitpid(child, None); match wait_status { // assert that waitpid returned correct status and the pid is the one of the child - Ok(WaitStatus::Exited(pid_t, _)) => assert_eq!(pid_t, child), + Ok(WaitStatus::Exited(pid_t, _)) => assert_eq!(pid_t, child), // panic, must never happen - s @ Ok(_) => panic!("Child exited {:?}, should never happen", s), + s @ Ok(_) => { + panic!("Child exited {:?}, should never happen", s) + } // panic, waitpid should never fail - Err(s) => panic!("Error: waitpid returned Err({:?}", s) + Err(s) => panic!("Error: waitpid returned Err({:?}", s), } - - }, + } } } @@ -61,14 +72,14 @@ fn test_wait() { let _m = crate::FORK_MTX.lock(); // Safe: Child only calls `_exit`, which is signal-safe - match unsafe{fork()}.expect("Error: Fork Failed") { + match unsafe { fork() }.expect("Error: Fork Failed") { Child => unsafe { _exit(0) }, Parent { child } => { let wait_status = wait(); // just assert that (any) one child returns with WaitStatus::Exited assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0))); - }, + } } } @@ -82,8 +93,8 @@ fn test_mkstemp() { Ok((fd, path)) => { close(fd).unwrap(); unlink(path.as_path()).unwrap(); - }, - Err(e) => panic!("mkstemp failed: {}", e) + } + Err(e) => panic!("mkstemp failed: {}", e), } } @@ -115,8 +126,12 @@ fn test_mkfifo_directory() { #[test] #[cfg(not(any( - target_os = "macos", target_os = "ios", - target_os = "android", target_os = "redox", target_os = "haiku")))] + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "redox", + target_os = "haiku" +)))] fn test_mkfifoat_none() { let _m = crate::CWD_LOCK.read(); @@ -132,8 +147,12 @@ fn test_mkfifoat_none() { #[test] #[cfg(not(any( - target_os = "macos", target_os = "ios", - target_os = "android", target_os = "redox", target_os = "haiku")))] + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "redox", + target_os = "haiku" +)))] fn test_mkfifoat() { use nix::fcntl; @@ -143,15 +162,20 @@ fn test_mkfifoat() { mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap(); - let stats = stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap(); + let stats = + stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap(); let typ = stat::SFlag::from_bits_truncate(stats.st_mode); assert_eq!(typ, SFlag::S_IFIFO); } #[test] #[cfg(not(any( - target_os = "macos", target_os = "ios", - target_os = "android", target_os = "redox", target_os = "haiku")))] + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "redox", + target_os = "haiku" +)))] fn test_mkfifoat_directory_none() { let _m = crate::CWD_LOCK.read(); @@ -161,8 +185,12 @@ fn test_mkfifoat_directory_none() { #[test] #[cfg(not(any( - target_os = "macos", target_os = "ios", - target_os = "android", target_os = "redox", target_os = "haiku")))] + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "redox", + target_os = "haiku" +)))] fn test_mkfifoat_directory() { // mkfifoat should fail if a directory is given let tempdir = tempdir().unwrap(); @@ -203,7 +231,13 @@ mod linux_android { #[test] // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] +#[cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] fn test_setgroups() { // Skip this test when not run as root as `setgroups()` requires root. skip_if_not_root!("test_setgroups"); @@ -226,12 +260,14 @@ fn test_setgroups() { #[test] // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms -#[cfg(not(any(target_os = "ios", - target_os = "macos", - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos")))] +#[cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos" +)))] fn test_initgroups() { // Skip this test when not run as root as `initgroups()` and `setgroups()` // require root. @@ -362,7 +398,7 @@ macro_rules! execve_test_factory( ) ); -cfg_if!{ +cfg_if! { if #[cfg(target_os = "android")] { execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap().as_c_str()); execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd()); @@ -387,7 +423,7 @@ cfg_if!{ #[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))] execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap()); -cfg_if!{ +cfg_if! { if #[cfg(target_os = "android")] { use nix::fcntl::AtFlags; execve_test_factory!(test_execveat_empty, execveat, @@ -501,7 +537,8 @@ fn test_fchownat() { let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); - fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); + fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink) + .unwrap(); chdir(tempdir.path()).unwrap(); fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap(); @@ -544,7 +581,7 @@ fn test_lseek64() { close(tmpfd).unwrap(); } -cfg_if!{ +cfg_if! { if #[cfg(any(target_os = "android", target_os = "linux"))] { macro_rules! require_acct{ () => { @@ -568,11 +605,15 @@ cfg_if!{ } #[test] -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] fn test_acct() { - use tempfile::NamedTempFile; use std::process::Command; use std::{thread, time}; + use tempfile::NamedTempFile; let _m = crate::FORK_MTX.lock(); require_acct!(); @@ -583,12 +624,11 @@ fn test_acct() { acct::enable(path).unwrap(); loop { - Command::new("echo") - .arg("Hello world") - .output() - .unwrap(); + Command::new("echo").arg("Hello world").output().unwrap(); let len = fs::metadata(path).unwrap().len(); - if len > 0 { break; } + if len > 0 { + break; + } thread::sleep(time::Duration::from_millis(10)); } acct::disable().unwrap(); @@ -599,21 +639,36 @@ fn test_fpathconf_limited() { let f = tempfile().unwrap(); // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test let path_max = fpathconf(f.as_raw_fd(), PathconfVar::PATH_MAX); - assert!(path_max.expect("fpathconf failed").expect("PATH_MAX is unlimited") > 0); + assert!( + path_max + .expect("fpathconf failed") + .expect("PATH_MAX is unlimited") + > 0 + ); } #[test] fn test_pathconf_limited() { // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test let path_max = pathconf("/", PathconfVar::PATH_MAX); - assert!(path_max.expect("pathconf failed").expect("PATH_MAX is unlimited") > 0); + assert!( + path_max + .expect("pathconf failed") + .expect("PATH_MAX is unlimited") + > 0 + ); } #[test] fn test_sysconf_limited() { // AFAIK, OPEN_MAX is limited on all platforms, so it makes a good test let open_max = sysconf(SysconfVar::OPEN_MAX); - assert!(open_max.expect("sysconf failed").expect("OPEN_MAX is unlimited") > 0); + assert!( + open_max + .expect("sysconf failed") + .expect("OPEN_MAX is unlimited") + > 0 + ); } #[cfg(target_os = "freebsd")] @@ -626,12 +681,13 @@ fn test_sysconf_unsupported() { assert!(open_max.expect("sysconf failed").is_none()) } - -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] #[test] fn test_getresuid() { let resuids = getresuid().unwrap(); @@ -640,11 +696,13 @@ fn test_getresuid() { assert!(resuids.saved.as_raw() != libc::uid_t::max_value()); } -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] #[test] fn test_getresgid() { let resgids = getresgid().unwrap(); @@ -658,25 +716,31 @@ fn test_getresgid() { #[test] fn test_pipe() { let (fd0, fd1) = pipe().unwrap(); - let m0 = stat::SFlag::from_bits_truncate(stat::fstat(fd0).unwrap().st_mode as mode_t); + let m0 = stat::SFlag::from_bits_truncate( + stat::fstat(fd0).unwrap().st_mode as mode_t, + ); // S_IFIFO means it's a pipe assert_eq!(m0, SFlag::S_IFIFO); - let m1 = stat::SFlag::from_bits_truncate(stat::fstat(fd1).unwrap().st_mode as mode_t); + let m1 = stat::SFlag::from_bits_truncate( + stat::fstat(fd1).unwrap().st_mode as mode_t, + ); assert_eq!(m1, SFlag::S_IFIFO); } // pipe2(2) is the same as pipe(2), except it allows setting some flags. Check // that we can set a flag. -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "redox", - target_os = "solaris"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris" +))] #[test] fn test_pipe2() { use nix::fcntl::{fcntl, FcntlArg, FdFlag}; @@ -731,8 +795,13 @@ static mut ALARM_CALLED: bool = false; // Used in `test_alarm`. #[cfg(not(target_os = "redox"))] -pub extern fn alarm_signal_handler(raw_signal: libc::c_int) { - assert_eq!(raw_signal, libc::SIGALRM, "unexpected signal: {}", raw_signal); +pub extern "C" fn alarm_signal_handler(raw_signal: libc::c_int) { + assert_eq!( + raw_signal, + libc::SIGALRM, + "unexpected signal: {}", + raw_signal + ); unsafe { ALARM_CALLED = true }; } @@ -740,15 +809,16 @@ pub extern fn alarm_signal_handler(raw_signal: libc::c_int) { #[cfg(not(target_os = "redox"))] fn test_alarm() { use std::{ - time::{Duration, Instant,}, - thread + thread, + time::{Duration, Instant}, }; // Maybe other tests that fork interfere with this one? let _m = crate::SIGNAL_MTX.lock(); let handler = SigHandler::Handler(alarm_signal_handler); - let signal_action = SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); + let signal_action = + SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); let old_handler = unsafe { sigaction(Signal::SIGALRM, &signal_action) .expect("unable to set signal handler for alarm") @@ -765,7 +835,7 @@ fn test_alarm() { let starttime = Instant::now(); loop { thread::sleep(Duration::from_millis(100)); - if unsafe { ALARM_CALLED} { + if unsafe { ALARM_CALLED } { break; } if starttime.elapsed() > Duration::from_secs(3) { @@ -833,10 +903,19 @@ fn test_linkat_file() { File::create(&oldfilepath).unwrap(); // Get file descriptor for base directory - let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); // Attempt hard link file at relative path - linkat(Some(dirfd), oldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap(); + linkat( + Some(dirfd), + oldfilename, + Some(dirfd), + newfilename, + LinkatFlags::SymlinkFollow, + ) + .unwrap(); assert!(newfilepath.exists()); } @@ -857,11 +936,23 @@ fn test_linkat_olddirfd_none() { File::create(&oldfilepath).unwrap(); // Get file descriptor for base directory of new file - let dirfd = fcntl::open(tempdir_newfile.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let dirfd = fcntl::open( + tempdir_newfile.path(), + fcntl::OFlag::empty(), + stat::Mode::empty(), + ) + .unwrap(); // Attempt hard link file using curent working directory as relative path for old file path chdir(tempdir_oldfile.path()).unwrap(); - linkat(None, oldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap(); + linkat( + None, + oldfilename, + Some(dirfd), + newfilename, + LinkatFlags::SymlinkFollow, + ) + .unwrap(); assert!(newfilepath.exists()); } @@ -882,16 +973,33 @@ fn test_linkat_newdirfd_none() { File::create(&oldfilepath).unwrap(); // Get file descriptor for base directory of old file - let dirfd = fcntl::open(tempdir_oldfile.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let dirfd = fcntl::open( + tempdir_oldfile.path(), + fcntl::OFlag::empty(), + stat::Mode::empty(), + ) + .unwrap(); // Attempt hard link file using current working directory as relative path for new file path chdir(tempdir_newfile.path()).unwrap(); - linkat(Some(dirfd), oldfilename, None, newfilename, LinkatFlags::SymlinkFollow).unwrap(); + linkat( + Some(dirfd), + oldfilename, + None, + newfilename, + LinkatFlags::SymlinkFollow, + ) + .unwrap(); assert!(newfilepath.exists()); } #[test] -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))] +#[cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "haiku" +)))] fn test_linkat_no_follow_symlink() { let _m = crate::CWD_LOCK.read(); @@ -912,17 +1020,23 @@ fn test_linkat_no_follow_symlink() { symlinkat(&oldfilepath, None, &symoldfilepath).unwrap(); // Get file descriptor for base directory - let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); // Attempt link symlink of file at relative path - linkat(Some(dirfd), symoldfilename, Some(dirfd), newfilename, LinkatFlags::NoSymlinkFollow).unwrap(); + linkat( + Some(dirfd), + symoldfilename, + Some(dirfd), + newfilename, + LinkatFlags::NoSymlinkFollow, + ) + .unwrap(); // Assert newfile is actually a symlink to oldfile. assert_eq!( - readlink(&newfilepath) - .unwrap() - .to_str() - .unwrap(), + readlink(&newfilepath).unwrap().to_str().unwrap(), oldfilepath.to_str().unwrap() ); } @@ -949,15 +1063,26 @@ fn test_linkat_follow_symlink() { symlinkat(&oldfilepath, None, &symoldfilepath).unwrap(); // Get file descriptor for base directory - let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); // Attempt link target of symlink of file at relative path - linkat(Some(dirfd), symoldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap(); + linkat( + Some(dirfd), + symoldfilename, + Some(dirfd), + newfilename, + LinkatFlags::SymlinkFollow, + ) + .unwrap(); let newfilestat = stat::stat(&newfilepath).unwrap(); // Check the file type of the new link - assert_eq!((stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t) & SFlag::S_IFMT), + assert_eq!( + (stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t) + & SFlag::S_IFMT), SFlag::S_IFREG ); @@ -976,12 +1101,15 @@ fn test_unlinkat_dir_noremovedir() { DirBuilder::new().recursive(true).create(&dirpath).unwrap(); // Get file descriptor for base directory - let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); // Attempt unlink dir at relative path without proper flag - let err_result = unlinkat(Some(dirfd), dirname, UnlinkatFlags::NoRemoveDir).unwrap_err(); + let err_result = + unlinkat(Some(dirfd), dirname, UnlinkatFlags::NoRemoveDir).unwrap_err(); assert!(err_result == Errno::EISDIR || err_result == Errno::EPERM); - } +} #[test] #[cfg(not(target_os = "redox"))] @@ -994,12 +1122,14 @@ fn test_unlinkat_dir_removedir() { DirBuilder::new().recursive(true).create(&dirpath).unwrap(); // Get file descriptor for base directory - let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); // Attempt unlink dir at relative path with proper flag unlinkat(Some(dirfd), dirname, UnlinkatFlags::RemoveDir).unwrap(); assert!(!dirpath.exists()); - } +} #[test] #[cfg(not(target_os = "redox"))] @@ -1012,25 +1142,29 @@ fn test_unlinkat_file() { File::create(&filepath).unwrap(); // Get file descriptor for base directory - let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + let dirfd = + fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) + .unwrap(); // Attempt unlink file at relative path unlinkat(Some(dirfd), filename, UnlinkatFlags::NoRemoveDir).unwrap(); assert!(!filepath.exists()); - } +} #[test] fn test_access_not_existing() { let tempdir = tempdir().unwrap(); let dir = tempdir.path().join("does_not_exist.txt"); - assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap(), - Errno::ENOENT); + assert_eq!( + access(&dir, AccessFlags::F_OK).err().unwrap(), + Errno::ENOENT + ); } #[test] fn test_access_file_exists() { let tempdir = tempdir().unwrap(); - let path = tempdir.path().join("does_exist.txt"); + let path = tempdir.path().join("does_exist.txt"); let _file = File::create(path.clone()).unwrap(); assert!(access(&path, AccessFlags::R_OK | AccessFlags::W_OK).is_ok()); } @@ -1090,7 +1224,11 @@ fn test_setfsuid() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] fn test_ttyname() { let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); assert!(fd.as_raw_fd() > 0); @@ -1101,11 +1239,8 @@ fn test_ttyname() { grantpt(&fd).expect("grantpt failed"); unlockpt(&fd).expect("unlockpt failed"); let sname = unsafe { ptsname(&fd) }.expect("ptsname failed"); - let fds = open( - Path::new(&sname), - OFlag::O_RDWR, - stat::Mode::empty(), - ).expect("open failed"); + let fds = open(Path::new(&sname), OFlag::O_RDWR, stat::Mode::empty()) + .expect("open failed"); assert!(fds > 0); let name = ttyname(fds).expect("ttyname failed"); @@ -1121,7 +1256,11 @@ fn test_ttyname_not_pty() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] +#[cfg(not(any( + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" +)))] fn test_ttyname_invalid_fd() { assert_eq!(ttyname(-1), Err(Errno::EBADF)); } From d0d48f214b5851704a8c14a4c8962a22c8a3956b Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sat, 25 Jun 2022 21:27:15 -0500 Subject: [PATCH 119/358] Pin cross to 0.2.1, as 0.2.2 requires Rust 1.58.1 --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index ee150f1931..1da767a63b 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -131,7 +131,7 @@ task: - curl --proto '=https' --tlsv1.2 -sSf -o rustup.sh https://sh.rustup.rs - sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN - . $HOME/.cargo/env - - cargo install cross + - cargo install cross --version 0.2.1 # cross 0.2.2 bumped the MSRV to 1.58.1 - cp Cargo.lock.msrv Cargo.lock << : *TEST before_cache_script: rm -rf $CARGO_HOME/registry/index From 1fa1bb19b0ba905a7d89ad3d0496d0970245a3f1 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Thu, 7 Apr 2022 23:17:37 -0500 Subject: [PATCH 120/358] Document aliases for functions like getuid() Add the autocfg crate as a build dependency, and introduce has_doc_alias as a conditional compilation symbol. --- Cargo.toml | 3 +++ build.rs | 7 +++++++ src/dir.rs | 1 + src/sys/signal.rs | 6 ++++++ src/sys/timer.rs | 4 ++++ src/sys/timerfd.rs | 4 ++++ src/unistd.rs | 6 ++++++ 7 files changed, 31 insertions(+) create mode 100644 build.rs diff --git a/Cargo.toml b/Cargo.toml index 65b4b9aed1..284b5e5eba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,9 @@ pin-utils = { version = "0.1.0", optional = true } [target.'cfg(not(target_os = "redox"))'.dependencies] memoffset = { version = "0.6.3", optional = true } +[build-dependencies] +autocfg = "1.1.0" + [features] default = [ "acct", "aio", "dir", "env", "event", "feature", "fs", diff --git a/build.rs b/build.rs new file mode 100644 index 0000000000..ad78ab3ffa --- /dev/null +++ b/build.rs @@ -0,0 +1,7 @@ +fn main() { + let cfg = autocfg::new(); + + if cfg.probe_rustc_version(1, 52) { + autocfg::emit("has_doc_alias"); + } +} diff --git a/src/dir.rs b/src/dir.rs index c9b5af8fc4..8f9a2d6f95 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -53,6 +53,7 @@ impl Dir { } /// Converts from a file descriptor, closing it on success or failure. + #[cfg_attr(has_doc_alias, doc(alias("fdopendir")))] pub fn from_fd(fd: RawFd) -> Result { let d = ptr::NonNull::new(unsafe { libc::fdopendir(fd) }).ok_or_else(|| { let e = Error::last(); diff --git a/src/sys/signal.rs b/src/sys/signal.rs index f6a8c2d773..529b39a886 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -472,6 +472,7 @@ pub struct SigSet { impl SigSet { /// Initialize to include all signals. + #[cfg_attr(has_doc_alias, doc(alias("sigfillset")))] pub fn all() -> SigSet { let mut sigset = mem::MaybeUninit::uninit(); let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) }; @@ -480,6 +481,7 @@ impl SigSet { } /// Initialize to include nothing. + #[cfg_attr(has_doc_alias, doc(alias("sigemptyset")))] pub fn empty() -> SigSet { let mut sigset = mem::MaybeUninit::uninit(); let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) }; @@ -488,21 +490,25 @@ impl SigSet { } /// Add the specified signal to the set. + #[cfg_attr(has_doc_alias, doc(alias("sigaddset")))] 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. + #[cfg_attr(has_doc_alias, doc(alias("sigemptyset")))] pub fn clear(&mut self) { unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) }; } /// Remove the specified signal from this set. + #[cfg_attr(has_doc_alias, doc(alias("sigdelset")))] 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. + #[cfg_attr(has_doc_alias, doc(alias("sigismember")))] pub fn contains(&self, signal: Signal) -> bool { let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) }; diff --git a/src/sys/timer.rs b/src/sys/timer.rs index 349346bb10..45ce0e5bf6 100644 --- a/src/sys/timer.rs +++ b/src/sys/timer.rs @@ -70,6 +70,7 @@ pub struct Timer(libc::timer_t); impl Timer { /// Creates a new timer based on the clock defined by `clockid`. The details /// of the signal and its handler are defined by the passed `sigevent`. + #[cfg_attr(has_doc_alias, doc(alias("timer_create")))] pub fn new(clockid: ClockId, mut sigevent: SigEvent) -> Result { let mut timer_id: mem::MaybeUninit = mem::MaybeUninit::uninit(); Errno::result(unsafe { @@ -122,6 +123,7 @@ impl Timer { /// /// Note: Setting a one shot alarm with a 0s TimeSpec disable the alarm /// altogether. + #[cfg_attr(has_doc_alias, doc(alias("timer_settime")))] pub fn set(&mut self, expiration: Expiration, flags: TimerSetTimeFlags) -> Result<()> { let timerspec: TimerSpec = expiration.into(); Errno::result(unsafe { @@ -136,6 +138,7 @@ impl Timer { } /// Get the parameters for the alarm currently set, if any. + #[cfg_attr(has_doc_alias, doc(alias("timer_gettime")))] pub fn get(&self) -> Result> { let mut timerspec = TimerSpec::none(); Errno::result(unsafe { libc::timer_gettime(self.0, timerspec.as_mut()) }).map(|_| { @@ -158,6 +161,7 @@ impl Timer { /// 'overrun'. This function returns how many times that has happened to /// this timer, up to `libc::DELAYTIMER_MAX`. If more than the maximum /// number of overruns have happened the return is capped to the maximum. + #[cfg_attr(has_doc_alias, doc(alias("timer_getoverrun")))] pub fn overruns(&self) -> i32 { unsafe { libc::timer_getoverrun(self.0) } } diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs index 18acbae30b..42860658aa 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -92,6 +92,7 @@ impl TimerFd { /// Creates a new timer based on the clock defined by `clockid`. The /// underlying fd can be assigned specific flags with `flags` (CLOEXEC, /// NONBLOCK). The underlying fd will be closed on drop. + #[cfg_attr(has_doc_alias, doc(alias("timerfd_create")))] pub fn new(clockid: ClockId, flags: TimerFlags) -> Result { Errno::result(unsafe { libc::timerfd_create(clockid as i32, flags.bits()) }) .map(|fd| Self { fd }) @@ -133,6 +134,7 @@ impl TimerFd { /// /// Note: Setting a one shot alarm with a 0s TimeSpec disables the alarm /// altogether. + #[cfg_attr(has_doc_alias, doc(alias("timerfd_settime")))] pub fn set(&self, expiration: Expiration, flags: TimerSetTimeFlags) -> Result<()> { let timerspec: TimerSpec = expiration.into(); Errno::result(unsafe { @@ -147,6 +149,7 @@ impl TimerFd { } /// Get the parameters for the alarm currently set, if any. + #[cfg_attr(has_doc_alias, doc(alias("timerfd_gettime")))] pub fn get(&self) -> Result> { let mut timerspec = TimerSpec::none(); Errno::result(unsafe { libc::timerfd_gettime(self.fd, timerspec.as_mut()) }).map(|_| { @@ -163,6 +166,7 @@ impl TimerFd { } /// Remove the alarm if any is set. + #[cfg_attr(has_doc_alias, doc(alias("timerfd_settime")))] pub fn unset(&self) -> Result<()> { Errno::result(unsafe { libc::timerfd_settime( diff --git a/src/unistd.rs b/src/unistd.rs index fe8ec8408a..86eec627b2 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -67,11 +67,13 @@ impl Uid { } /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`. + #[cfg_attr(has_doc_alias, doc(alias("getuid")))] pub fn current() -> Self { getuid() } /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`. + #[cfg_attr(has_doc_alias, doc(alias("geteuid")))] pub fn effective() -> Self { geteuid() } @@ -122,11 +124,13 @@ impl Gid { } /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`. + #[cfg_attr(has_doc_alias, doc(alias("getgid")))] pub fn current() -> Self { getgid() } /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`. + #[cfg_attr(has_doc_alias, doc(alias("getegid")))] pub fn effective() -> Self { getegid() } @@ -172,11 +176,13 @@ impl Pid { } /// Returns PID of calling process + #[cfg_attr(has_doc_alias, doc(alias("getpid")))] pub fn this() -> Self { getpid() } /// Returns PID of parent of calling process + #[cfg_attr(has_doc_alias, doc(alias("getppid")))] pub fn parent() -> Self { getppid() } From 356ecce5cd196afe533d881d888856fd41fe624e Mon Sep 17 00:00:00 2001 From: Nathaniel Daniel Date: Tue, 14 Jun 2022 19:38:17 -0700 Subject: [PATCH 121/358] Change gethostname to use a buffer of MaybeUninit values --- CHANGELOG.md | 2 ++ README.md | 2 +- src/unistd.rs | 11 +++++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7c3df5f53..6edfba90ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1713](https://github.com/nix-rust/nix/pull/1713)) - `nix::poll::ppoll`: `sigmask` parameter is now optional. (#[1739](https://github.com/nix-rust/nix/pull/1739)) +- Changed `gethostname` to use a buffer of `MaybeUninit` values. + (#[1745](https://github.com/nix-rust/nix/pull/1745)) ### Fixed diff --git a/README.md b/README.md index 44e620cce5..04f9bd613e 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ call: pub unsafe extern fn gethostname(name: *mut c_char, len: size_t) -> c_int; // nix api (returns a nix::Result) -pub fn gethostname<'a>(buffer: &'a mut [u8]) -> Result<&'a CStr>; +pub fn gethostname<'a>(buffer: &'a mut [mem::MaybeUninit]) -> Result<&'a CStr>; ``` ## Supported Platforms diff --git a/src/unistd.rs b/src/unistd.rs index 86eec627b2..6a7f0c3793 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -1005,20 +1005,23 @@ pub fn sethostname>(name: S) -> Result<()> { /// /// ```no_run /// use nix::unistd; +/// use std::mem; /// -/// let mut buf = [0u8; 64]; +/// let mut buf = [mem::MaybeUninit::uninit(); 64]; /// let hostname_cstr = unistd::gethostname(&mut buf).expect("Failed getting hostname"); /// let hostname = hostname_cstr.to_str().expect("Hostname wasn't valid UTF-8"); /// println!("Hostname: {}", hostname); /// ``` -pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> { +pub fn gethostname(buffer: &mut [mem::MaybeUninit]) -> Result<&CStr> { let ptr = buffer.as_mut_ptr() as *mut c_char; let len = buffer.len() as size_t; let res = unsafe { libc::gethostname(ptr, len) }; Errno::result(res).map(|_| { - buffer[len - 1] = 0; // ensure always null-terminated - unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) } + unsafe { + buffer[len - 1].as_mut_ptr().write(0); // ensure always null-terminated + CStr::from_ptr(buffer.as_ptr() as *const c_char) + } }) } } From 22c4ba8bc0f7f9de703cf64007f5d0ef1ebdd943 Mon Sep 17 00:00:00 2001 From: Nathaniel Daniel Date: Fri, 24 Jun 2022 18:29:07 -0700 Subject: [PATCH 122/358] Change gethostname to return an OsString --- CHANGELOG.md | 2 +- README.md | 4 ++-- src/unistd.rs | 29 +++++++++++++---------------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6edfba90ab..424b9d895b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1713](https://github.com/nix-rust/nix/pull/1713)) - `nix::poll::ppoll`: `sigmask` parameter is now optional. (#[1739](https://github.com/nix-rust/nix/pull/1739)) -- Changed `gethostname` to use a buffer of `MaybeUninit` values. +- Changed `gethostname` to return an owned `OsString`. (#[1745](https://github.com/nix-rust/nix/pull/1745)) ### Fixed diff --git a/README.md b/README.md index 04f9bd613e..7c13cf201c 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ call: // libc api (unsafe, requires handling return code/errno) pub unsafe extern fn gethostname(name: *mut c_char, len: size_t) -> c_int; -// nix api (returns a nix::Result) -pub fn gethostname<'a>(buffer: &'a mut [mem::MaybeUninit]) -> Result<&'a CStr>; +// nix api (returns a nix::Result) +pub fn gethostname() -> Result; ``` ## Supported Platforms diff --git a/src/unistd.rs b/src/unistd.rs index 6a7f0c3793..01181893a9 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -991,37 +991,34 @@ pub fn sethostname>(name: S) -> Result<()> { Errno::result(res).map(drop) } -/// Get the host name and store it in the provided buffer, returning a pointer -/// the `CStr` in that buffer on success (see +/// Get the host name and store it in an internally allocated buffer, returning an +/// `OsString` on success (see /// [gethostname(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)). /// /// This function call attempts to get the host name for the running system and -/// store it in a provided buffer. The buffer will be populated with bytes up -/// to the length of the provided slice including a NUL terminating byte. If -/// the hostname is longer than the length provided, no error will be provided. -/// The posix specification does not specify whether implementations will -/// null-terminate in this case, but the nix implementation will ensure that the -/// buffer is null terminated in this case. +/// store it in an internal buffer, returning it as an `OsString` if successful. /// /// ```no_run /// use nix::unistd; -/// use std::mem; /// -/// let mut buf = [mem::MaybeUninit::uninit(); 64]; -/// let hostname_cstr = unistd::gethostname(&mut buf).expect("Failed getting hostname"); -/// let hostname = hostname_cstr.to_str().expect("Hostname wasn't valid UTF-8"); +/// let hostname = unistd::gethostname().expect("Failed getting hostname"); +/// let hostname = hostname.into_string().expect("Hostname wasn't valid UTF-8"); /// println!("Hostname: {}", hostname); /// ``` -pub fn gethostname(buffer: &mut [mem::MaybeUninit]) -> Result<&CStr> { +pub fn gethostname() -> Result { + // The capacity is the max length of a hostname plus the NUL terminator. + let mut buffer: Vec = Vec::with_capacity(256); let ptr = buffer.as_mut_ptr() as *mut c_char; - let len = buffer.len() as size_t; + let len = buffer.capacity() as size_t; let res = unsafe { libc::gethostname(ptr, len) }; Errno::result(res).map(|_| { unsafe { - buffer[len - 1].as_mut_ptr().write(0); // ensure always null-terminated - CStr::from_ptr(buffer.as_ptr() as *const c_char) + buffer.as_mut_ptr().wrapping_add(len - 1).write(0); // ensure always null-terminated + let len = CStr::from_ptr(buffer.as_ptr() as *const c_char).len(); + buffer.set_len(len); } + OsString::from_vec(buffer) }) } } From 8cfc530b8881e2edba4df54d0334a6b81cd598c6 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Thu, 7 Jul 2022 14:58:38 -0500 Subject: [PATCH 123/358] Fix clippy on nightly --- src/unistd.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 86eec627b2..4c9b67ffc9 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2938,35 +2938,35 @@ impl From<&libc::passwd> for User { fn from(pw: &libc::passwd) -> User { unsafe { User { - name: CStr::from_ptr((*pw).pw_name).to_string_lossy().into_owned(), - passwd: CString::new(CStr::from_ptr((*pw).pw_passwd).to_bytes()).unwrap(), + name: CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned(), + passwd: CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes()).unwrap(), #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] - gecos: CString::new(CStr::from_ptr((*pw).pw_gecos).to_bytes()).unwrap(), - dir: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_dir).to_bytes())), - shell: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_shell).to_bytes())), - uid: Uid::from_raw((*pw).pw_uid), - gid: Gid::from_raw((*pw).pw_gid), + gecos: CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes()).unwrap(), + dir: PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_dir).to_bytes())), + shell: PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_shell).to_bytes())), + uid: Uid::from_raw(pw.pw_uid), + gid: Gid::from_raw(pw.pw_gid), #[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "haiku", target_os = "illumos", target_os = "linux", target_os = "solaris")))] - class: CString::new(CStr::from_ptr((*pw).pw_class).to_bytes()).unwrap(), + class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes()).unwrap(), #[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "haiku", target_os = "illumos", target_os = "linux", target_os = "solaris")))] - change: (*pw).pw_change, + change: pw.pw_change, #[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "haiku", target_os = "illumos", target_os = "linux", target_os = "solaris")))] - expire: (*pw).pw_expire + expire: pw.pw_expire } } } @@ -3123,10 +3123,10 @@ impl From<&libc::group> for Group { fn from(gr: &libc::group) -> Group { unsafe { Group { - name: CStr::from_ptr((*gr).gr_name).to_string_lossy().into_owned(), - passwd: CString::new(CStr::from_ptr((*gr).gr_passwd).to_bytes()).unwrap(), - gid: Gid::from_raw((*gr).gr_gid), - mem: Group::members((*gr).gr_mem) + name: CStr::from_ptr(gr.gr_name).to_string_lossy().into_owned(), + passwd: CString::new(CStr::from_ptr(gr.gr_passwd).to_bytes()).unwrap(), + gid: Gid::from_raw(gr.gr_gid), + mem: Group::members(gr.gr_mem) } } } From dc1a34b864abc12bfef3de06b267d299298e01cb Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 9 Jul 2022 21:48:24 -0600 Subject: [PATCH 124/358] Clippy cleanup in the tests. * Remove a redundant closure. * Comparison with null * Manual implementation of find * Suppress a false positive --- .cirrus.yml | 4 ++-- test/sys/test_pthread.rs | 2 +- test/sys/test_socket.rs | 14 +++++--------- test/test_unistd.rs | 5 +++-- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 1da767a63b..9b735cf2b4 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -20,7 +20,7 @@ build: &BUILD - rustc +$TOOLCHAIN -Vv - $TOOL +$TOOLCHAIN $BUILD $ZFLAGS --target $TARGET --all-targets - $TOOL +$TOOLCHAIN doc $ZFLAGS --no-deps --target $TARGET - - $TOOL +$TOOLCHAIN clippy $ZFLAGS --target $TARGET -- -D warnings + - $TOOL +$TOOLCHAIN clippy $ZFLAGS --target $TARGET --all-targets -- -D warnings - if [ -z "$NOHACK" ]; then $TOOL +$TOOLCHAIN install cargo-hack; fi - if [ -z "$NOHACK" ]; then $TOOL +$TOOLCHAIN hack $ZFLAGS check --target $TARGET --each-feature; fi @@ -327,4 +327,4 @@ task: container: image: rust:latest setup_script: rustup +$TOOLCHAIN component add rustfmt - test_script: $TOOL +$TOOLCHAIN fmt --all -- --check \ No newline at end of file + test_script: $TOOL +$TOOLCHAIN fmt --all -- --check diff --git a/test/sys/test_pthread.rs b/test/sys/test_pthread.rs index fa9b510e85..42a4aefaad 100644 --- a/test/sys/test_pthread.rs +++ b/test/sys/test_pthread.rs @@ -4,7 +4,7 @@ use nix::sys::pthread::*; #[test] fn test_pthread_self() { let tid = pthread_self(); - assert!(tid != ::std::ptr::null_mut()); + assert!(!tid.is_null()); } #[cfg(not(any(target_env = "musl", target_os = "redox")))] diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 067717bb1d..3a553d3a6a 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -345,7 +345,7 @@ mod recvfrom { ) .unwrap(); // Ignore from for stream sockets - let _ = sendrecv(fd1, fd2, |s, m, flags| send(s, m, flags), |_, _| {}); + let _ = sendrecv(fd1, fd2, send, |_, _| {}); } #[test] @@ -1472,7 +1472,7 @@ fn loopback_address( use std::io; use std::io::Write; - let addrs = match getifaddrs() { + let mut addrs = match getifaddrs() { Ok(iter) => iter, Err(e) => { let stdioerr = io::stderr(); @@ -1482,15 +1482,11 @@ fn loopback_address( } }; // return first address matching family - for ifaddr in addrs { - if ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK) + addrs.find(|ifaddr| { + ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK) && ifaddr.address.as_ref().and_then(SockaddrLike::family) == Some(family) - { - return Some(ifaddr); - } - } - None + }) } #[cfg(any( diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 233928349e..38d31a3fd5 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -1169,6 +1169,8 @@ fn test_access_file_exists() { assert!(access(&path, AccessFlags::R_OK | AccessFlags::W_OK).is_ok()); } +//Clippy false positive https://github.com/rust-lang/rust-clippy/issues/9111 +#[allow(clippy::needless_borrow)] #[cfg(not(target_os = "redox"))] #[test] fn test_user_into_passwd() { @@ -1198,8 +1200,7 @@ fn test_setfsuid() { // create a temporary file with permissions '-rw-r-----' let file = tempfile::NamedTempFile::new_in("/var/tmp").unwrap(); let temp_path = file.into_temp_path(); - dbg!(&temp_path); - let temp_path_2 = (&temp_path).to_path_buf(); + let temp_path_2 = temp_path.to_path_buf(); let mut permissions = fs::metadata(&temp_path).unwrap().permissions(); permissions.set_mode(0o640); From d988c65d86a8d7cf74622af2378e1e611d1f2966 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 10 Jul 2022 10:20:48 -0600 Subject: [PATCH 125/358] More docs for mqueue. Also, delete some dead code. It's always been dead. --- src/lib.rs | 1 - src/mqueue.rs | 29 +++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c8df1ce36d..a2d5f817ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,7 +119,6 @@ feature! { ))] feature! { #![feature = "mqueue"] - #[allow(missing_docs)] pub mod mqueue; } feature! { diff --git a/src/mqueue.rs b/src/mqueue.rs index 792a5d2293..e3c0c43eee 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -39,23 +39,29 @@ use crate::sys::stat::Mode; use std::mem; libc_bitflags!{ + /// Used with [`mq_open`]. pub struct MQ_OFlag: libc::c_int { + /// Open the message queue for receiving messages. O_RDONLY; + /// Open the queue for sending messages. O_WRONLY; + /// Open the queue for both receiving and sending messages O_RDWR; + /// Create a message queue. O_CREAT; + /// If set along with `O_CREAT`, `mq_open` will fail if the message + /// queue name exists. O_EXCL; + /// `mq_send` and `mq_receive` should fail with `EAGAIN` rather than + /// wait for resources that are not currently available. O_NONBLOCK; + /// Set the close-on-exec flag for the message queue descriptor. O_CLOEXEC; } } -libc_bitflags!{ - pub struct FdFlag: libc::c_int { - FD_CLOEXEC; - } -} - +/// A message-queue attribute, optionally used with [`mq_setattr`] and +/// [`mq_getattr`] and optionally [`mq_open`], #[repr(C)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct MqAttr { @@ -72,14 +78,24 @@ pub struct MqdT(mqd_t); // x32 compatibility // See https://sourceware.org/bugzilla/show_bug.cgi?id=21279 +/// Size of a message queue attribute member #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub type mq_attr_member_t = i64; +/// Size of a message queue attribute member #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] #[cfg_attr(docsrs, doc(cfg(all())))] pub type mq_attr_member_t = libc::c_long; impl MqAttr { + /// Create a new message queue attribute + /// + /// # Arguments + /// + /// - `mq_flags`: Either `0` or `O_NONBLOCK`. + /// - `mq_maxmsg`: Maximum number of messages on the queue. + /// - `mq_msgsize`: Maximum message size in bytes. + /// - `mq_curmsgs`: Number of messages currently in the queue. pub fn new(mq_flags: mq_attr_member_t, mq_maxmsg: mq_attr_member_t, mq_msgsize: mq_attr_member_t, @@ -97,6 +113,7 @@ impl MqAttr { } } + /// The current flags, either `0` or `O_NONBLOCK`. pub const fn flags(&self) -> mq_attr_member_t { self.mq_attr.mq_flags } From 349f3acf423f8f38d69eb49b89d2872864b871c4 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 10 Jul 2022 10:28:38 -0600 Subject: [PATCH 126/358] More docs for the dir module --- src/dir.rs | 11 +++++++++++ src/lib.rs | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/dir.rs b/src/dir.rs index 8f9a2d6f95..6d5fc3b925 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -1,3 +1,5 @@ +//! List directory contents + use crate::{Error, NixPath, Result}; use crate::errno::Errno; use crate::fcntl::{self, OFlag}; @@ -114,6 +116,7 @@ fn next(dir: &mut Dir) -> Option> { } } +/// Return type of [`Dir::iter`]. #[derive(Debug, Eq, Hash, PartialEq)] pub struct Iter<'d>(&'d mut Dir); @@ -183,14 +186,22 @@ impl IntoIterator for Dir { #[repr(transparent)] pub struct Entry(dirent); +/// Type of file referenced by a directory entry #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] pub enum Type { + /// FIFO (Named pipe) Fifo, + /// Character device CharacterDevice, + /// Directory Directory, + /// Block device BlockDevice, + /// Regular file File, + /// Symbolic link Symlink, + /// Unix-domain socket Socket, } diff --git a/src/lib.rs b/src/lib.rs index a2d5f817ae..689392090b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,7 +65,6 @@ mod macros; #[cfg(not(target_os = "redox"))] feature! { #![feature = "dir"] - #[allow(missing_docs)] pub mod dir; } feature! { From ba376e8577fd9b441ca1e6028f03c928f1045dd5 Mon Sep 17 00:00:00 2001 From: Leo Lu Date: Tue, 28 Jun 2022 20:32:55 +0800 Subject: [PATCH 127/358] Add DontRoute SockOpt --- src/sys/socket/sockopt.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 33c86cd272..8f85748f20 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -352,6 +352,9 @@ sockopt_impl!( sockopt_impl!( /// Get and clear the pending socket error. SocketError, GetOnly, libc::SOL_SOCKET, libc::SO_ERROR, i32); +sockopt_impl!( + /// Set or get the don't route flag. + DontRoute, Both, libc::SOL_SOCKET, libc::SO_DONTROUTE, bool); sockopt_impl!( /// Enable sending of keep-alive messages on connection-oriented sockets. KeepAlive, Both, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool); From 790960cbb2fa496fcfe56c6be07361ffcfe67901 Mon Sep 17 00:00:00 2001 From: Leo Lu Date: Sun, 10 Jul 2022 12:19:20 +0800 Subject: [PATCH 128/358] Added CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 424b9d895b..70e4331669 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1697](https://github.com/nix-rust/nix/pull/1697)) - Added `getrusage` and helper types `UsageWho` and `Usage` (#[1747](https://github.com/nix-rust/nix/pull/1747)) +- Added the `DontRoute` SockOpt + (#[1752](https://github.com/nix-rust/nix/pull/1752)) ### Changed From b3e4d59bd7ad8a816b2ebe5f4564d8b62bbba4f5 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 10 Jul 2022 18:09:51 -0600 Subject: [PATCH 129/358] Add const constructors for TimeSpec and TimeVal These are basically the same as From and From, but they're const and require less typing. --- CHANGELOG.md | 3 ++- src/sys/time.rs | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7c3df5f53..80e2ce2f92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added const constructors for `TimeSpec` and `TimeVal` + (#[1760](https://github.com/nix-rust/nix/pull/1760)) - Added `aio_writev` and `aio_readv`. (#[1713](https://github.com/nix-rust/nix/pull/1713)) - - impl `From` for `Uid` and `From` for `Gid` (#[1727](https://github.com/nix-rust/nix/pull/1727)) - impl From for std::net::SocketAddrV4 and diff --git a/src/sys/time.rs b/src/sys/time.rs index c559cc4794..b7ab3986f8 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -330,6 +330,15 @@ impl TimeValLike for TimeSpec { } impl TimeSpec { + /// Construct a new `TimeSpec` from its components + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self { + Self(timespec { + tv_sec: seconds, + tv_nsec: nanoseconds, + }) + } + fn nanos_mod_sec(&self) -> timespec_tv_nsec_t { if self.tv_sec() < 0 && self.tv_nsec() > 0 { self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t @@ -564,6 +573,15 @@ impl TimeValLike for TimeVal { } impl TimeVal { + /// Construct a new `TimeVal` from its components + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 + pub const fn new(seconds: time_t, microseconds: suseconds_t) -> Self { + Self(timeval { + tv_sec: seconds, + tv_usec: microseconds, + }) + } + fn micros_mod_sec(&self) -> suseconds_t { if self.tv_sec() < 0 && self.tv_usec() > 0 { self.tv_usec() - MICROS_PER_SEC as suseconds_t From 3d44d276e768f47cefe301e3affbefd315dc1327 Mon Sep 17 00:00:00 2001 From: German Maglione Date: Wed, 8 Jun 2022 15:55:13 +0200 Subject: [PATCH 130/358] SigSet: A new unsafe helper method to create a SigSet from a sigset_t Currently, the only way to create a `SigSet` from a `sigset_t` object is by using pointer casts, like: ``` unsafe { let sigset = *(&sigset as *const libc::sigset_t as *const SigSet) }; ``` This is un-ergonomic for library creators with interfaces to C. So, let's add a new unsafe method that creates a `SigSet` from a `libc::sigset_t` object. We can't implement `From` since converting from `libc::sigset_t` to `SigSet` is unsafe, because objects of type `libc::sigset_t` must be initialized by calling either `sigemptyset(3)` or `sigfillset(3)` before being used. In other case, the results are undefined. We can't implement `TryFrom` either, because there is no way to check if an object of type `libc::sigset_t` is initialized. Signed-off-by: German Maglione --- CHANGELOG.md | 2 ++ src/sys/signal.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0bdeb3489..02620c3607 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1747](https://github.com/nix-rust/nix/pull/1747)) - Added the `DontRoute` SockOpt (#[1752](https://github.com/nix-rust/nix/pull/1752)) +- Added `signal::SigSet::from_sigset_t_unchecked()`. + (#[1741](https://github.com/nix-rust/nix/pull/1741)) ### Changed diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 529b39a886..4ce093080b 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -567,6 +567,19 @@ impl SigSet { Signal::try_from(signum.assume_init()).unwrap() }) } + + /// Converts a `libc::sigset_t` object to a [`SigSet`] without checking whether the + /// `libc::sigset_t` is already initialized. + /// + /// # Safety + /// + /// The `sigset` passed in must be a valid an initialized `libc::sigset_t` by calling either + /// [`sigemptyset(3)`](https://man7.org/linux/man-pages/man3/sigemptyset.3p.html) or + /// [`sigfillset(3)`](https://man7.org/linux/man-pages/man3/sigfillset.3p.html). + /// Otherwise, the results are undefined. + pub unsafe fn from_sigset_t_unchecked(sigset: libc::sigset_t) -> SigSet { + SigSet { sigset } + } } impl AsRef for SigSet { @@ -1311,4 +1324,21 @@ mod tests { .join() .unwrap(); } + + #[test] + fn test_from_sigset_t_unchecked() { + let src_set = SigSet::empty(); + let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) }; + + for signal in Signal::iterator() { + assert!(!set.contains(signal)); + } + + let src_set = SigSet::all(); + let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) }; + + for signal in Signal::iterator() { + assert!(set.contains(signal)); + } + } } From b207aaee4ca5721314d03172bbf188e63ec21cc3 Mon Sep 17 00:00:00 2001 From: German Maglione Date: Mon, 20 Jun 2022 11:57:04 +0200 Subject: [PATCH 131/358] SigSet: Add the `repr(transparent)` attribute This commit adds the `repr(transparent)` attribute to the `SigSet` struct, to make sure that its representation is exactly like the `sigset_t` struct from C, in all cases. Signed-off-by: German Maglione --- CHANGELOG.md | 2 ++ src/sys/signal.rs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02620c3607..b3f2130189 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1739](https://github.com/nix-rust/nix/pull/1739)) - Changed `gethostname` to return an owned `OsString`. (#[1745](https://github.com/nix-rust/nix/pull/1745)) +- `signal:SigSet` is now marked as `repr(transparent)`. + (#[1741](https://github.com/nix-rust/nix/pull/1741)) ### Fixed diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 4ce093080b..4a468b62c5 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -465,6 +465,9 @@ use std::iter::FromIterator; use std::iter::IntoIterator; /// Specifies a set of [`Signal`]s that may be blocked, waited for, etc. +// We are using `transparent` here to be super sure that `SigSet` +// is represented exactly like the `sigset_t` struct from C. +#[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct SigSet { sigset: libc::sigset_t From b7a2de0539ccd35cf78f9ff3a06f1b3275bcf27a Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Wed, 13 Jul 2022 14:37:49 -0400 Subject: [PATCH 132/358] Added non-standard Linux `SysconfVar` variants --- CHANGELOG.md | 2 ++ src/unistd.rs | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0bdeb3489..1109818be1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added four non-standard Linux `SysconfVar` variants + (#[1761](https://github.com/nix-rust/nix/pull/1761)) - Added const constructors for `TimeSpec` and `TimeVal` (#[1760](https://github.com/nix-rust/nix/pull/1760)) - Added `aio_writev` and `aio_readv`. diff --git a/src/unistd.rs b/src/unistd.rs index 056b552936..e738349a21 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2668,6 +2668,19 @@ pub enum SysconfVar { /// Integer value indicating version of the X/Open Portability Guide to /// which the implementation conforms. _XOPEN_VERSION = libc::_SC_XOPEN_VERSION, + /// The number of pages of physical memory. Note that it is possible for + /// the product of this value to overflow. + #[cfg(any(target_os="android", target_os="linux"))] + _PHYS_PAGES = libc::_SC_PHYS_PAGES, + /// The number of currently available pages of physical memory. + #[cfg(any(target_os="android", target_os="linux"))] + _AVPHYS_PAGES = libc::_SC_AVPHYS_PAGES, + /// The number of processors configured. + #[cfg(any(target_os="android", target_os="linux"))] + _NPROCESSORS_CONF = libc::_SC_NPROCESSORS_CONF, + /// The number of processors currently online (available). + #[cfg(any(target_os="android", target_os="linux"))] + _NPROCESSORS_ONLN = libc::_SC_NPROCESSORS_ONLN, } /// Get configurable system variables (see From 137a9abb666661d1546d471e61321a94ead2eca2 Mon Sep 17 00:00:00 2001 From: musikid Date: Wed, 27 Apr 2022 12:23:56 +0200 Subject: [PATCH 133/358] Add chflags --- CHANGELOG.md | 2 + Cargo.toml | 2 +- src/sys/stat.rs | 112 ++++++++++++++++++++++++++++++++++++++++++ src/unistd.rs | 35 +++++++++++++ test/sys/mod.rs | 1 + test/sys/test_stat.rs | 27 ++++++++++ 6 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 test/sys/test_stat.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 1109818be1..244455bdc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1761](https://github.com/nix-rust/nix/pull/1761)) - Added const constructors for `TimeSpec` and `TimeVal` (#[1760](https://github.com/nix-rust/nix/pull/1760)) +- Added `chflags`. + (#[1758](https://github.com/nix-rust/nix/pull/1758)) - Added `aio_writev` and `aio_readv`. (#[1713](https://github.com/nix-rust/nix/pull/1713)) - impl `From` for `Uid` and `From` for `Gid` diff --git a/Cargo.toml b/Cargo.toml index 284b5e5eba..4214b16e5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.126", features = [ "extra_traits" ] } +libc = { git = "https://github.com/rust-lang/libc", rev = "8dbd2c9", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 5cf2deb75e..8b7627d5bc 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -1,4 +1,12 @@ pub use libc::{dev_t, mode_t}; +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] +pub use libc::c_uint; +#[cfg(any( + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly" +))] +pub use libc::c_ulong; pub use libc::stat as FileStat; use crate::{Result, NixPath, errno::Errno}; @@ -43,6 +51,110 @@ libc_bitflags! { } } +#[cfg(any(target_os = "macos", target_os = "ios", target_os="openbsd"))] +pub type type_of_file_flag = c_uint; +#[cfg(any( + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly" +))] +pub type type_of_file_flag = c_ulong; + +#[cfg(any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios" +))] +libc_bitflags! { + /// File flags. + #[cfg_attr(docsrs, doc(cfg(all())))] + pub struct FileFlag: type_of_file_flag { + /// The file may only be appended to. + SF_APPEND; + /// The file has been archived. + SF_ARCHIVED; + #[cfg(any(target_os = "dragonfly"))] + SF_CACHE; + /// The file may not be changed. + SF_IMMUTABLE; + /// Indicates a WAPBL journal file. + #[cfg(any(target_os = "netbsd"))] + SF_LOG; + /// Do not retain history for file + #[cfg(any(target_os = "dragonfly"))] + SF_NOHISTORY; + /// The file may not be renamed or deleted. + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + SF_NOUNLINK; + /// Mask of superuser changeable flags + SF_SETTABLE; + /// Snapshot is invalid. + #[cfg(any(target_os = "netbsd"))] + SF_SNAPINVAL; + /// The file is a snapshot file. + #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] + SF_SNAPSHOT; + #[cfg(any(target_os = "dragonfly"))] + SF_XLINK; + /// The file may only be appended to. + UF_APPEND; + /// The file needs to be archived. + #[cfg(any(target_os = "freebsd"))] + UF_ARCHIVE; + #[cfg(any(target_os = "dragonfly"))] + UF_CACHE; + /// File is compressed at the file system level. + #[cfg(any(target_os = "macos", target_os = "ios"))] + UF_COMPRESSED; + /// The file may be hidden from directory listings at the application's + /// discretion. + #[cfg(any( + target_os = "freebsd", + target_os = "macos", + target_os = "ios", + ))] + UF_HIDDEN; + /// The file may not be changed. + UF_IMMUTABLE; + /// Do not dump the file. + UF_NODUMP; + #[cfg(any(target_os = "dragonfly"))] + UF_NOHISTORY; + /// The file may not be renamed or deleted. + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + UF_NOUNLINK; + /// The file is offline, or has the Windows and CIFS + /// `FILE_ATTRIBUTE_OFFLINE` attribute. + #[cfg(any(target_os = "freebsd"))] + UF_OFFLINE; + /// The directory is opaque when viewed through a union stack. + UF_OPAQUE; + /// The file is read only, and may not be written or appended. + #[cfg(any(target_os = "freebsd"))] + UF_READONLY; + /// The file contains a Windows reparse point. + #[cfg(any(target_os = "freebsd"))] + UF_REPARSE; + /// Mask of owner changeable flags. + UF_SETTABLE; + /// The file has the Windows `FILE_ATTRIBUTE_SPARSE_FILE` attribute. + #[cfg(any(target_os = "freebsd"))] + UF_SPARSE; + /// The file has the DOS, Windows and CIFS `FILE_ATTRIBUTE_SYSTEM` + /// attribute. + #[cfg(any(target_os = "freebsd"))] + UF_SYSTEM; + /// File renames and deletes are tracked. + #[cfg(any(target_os = "macos", target_os = "ios"))] + UF_TRACKED; + #[cfg(any(target_os = "dragonfly"))] + UF_XLINK; + } +} + /// Create a special or ordinary file, by pathname. pub fn mknod(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { diff --git a/src/unistd.rs b/src/unistd.rs index e738349a21..6dd0c16463 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -6,6 +6,18 @@ use crate::errno::{self, Errno}; use crate::fcntl::{at_rawfd, AtFlags}; #[cfg(feature = "fs")] use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; +#[cfg(all( + feature = "fs", + any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios" + ) +))] +use crate::sys::stat::FileFlag; #[cfg(feature = "fs")] use crate::sys::stat::Mode; use crate::{Error, NixPath, Result}; @@ -3288,3 +3300,26 @@ pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> { Errno::result(ret).map(|_| (Uid(uid), Gid(gid))) } } + +feature! { +#![all(feature = "fs")] + +/// Set the file flags. +/// +/// See also [chflags(2)](https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2) +#[cfg(any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios" +))] +pub fn chflags(path: &P, flags: FileFlag) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::chflags(cstr.as_ptr(), flags.bits()) + })?; + + Errno::result(res).map(drop) +} +} diff --git a/test/sys/mod.rs b/test/sys/mod.rs index ed4ad736fb..20312120a6 100644 --- a/test/sys/mod.rs +++ b/test/sys/mod.rs @@ -29,6 +29,7 @@ mod test_signalfd; mod test_socket; #[cfg(not(any(target_os = "redox")))] mod test_sockopt; +mod test_stat; #[cfg(any(target_os = "android", target_os = "linux"))] mod test_sysinfo; #[cfg(not(any( diff --git a/test/sys/test_stat.rs b/test/sys/test_stat.rs new file mode 100644 index 0000000000..2f26e789c7 --- /dev/null +++ b/test/sys/test_stat.rs @@ -0,0 +1,27 @@ +#[cfg(target_os = "freebsd")] +#[test] +fn test_chflags() { + use nix::{ + sys::stat::{fstat, FileFlag}, + unistd::chflags, + }; + use std::os::unix::io::AsRawFd; + use tempfile::NamedTempFile; + + let f = NamedTempFile::new().unwrap(); + + let initial = FileFlag::from_bits_truncate( + fstat(f.as_raw_fd()).unwrap().st_flags.into(), + ); + // UF_OFFLINE is preserved by all FreeBSD file systems, but not interpreted + // in any way, so it's handy for testing. + let commanded = initial ^ FileFlag::UF_OFFLINE; + + chflags(f.path(), commanded).unwrap(); + + let changed = FileFlag::from_bits_truncate( + fstat(f.as_raw_fd()).unwrap().st_flags.into(), + ); + + assert_eq!(commanded, changed); +} From e0e768e7b92a33ed040c7f0438f860c522f2ef6f Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 14 Jul 2022 11:10:06 -0600 Subject: [PATCH 134/358] Fix a buffer overflow in sys::socket::recvfrom IPv4 and stream sockets are unaffected, but for datagram sockets of other address types libc::recvfrom might overwrite part of the stack. Fixes #1762 --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 9 +++++--- test/sys/test_socket.rs | 49 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 244455bdc4..9f59605c42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Fixed +- Fixed buffer overflow in nix::sys::socket::recvfrom. + (#[1763](https://github.com/nix-rust/nix/pull/1763)) - Enabled `SockaddrStorage::{as_link_addr, as_link_addr_mut}` for Linux-like operating systems. (#[1729](https://github.com/nix-rust/nix/pull/1729)) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 6386e62b6b..00b2ca703e 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1912,8 +1912,8 @@ pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, Option)> { unsafe { - let mut addr = mem::MaybeUninit::uninit(); - let mut len = mem::size_of::() as socklen_t; + let mut addr = mem::MaybeUninit::::uninit(); + let mut len = mem::size_of_val(&addr) as socklen_t; let ret = Errno::result(libc::recvfrom( sockfd, @@ -1923,7 +1923,10 @@ pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) addr.as_mut_ptr() as *mut libc::sockaddr, &mut len as *mut socklen_t))? as usize; - Ok((ret, T::from_raw(&addr.assume_init(), Some(len)))) + Ok((ret, T::from_raw( + addr.assume_init().as_ptr() as *const libc::sockaddr, + Some(len)) + )) } } diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 3a553d3a6a..56819c9f0d 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -298,7 +298,7 @@ pub fn test_std_conversions() { mod recvfrom { use super::*; use nix::sys::socket::*; - use nix::Result; + use nix::{errno::Errno, Result}; use std::thread; const MSG: &[u8] = b"Hello, World!"; @@ -681,6 +681,51 @@ mod recvfrom { assert_eq!(&buf[..DATA.len()], DATA); } } + + #[test] + pub fn udp_inet6() { + let addr = std::net::Ipv6Addr::from_str("::1").unwrap(); + let rport = 6789; + let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0); + let raddr = SockaddrIn6::from(rstd_sa); + let sport = 6790; + let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0); + let saddr = SockaddrIn6::from(sstd_sa); + let rsock = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("receive socket failed"); + match bind(rsock, &raddr) { + Err(Errno::EADDRNOTAVAIL) => { + println!("IPv6 not available, skipping test."); + return; + } + Err(e) => panic!("bind: {}", e), + Ok(()) => (), + } + let ssock = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + bind(ssock, &saddr).unwrap(); + let from = sendrecv( + rsock, + ssock, + move |s, m, flags| sendto(s, m, &raddr, flags), + |_, _| {}, + ); + assert_eq!(AddressFamily::Inet6, from.unwrap().family().unwrap()); + let osent_addr = from.unwrap(); + let sent_addr = osent_addr.as_sockaddr_in6().unwrap(); + assert_eq!(sent_addr.ip(), addr); + assert_eq!(sent_addr.port(), sport); + } } // Test error handling of our recvmsg wrapper @@ -1734,7 +1779,7 @@ pub fn test_recv_ipv6pktinfo() { let (lo_name, lo) = match lo_ifaddr { Some(ifaddr) => ( ifaddr.interface_name, - ifaddr.address.expect("Expect IPv4 address on interface"), + ifaddr.address.expect("Expect IPv6 address on interface"), ), None => return, }; From 885b9430ae806a8e15ab61a0a342371dc85c4790 Mon Sep 17 00:00:00 2001 From: valdaarhun Date: Sat, 16 Jul 2022 00:18:34 +0530 Subject: [PATCH 135/358] Fix description of fchownat --- src/unistd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 6dd0c16463..d3915dccc5 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -758,8 +758,8 @@ pub enum FchownatFlags { /// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link, /// then the mode of the symbolic link is changed. /// -/// `fchownat(None, path, mode, FchownatFlags::NoFollowSymlink)` is identical to -/// a call `libc::lchown(path, mode)`. That's why `lchmod` is unimplemented in +/// `fchownat(None, path, owner, group, FchownatFlags::NoFollowSymlink)` is identical to +/// a call `libc::lchown(path, owner, group)`. That's why `lchown` is unimplemented in /// the `nix` crate. /// /// # References From 12475785ff418e0961a0edeb6a26dc77cb1c0202 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 23 Jul 2022 14:38:41 -0600 Subject: [PATCH 136/358] [skip ci] Add 0.24.2 release notes to CHANGELOG --- CHANGELOG.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ab4181df9..235b1c10bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,17 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1741](https://github.com/nix-rust/nix/pull/1741)) ### Fixed +### Removed + +- Removed support for resubmitting partially complete `lio_listio` operations. + It was too complicated, and didn't fit Nix's theme of zero-cost abstractions. + Instead, it can be reimplemented downstream. + (#[1713](https://github.com/nix-rust/nix/pull/1713)) + +## [0.24.2] - 2022-07-17 +### Added +### Changed +### Fixed - Fixed buffer overflow in nix::sys::socket::recvfrom. (#[1763](https://github.com/nix-rust/nix/pull/1763)) @@ -57,13 +68,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). `SysControlAddr`. (#[1736](https://github.com/nix-rust/nix/pull/1736)) -### Removed - -- Removed support for resubmitting partially complete `lio_listio` operations. - It was too complicated, and didn't fit Nix's theme of zero-cost abstractions. - Instead, it can be reimplemented downstream. - (#[1713](https://github.com/nix-rust/nix/pull/1713)) - ## [0.24.1] - 2022-04-22 ### Added ### Changed From 098aba2c4a4fed68222f7f48dbab72aedd9177d8 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 23 Jul 2022 13:34:33 -0600 Subject: [PATCH 137/358] Fix SockaddrLike::from_raw with unaligned inputs The major users of this function are functions like gethostname, which will always properly align their buffers. But out-of-crate consumers could manually construct an unaligned buffer. Handle that correctly. Enable Clippy's cast_ptr_alignment lint. It's disabled by default as it reports many false positives, but it would've caught this problem. Reported-by: Miri Fixes: 1769 --- src/lib.rs | 1 + src/sys/socket/addr.rs | 45 +++++++++++++++++++++++------------------- src/sys/socket/mod.rs | 1 + 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 689392090b..770258dd36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,7 @@ #![deny(missing_debug_implementations)] #![warn(missing_docs)] #![cfg_attr(docsrs, feature(doc_cfg))] +#![deny(clippy::cast_ptr_alignment)] // Re-exported external crates pub use libc; diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 9d5c61ce32..ad917cd08f 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1195,7 +1195,7 @@ impl SockaddrLike for SockaddrIn { if (*addr).sa_family as i32 != libc::AF_INET as i32 { return None; } - Some(SockaddrIn(*(addr as *const libc::sockaddr_in))) + Some(Self(ptr::read_unaligned(addr as *const _))) } } @@ -1301,7 +1301,7 @@ impl SockaddrLike for SockaddrIn6 { if (*addr).sa_family as i32 != libc::AF_INET6 as i32 { return None; } - Some(SockaddrIn6(*(addr as *const libc::sockaddr_in6))) + Some(Self(ptr::read_unaligned(addr as *const _))) } } @@ -1870,21 +1870,21 @@ impl SockAddr { Some(AddressFamily::Unix) => None, #[cfg(feature = "net")] Some(AddressFamily::Inet) => Some(SockAddr::Inet( - InetAddr::V4(*(addr as *const libc::sockaddr_in)))), + InetAddr::V4(ptr::read_unaligned(addr as *const _)))), #[cfg(feature = "net")] Some(AddressFamily::Inet6) => Some(SockAddr::Inet( - InetAddr::V6(*(addr as *const libc::sockaddr_in6)))), + InetAddr::V6(ptr::read_unaligned(addr as *const _)))), #[cfg(any(target_os = "android", target_os = "linux"))] Some(AddressFamily::Netlink) => Some(SockAddr::Netlink( - NetlinkAddr(*(addr as *const libc::sockaddr_nl)))), + NetlinkAddr(ptr::read_unaligned(addr as *const _)))), #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] Some(AddressFamily::System) => Some(SockAddr::SysControl( - SysControlAddr(*(addr as *const libc::sockaddr_ctl)))), + SysControlAddr(ptr::read_unaligned(addr as *const _)))), #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg(feature = "net")] Some(AddressFamily::Packet) => Some(SockAddr::Link( - LinkAddr(*(addr as *const libc::sockaddr_ll)))), + LinkAddr(ptr::read_unaligned(addr as *const _)))), #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -1894,7 +1894,7 @@ impl SockAddr { target_os = "openbsd"))] #[cfg(feature = "net")] Some(AddressFamily::Link) => { - let ether_addr = LinkAddr(*(addr as *const libc::sockaddr_dl)); + let ether_addr = LinkAddr(ptr::read_unaligned(addr as *const _)); if ether_addr.is_empty() { None } else { @@ -1903,7 +1903,7 @@ impl SockAddr { }, #[cfg(any(target_os = "android", target_os = "linux"))] Some(AddressFamily::Vsock) => Some(SockAddr::Vsock( - VsockAddr(*(addr as *const libc::sockaddr_vm)))), + VsockAddr(ptr::read_unaligned(addr as *const _)))), // Other address families are currently not supported and simply yield a None // entry instead of a proper conversion to a `SockAddr`. Some(_) | None => None, @@ -2104,7 +2104,7 @@ pub mod netlink { if (*addr).sa_family as i32 != libc::AF_NETLINK as i32 { return None; } - Some(NetlinkAddr(*(addr as *const libc::sockaddr_nl))) + Some(Self(ptr::read_unaligned(addr as *const _))) } } @@ -2148,7 +2148,7 @@ pub mod alg { if (*addr).sa_family as i32 != libc::AF_ALG as i32 { return None; } - Some(AlgAddr(*(addr as *const libc::sockaddr_alg))) + Some(Self(ptr::read_unaligned(addr as *const _))) } } @@ -2220,7 +2220,7 @@ feature! { pub mod sys_control { use crate::sys::socket::addr::AddressFamily; use libc::{self, c_uchar}; - use std::{fmt, mem}; + use std::{fmt, mem, ptr}; use std::os::unix::io::RawFd; use crate::{Errno, Result}; use super::{private, SockaddrLike}; @@ -2262,7 +2262,7 @@ pub mod sys_control { if (*addr).sa_family as i32 != libc::AF_SYSTEM as i32 { return None; } - Some(SysControlAddr(*(addr as *const libc::sockaddr_ctl))) + Some(Self(ptr::read_unaligned(addr as *const _))) } } @@ -2329,7 +2329,7 @@ pub mod sys_control { mod datalink { feature! { #![feature = "net"] - use super::{fmt, mem, private, SockaddrLike}; + use super::{fmt, mem, private, ptr, SockaddrLike}; /// Hardware Address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -2405,7 +2405,7 @@ mod datalink { if (*addr).sa_family as i32 != libc::AF_PACKET as i32 { return None; } - Some(LinkAddr(*(addr as *const libc::sockaddr_ll))) + Some(Self(ptr::read_unaligned(addr as *const _))) } } @@ -2430,7 +2430,7 @@ mod datalink { mod datalink { feature! { #![feature = "net"] - use super::{fmt, mem, private, SockaddrLike}; + use super::{fmt, mem, private, ptr, SockaddrLike}; /// Hardware Address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -2525,7 +2525,7 @@ mod datalink { if (*addr).sa_family as i32 != libc::AF_LINK as i32 { return None; } - Some(LinkAddr(*(addr as *const libc::sockaddr_dl))) + Some(Self(ptr::read_unaligned(addr as *const _))) } } @@ -2569,7 +2569,7 @@ pub mod vsock { if (*addr).sa_family as i32 != libc::AF_VSOCK as i32 { return None; } - Some(VsockAddr(*(addr as *const libc::sockaddr_vm))) + Some(Self(ptr::read_unaligned(addr as *const _))) } } @@ -2658,6 +2658,8 @@ mod tests { } mod link { + #![allow(clippy::cast_ptr_alignment)] + use super::*; #[cfg(any(target_os = "ios", target_os = "macos", @@ -2698,8 +2700,11 @@ mod tests { ))] #[test] fn linux_loopback() { - let bytes = [17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0]; - let sa = bytes.as_ptr() as *const libc::sockaddr; + #[repr(align(2))] + struct Raw([u8; 20]); + + let bytes = Raw([17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0]); + let sa = bytes.0.as_ptr() as *const libc::sockaddr; let len = None; let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); assert_eq!(sock_addr.family(), Some(AddressFamily::Packet)); diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 00b2ca703e..e789c116c3 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -949,6 +949,7 @@ impl ControlMessageOwned { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg(feature = "net")] + #[allow(clippy::cast_ptr_alignment)] // False positive unsafe fn recv_err_helper(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option) { let ee = p as *const libc::sock_extended_err; let err = ptr::read_unaligned(ee); From ca2c9208ecff9ae4ad92ed72fc49202f82e0640e Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 23 Jul 2022 13:58:42 -0600 Subject: [PATCH 138/358] Pin cargo-hack to 0.5.14 in CI Newer versions of cargo-hack require a newer toolchain to install --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 9b735cf2b4..49f259a130 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -21,7 +21,7 @@ build: &BUILD - $TOOL +$TOOLCHAIN $BUILD $ZFLAGS --target $TARGET --all-targets - $TOOL +$TOOLCHAIN doc $ZFLAGS --no-deps --target $TARGET - $TOOL +$TOOLCHAIN clippy $ZFLAGS --target $TARGET --all-targets -- -D warnings - - if [ -z "$NOHACK" ]; then $TOOL +$TOOLCHAIN install cargo-hack; fi + - if [ -z "$NOHACK" ]; then $TOOL +$TOOLCHAIN install --version 0.5.14 cargo-hack; fi - if [ -z "$NOHACK" ]; then $TOOL +$TOOLCHAIN hack $ZFLAGS check --target $TARGET --each-feature; fi # Tests that do require executing the binaries From 1040d970366100ce766eb8cb6af2c7453ffcdb6a Mon Sep 17 00:00:00 2001 From: valdaarhun Date: Sat, 23 Jul 2022 01:32:57 +0530 Subject: [PATCH 139/358] Add ETH_P_ALL protocol number to SockProtocol Add note to Changelog.md Make changes in comments Co-authored-by: Alan Somers Add Android as target os for ETH_P_ALL --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 235b1c10bd..f9e7f6dcd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added ETH_P_ALL to SockProtocol enum + (#[1768](https://github.com/nix-rust/nix/pull/1768)) - Added four non-standard Linux `SysconfVar` variants (#[1761](https://github.com/nix-rust/nix/pull/1761)) - Added const constructors for `TimeSpec` and `TimeVal` diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index e789c116c3..e937e65204 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -214,6 +214,13 @@ pub enum SockProtocol { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkCrypto = libc::NETLINK_CRYPTO, + /// Non-DIX type protocol number defined for the Ethernet IEEE 802.3 interface that allows packets of all protocols + /// defined in the interface to be received. + /// ([ref](https://man7.org/linux/man-pages/man7/packet.7.html)) + // The protocol number is fed into the socket syscall in network byte order. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + EthAll = libc::ETH_P_ALL.to_be(), } #[cfg(any(target_os = "linux"))] From e357d60cde1c3cf04ac4c17d33e5056c15028459 Mon Sep 17 00:00:00 2001 From: Felix Obenhuber Date: Mon, 25 Jul 2022 08:56:48 +0200 Subject: [PATCH 140/358] Add memfd for target_os = "android" Memory fds (`memfd`) are implemented and exported by Androids bionic. Export the `memfd` module if the target os is `android`. https://cs.android.com/android/platform/superproject/+/master:bionic/libc/include/sys/mman.h;drc=23c7543b8e608ebcbb38b952761b54bb56065577;bpv=1;bpt=1;l=182 --- CHANGELOG.md | 2 ++ src/sys/mod.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9e7f6dcd6..6609e11428 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added `memfd` on Android. + (#[1773](https://github.com/nix-rust/nix/pull/1773)) - Added ETH_P_ALL to SockProtocol enum (#[1768](https://github.com/nix-rust/nix/pull/1768)) - Added four non-standard Linux `SysconfVar` variants diff --git a/src/sys/mod.rs b/src/sys/mod.rs index ddd4fdfc3b..80c75e1fb9 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -50,7 +50,7 @@ feature! { #[macro_use] pub mod ioctl; -#[cfg(target_os = "linux")] +#[cfg(any(target_is = "android", target_os = "linux"))] feature! { #![feature = "fs"] pub mod memfd; From c45cd74f42d896bf5f7ae37736e6e44ab5dd3ce9 Mon Sep 17 00:00:00 2001 From: Brian May Date: Sun, 24 Jul 2022 09:31:19 +1000 Subject: [PATCH 141/358] Add support for RecvOrigDstAddr on Linux Fixes #1767 --- CHANGELOG.md | 4 + src/sys/socket/mod.rs | 20 +++++ src/sys/socket/sockopt.rs | 14 ++++ test/sys/test_socket.rs | 170 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 235b1c10bd..c720d165b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1752](https://github.com/nix-rust/nix/pull/1752)) - Added `signal::SigSet::from_sigset_t_unchecked()`. (#[1741](https://github.com/nix-rust/nix/pull/1741)) +- Added IP_ORIGDSTADDR using Ipv4OrigDstAddr in setsockopt and recvmsg. + (#[1772](https://github.com/nix-rust/nix/pull/1772)) +- Added IPV6_ORIGDSTADDR using Ipv6OrigDstAddr in setsockopt and recvmsg. + (#[1772](https://github.com/nix-rust/nix/pull/1772)) ### Changed diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index e789c116c3..88378b1783 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -757,6 +757,14 @@ pub enum ControlMessageOwned { #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv4RecvDstAddr(libc::in_addr), + #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv4OrigDstAddr(libc::sockaddr_in), + #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv6OrigDstAddr(libc::sockaddr_in6), /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP /// packets from a single sender. @@ -916,6 +924,12 @@ impl ControlMessageOwned { let dl = ptr::read_unaligned(p as *const libc::in_addr); ControlMessageOwned::Ipv4RecvDstAddr(dl) }, + #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(feature = "net")] + (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => { + let dl = ptr::read_unaligned(p as *const libc::sockaddr_in); + ControlMessageOwned::Ipv4OrigDstAddr(dl) + }, #[cfg(target_os = "linux")] #[cfg(feature = "net")] (libc::SOL_UDP, libc::UDP_GRO) => { @@ -939,6 +953,12 @@ impl ControlMessageOwned { let (err, addr) = Self::recv_err_helper::(p, len); ControlMessageOwned::Ipv6RecvErr(err, addr) }, + #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] + #[cfg(feature = "net")] + (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => { + let dl = ptr::read_unaligned(p as *const libc::sockaddr_in6); + ControlMessageOwned::Ipv6OrigDstAddr(dl) + }, (_, _) => { let sl = slice::from_raw_parts(p, len); let ucmsg = UnknownCmsg(*header, Vec::::from(sl)); diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 8f85748f20..fff496dbbd 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -574,6 +574,13 @@ sockopt_impl!( /// The `recvmsg(2)` call will return the destination IP address for a UDP /// datagram. Ipv4RecvDstAddr, Both, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool); +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// The `recvmsg(2)` call will return the destination IP address for a UDP + /// datagram. + Ipv4OrigDstAddr, Both, libc::IPPROTO_IP, libc::IP_ORIGDSTADDR, bool); #[cfg(target_os = "linux")] #[cfg(feature = "net")] sockopt_impl!( @@ -621,6 +628,13 @@ sockopt_impl!( sockopt_impl!( /// Set the unicast hop limit for the socket. Ipv6Ttl, Both, libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS, libc::c_int); +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// The `recvmsg(2)` call will return the destination IP address for a UDP + /// datagram. + Ipv6OrigDstAddr, Both, libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR, bool); #[cfg(any(target_os = "ios", target_os = "macos"))] sockopt_impl!( /// Set "don't fragment packet" flag on the IP packet. diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 56819c9f0d..0a74b5e1e4 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1745,6 +1745,176 @@ pub fn test_recvif() { } } +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg_attr(qemu, ignore)] +#[test] +pub fn test_recvif_ipv4() { + use nix::sys::socket::sockopt::Ipv4OrigDstAddr; + use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn}; + use nix::sys::socket::{getsockname, setsockopt, socket}; + use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; + use std::io::{IoSlice, IoSliceMut}; + + let lo_ifaddr = loopback_address(AddressFamily::Inet); + let (_lo_name, lo) = match lo_ifaddr { + Some(ifaddr) => ( + ifaddr.interface_name, + ifaddr.address.expect("Expect IPv4 address on interface"), + ), + None => return, + }; + let receive = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("receive socket failed"); + bind(receive, &lo).expect("bind failed"); + let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); + setsockopt(receive, Ipv4OrigDstAddr, &true) + .expect("setsockopt IP_ORIGDSTADDR failed"); + + { + let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let iov = [IoSlice::new(&slice)]; + + let send = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + .expect("sendmsg failed"); + } + + { + let mut buf = [0u8; 8]; + let mut iovec = [IoSliceMut::new(&mut buf)]; + let mut space = cmsg_space!(libc::sockaddr_in); + let msg = recvmsg::<()>( + receive, + &mut iovec, + Some(&mut space), + MsgFlags::empty(), + ) + .expect("recvmsg failed"); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + assert_eq!(msg.cmsgs().count(), 1, "expected 1 cmsgs"); + + let mut rx_recvorigdstaddr = false; + for cmsg in msg.cmsgs() { + match cmsg { + ControlMessageOwned::Ipv4OrigDstAddr(addr) => { + rx_recvorigdstaddr = true; + if let Some(sin) = lo.as_sockaddr_in() { + assert_eq!(sin.as_ref().sin_addr.s_addr, + addr.sin_addr.s_addr, + "unexpected destination address (expected {}, got {})", + sin.as_ref().sin_addr.s_addr, + addr.sin_addr.s_addr); + } else { + panic!("unexpected Sockaddr"); + } + } + _ => panic!("unexpected additional control msg"), + } + } + assert!(rx_recvorigdstaddr); + assert_eq!(msg.bytes, 8); + assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); + } +} + +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +#[cfg_attr(qemu, ignore)] +#[test] +pub fn test_recvif_ipv6() { + use nix::sys::socket::sockopt::Ipv6OrigDstAddr; + use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6}; + use nix::sys::socket::{getsockname, setsockopt, socket}; + use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; + use std::io::{IoSlice, IoSliceMut}; + + let lo_ifaddr = loopback_address(AddressFamily::Inet6); + let (_lo_name, lo) = match lo_ifaddr { + Some(ifaddr) => ( + ifaddr.interface_name, + ifaddr.address.expect("Expect IPv6 address on interface"), + ), + None => return, + }; + let receive = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("receive socket failed"); + bind(receive, &lo).expect("bind failed"); + let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed"); + setsockopt(receive, Ipv6OrigDstAddr, &true) + .expect("setsockopt IP_ORIGDSTADDR failed"); + + { + let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let iov = [IoSlice::new(&slice)]; + + let send = socket( + AddressFamily::Inet6, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("send socket failed"); + sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + .expect("sendmsg failed"); + } + + { + let mut buf = [0u8; 8]; + let mut iovec = [IoSliceMut::new(&mut buf)]; + let mut space = cmsg_space!(libc::sockaddr_in6); + let msg = recvmsg::<()>( + receive, + &mut iovec, + Some(&mut space), + MsgFlags::empty(), + ) + .expect("recvmsg failed"); + assert!(!msg + .flags + .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); + assert_eq!(msg.cmsgs().count(), 1, "expected 1 cmsgs"); + + let mut rx_recvorigdstaddr = false; + for cmsg in msg.cmsgs() { + match cmsg { + ControlMessageOwned::Ipv6OrigDstAddr(addr) => { + rx_recvorigdstaddr = true; + if let Some(sin) = lo.as_sockaddr_in6() { + assert_eq!(sin.as_ref().sin6_addr.s6_addr, + addr.sin6_addr.s6_addr, + "unexpected destination address (expected {:?}, got {:?})", + sin.as_ref().sin6_addr.s6_addr, + addr.sin6_addr.s6_addr); + } else { + panic!("unexpected Sockaddr"); + } + } + _ => panic!("unexpected additional control msg"), + } + } + assert!(rx_recvorigdstaddr); + assert_eq!(msg.bytes, 8); + assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]); + } +} + #[cfg(any( target_os = "android", target_os = "freebsd", From 4e3426f27e27219610c9f12920b8e1461d83984f Mon Sep 17 00:00:00 2001 From: Jason Heeris Date: Tue, 26 Jul 2022 10:34:56 +0800 Subject: [PATCH 142/358] Fix typo guarding memfd export on android. --- src/sys/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 80c75e1fb9..979d623b89 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -50,7 +50,7 @@ feature! { #[macro_use] pub mod ioctl; -#[cfg(any(target_is = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "linux"))] feature! { #![feature = "fs"] pub mod memfd; From a6ee63ac3212e62518c97252581cfa48e2ad056e Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Thu, 4 Aug 2022 07:54:45 +0800 Subject: [PATCH 143/358] fix clippy assertions_on_result_states https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_result_states --- src/sys/signal.rs | 6 +++--- src/sys/signalfd.rs | 9 ++++++--- src/sys/termios.rs | 4 ++-- test/sys/test_aio.rs | 14 +++++++------- test/sys/test_epoll.rs | 4 ++-- test/sys/test_socket.rs | 2 +- test/sys/test_termios.rs | 2 +- test/sys/test_uio.rs | 35 ++++++++++------------------------- test/sys/test_wait.rs | 24 ++++++++++++------------ test/test_fcntl.rs | 6 ++---- test/test_net.rs | 2 +- test/test_stat.rs | 4 ++-- test/test_time.rs | 15 ++++++++------- test/test_unistd.rs | 30 +++++++++++++++++------------- 14 files changed, 74 insertions(+), 83 deletions(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 4a468b62c5..0da9c74ad6 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -1189,7 +1189,7 @@ mod tests { let mut test_mask = prev_mask; test_mask.add(SIGUSR1); - assert!(test_mask.thread_set_mask().is_ok()); + test_mask.thread_set_mask().expect("assertion failed"); let new_mask = SigSet::thread_get_mask().expect("Failed to get new mask!"); @@ -1211,7 +1211,7 @@ mod tests { let mut mask = SigSet::empty(); mask.add(SIGUSR1); - assert!(mask.thread_block().is_ok()); + mask.thread_block().expect("assertion failed"); assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); }) @@ -1226,7 +1226,7 @@ mod tests { let mut mask = SigSet::empty(); mask.add(SIGUSR1); - assert!(mask.thread_unblock().is_ok()); + mask.thread_unblock().expect("assertion failed"); assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1)); }) diff --git a/src/sys/signalfd.rs b/src/sys/signalfd.rs index bc4a452243..3d82b5ba5a 100644 --- a/src/sys/signalfd.rs +++ b/src/sys/signalfd.rs @@ -148,14 +148,17 @@ mod tests { fn create_signalfd() { let mask = SigSet::empty(); let fd = SignalFd::new(&mask); - assert!(fd.is_ok()); + fd.expect("assert failed"); } #[test] fn create_signalfd_with_opts() { let mask = SigSet::empty(); - let fd = SignalFd::with_flags(&mask, SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK); - assert!(fd.is_ok()); + let fd = SignalFd::with_flags( + &mask, + SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK, + ); + fd.expect("assert failed"); } #[test] diff --git a/src/sys/termios.rs b/src/sys/termios.rs index 2e1b53d7c9..feb52c0ab9 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -1107,8 +1107,8 @@ mod test { fn try_from() { assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0)); #[cfg(not(target_os = "haiku"))] - assert!(BaudRate::try_from(999999999).is_err()); + BaudRate::try_from(999999999).expect_err("assertion failed"); #[cfg(target_os = "haiku")] - assert!(BaudRate::try_from(99).is_err()); + BaudRate::try_from(99).expect_err("assertion failed"); } } diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index b4ea6757d9..12749b1d59 100644 --- a/test/sys/test_aio.rs +++ b/test/sys/test_aio.rs @@ -85,7 +85,7 @@ mod aio_fsync { SigevNotify::SigevNone, )); let err = aiof.as_mut().submit(); - assert!(err.is_err()); + err.expect_err("assertion failed"); } #[test] @@ -102,7 +102,7 @@ mod aio_fsync { SigevNotify::SigevNone, )); let err = aiof.as_mut().submit(); - assert!(err.is_ok()); + err.expect("assert failed"); poll_aio!(&mut aiof).unwrap(); aiof.as_mut().aio_return().unwrap(); } @@ -149,7 +149,7 @@ mod aio_read { aior.as_mut().submit().unwrap(); let cancelstat = aior.as_mut().cancel(); - assert!(cancelstat.is_ok()); + cancelstat.expect("assert failed"); // Wait for aiow to complete, but don't care whether it succeeded let _ = poll_aio!(&mut aior); @@ -174,7 +174,7 @@ mod aio_read { 0, //priority SigevNotify::SigevNone, )); - assert!(aior.as_mut().submit().is_err()); + aior.as_mut().submit().expect_err("assertion failed"); } // Test a simple aio operation with no completion notification. We must @@ -342,7 +342,7 @@ mod aio_write { assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); let cancelstat = aiow.as_mut().cancel(); - assert!(cancelstat.is_ok()); + cancelstat.expect("assert failed"); // Wait for aiow to complete, but don't care whether it succeeded let _ = poll_aio!(&mut aiow); @@ -426,7 +426,7 @@ mod aio_write { 0, //priority SigevNotify::SigevNone, )); - assert!(aiow.as_mut().submit().is_err()); + aiow.as_mut().submit().expect_err("assertion failed"); // Dropping the AioWrite at this point should not panic } } @@ -565,7 +565,7 @@ fn test_aio_cancel_all() { assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); let cancelstat = aio_cancel_all(f.as_raw_fd()); - assert!(cancelstat.is_ok()); + cancelstat.expect("assert failed"); // Wait for aiocb to complete, but don't care whether it succeeded let _ = poll_aio!(&mut aiocb); diff --git a/test/sys/test_epoll.rs b/test/sys/test_epoll.rs index fafbd7499d..915691595c 100644 --- a/test/sys/test_epoll.rs +++ b/test/sys/test_epoll.rs @@ -6,11 +6,11 @@ use nix::sys::epoll::{EpollCreateFlags, EpollEvent, EpollFlags, EpollOp}; pub fn test_epoll_errno() { let efd = epoll_create1(EpollCreateFlags::empty()).unwrap(); let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None); - assert!(result.is_err()); + result.expect_err("assertion failed"); assert_eq!(result.unwrap_err(), Errno::ENOENT); let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None); - assert!(result.is_err()); + result.expect_err("assertion failed"); assert_eq!(result.unwrap_err(), Errno::EINVAL); } diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 0a74b5e1e4..06d5b76166 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -204,7 +204,7 @@ pub fn test_addr_equality_path() { pub fn test_abstract_sun_path_too_long() { let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough"); let addr = UnixAddr::new_abstract(name.as_bytes()); - assert!(addr.is_err()); + addr.expect_err("assertion failed"); } #[cfg(any(target_os = "android", target_os = "linux"))] diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs index e567a52c07..11a08cb5f8 100644 --- a/test/sys/test_termios.rs +++ b/test/sys/test_termios.rs @@ -22,7 +22,7 @@ fn test_tcgetattr_pty() { let _m = crate::PTSNAME_MTX.lock(); let pty = openpty(None, None).expect("openpty failed"); - assert!(termios::tcgetattr(pty.slave).is_ok()); + termios::tcgetattr(pty.slave).expect("assert failed"); close(pty.master).expect("closing the master failed"); close(pty.slave).expect("closing the slave failed"); } diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index f46b1940c0..0f4b8a6568 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -41,29 +41,22 @@ fn test_writev() { consumed += slice_len; } let pipe_res = pipe(); - assert!(pipe_res.is_ok()); - let (reader, writer) = pipe_res.ok().unwrap(); + let (reader, writer) = pipe_res.expect("Couldn't create pipe"); // FileDesc will close its filedesc (reader). let mut read_buf: Vec = iter::repeat(0u8).take(128 * 16).collect(); // Blocking io, should write all data. let write_res = writev(writer, &iovecs); - // Successful write - assert!(write_res.is_ok()); - let written = write_res.ok().unwrap(); + let written = write_res.expect("couldn't write"); // Check whether we written all data assert_eq!(to_write.len(), written); let read_res = read(reader, &mut read_buf[..]); - // Successful read - assert!(read_res.is_ok()); - let read = read_res.ok().unwrap() as usize; + let read = read_res.expect("couldn't read"); // Check we have read as much as we written assert_eq!(read, written); // Check equality of written and read data assert_eq!(&to_write, &read_buf); - let close_res = close(writer); - assert!(close_res.is_ok()); - let close_res = close(reader); - assert!(close_res.is_ok()); + close(writer).expect("closed writer"); + close(reader).expect("closed reader"); } #[test] @@ -92,16 +85,10 @@ fn test_readv() { for v in &mut storage { iovecs.push(IoSliceMut::new(&mut v[..])); } - let pipe_res = pipe(); - assert!(pipe_res.is_ok()); - let (reader, writer) = pipe_res.ok().unwrap(); + let (reader, writer) = pipe().expect("couldn't create pipe"); // Blocking io, should write all data. - let write_res = write(writer, &to_write); - // Successful write - assert!(write_res.is_ok()); - let read_res = readv(reader, &mut iovecs[..]); - assert!(read_res.is_ok()); - let read = read_res.ok().unwrap(); + write(writer, &to_write).expect("write failed"); + let read = readv(reader, &mut iovecs[..]).expect("read failed"); // Check whether we've read all data assert_eq!(to_write.len(), read); // Cccumulate data from iovecs @@ -113,10 +100,8 @@ fn test_readv() { assert_eq!(read_buf.len(), to_write.len()); // Check equality of written and read data assert_eq!(&read_buf, &to_write); - let close_res = close(reader); - assert!(close_res.is_ok()); - let close_res = close(writer); - assert!(close_res.is_ok()); + close(reader).expect("couldn't close reader"); + close(writer).expect("couldn't close writer"); } #[test] diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs index 1a4a0f879e..d472f1ec19 100644 --- a/test/sys/test_wait.rs +++ b/test/sys/test_wait.rs @@ -167,17 +167,17 @@ mod ptrace { Ok(WaitStatus::Stopped(child, SIGTRAP)) ); // We want to test a syscall stop and a PTRACE_EVENT stop - assert!(ptrace::setoptions( + ptrace::setoptions( child, - Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT + Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT, ) - .is_ok()); + .expect("setoptions failed"); // First, stop on the next system call, which will be exit() - assert!(ptrace::syscall(child, None).is_ok()); + ptrace::syscall(child, None).expect("syscall failed"); assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); // Then get the ptrace event for the process exiting - assert!(ptrace::cont(child, None).is_ok()); + ptrace::cont(child, None).expect("cont failed"); assert_eq!( waitpid(child, None), Ok(WaitStatus::PtraceEvent( @@ -187,7 +187,7 @@ mod ptrace { )) ); // Finally get the normal wait() result, now that the process has exited - assert!(ptrace::cont(child, None).is_ok()); + ptrace::cont(child, None).expect("cont failed"); assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0))); } @@ -202,20 +202,20 @@ mod ptrace { Ok(WaitStatus::PtraceEvent(child, SIGTRAP, 0)), ); // We want to test a syscall stop and a PTRACE_EVENT stop - assert!(ptrace::setoptions( + ptrace::setoptions( child, - Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT + Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT, ) - .is_ok()); + .expect("setopts failed"); // First, stop on the next system call, which will be exit() - assert!(ptrace::syscall(child, None).is_ok()); + ptrace::syscall(child, None).expect("syscall failed"); assert_eq!( waitid(Id::Pid(child), WaitPidFlag::WEXITED), Ok(WaitStatus::PtraceSyscall(child)), ); // Then get the ptrace event for the process exiting - assert!(ptrace::cont(child, None).is_ok()); + ptrace::cont(child, None).expect("cont failed"); assert_eq!( waitid(Id::Pid(child), WaitPidFlag::WEXITED), Ok(WaitStatus::PtraceEvent( @@ -225,7 +225,7 @@ mod ptrace { )), ); // Finally get the normal wait() result, now that the process has exited - assert!(ptrace::cont(child, None).is_ok()); + ptrace::cont(child, None).expect("cont failed"); assert_eq!( waitid(Id::Pid(child), WaitPidFlag::WEXITED), Ok(WaitStatus::Exited(child, 0)), diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index d4a12718d9..f4adee21fc 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -492,10 +492,8 @@ mod test_posix_fadvise { fn test_success() { let tmp = NamedTempFile::new().unwrap(); let fd = tmp.as_raw_fd(); - let res = - posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED); - - assert!(res.is_ok()); + posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED) + .expect("posix_fadvise failed"); } #[test] diff --git a/test/test_net.rs b/test/test_net.rs index d1050c16d7..c44655a4c9 100644 --- a/test/test_net.rs +++ b/test/test_net.rs @@ -15,5 +15,5 @@ const LOOPBACK: &[u8] = b"loop"; #[test] fn test_if_nametoindex() { - assert!(if_nametoindex(LOOPBACK).is_ok()); + if_nametoindex(LOOPBACK).expect("assertion failed"); } diff --git a/test/test_stat.rs b/test/test_stat.rs index de5a964ec7..1888c64914 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -323,7 +323,7 @@ fn test_mkdirat_success_path() { let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) .unwrap(); - assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok()); + mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); assert!(Path::exists(&tempdir.path().join(filename))); } @@ -337,7 +337,7 @@ fn test_mkdirat_success_mode() { let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()) .unwrap(); - assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok()); + mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed"); let permissions = fs::metadata(tempdir.path().join(filename)) .unwrap() .permissions(); diff --git a/test/test_time.rs b/test/test_time.rs index dc307e57b3..3e8af653dc 100644 --- a/test/test_time.rs +++ b/test/test_time.rs @@ -11,12 +11,12 @@ use nix::time::{clock_gettime, ClockId}; #[cfg(not(target_os = "redox"))] #[test] pub fn test_clock_getres() { - assert!(nix::time::clock_getres(ClockId::CLOCK_REALTIME).is_ok()); + nix::time::clock_getres(ClockId::CLOCK_REALTIME).expect("assertion failed"); } #[test] pub fn test_clock_gettime() { - assert!(clock_gettime(ClockId::CLOCK_REALTIME).is_ok()); + clock_gettime(ClockId::CLOCK_REALTIME).expect("assertion failed"); } #[cfg(any( @@ -29,18 +29,18 @@ pub fn test_clock_gettime() { #[test] pub fn test_clock_getcpuclockid() { let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap(); - assert!(clock_gettime(clock_id).is_ok()); + clock_gettime(clock_id).expect("assert failed"); } #[cfg(not(target_os = "redox"))] #[test] pub fn test_clock_id_res() { - assert!(ClockId::CLOCK_REALTIME.res().is_ok()); + ClockId::CLOCK_REALTIME.res().expect("assert failed"); } #[test] pub fn test_clock_id_now() { - assert!(ClockId::CLOCK_REALTIME.now().is_ok()); + ClockId::CLOCK_REALTIME.now().expect("assert failed"); } #[cfg(any( @@ -52,7 +52,8 @@ pub fn test_clock_id_now() { ))] #[test] pub fn test_clock_id_pid_cpu_clock_id() { - assert!(ClockId::pid_cpu_clock_id(nix::unistd::Pid::this()) + ClockId::pid_cpu_clock_id(nix::unistd::Pid::this()) .map(ClockId::now) - .is_ok()); + .expect("assert failed") + .expect("assert failed"); } diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 38d31a3fd5..337ebe4672 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -101,7 +101,7 @@ fn test_mkstemp() { #[test] fn test_mkstemp_directory() { // mkstemp should fail if a directory is given - assert!(mkstemp(&env::temp_dir()).is_err()); + mkstemp(&env::temp_dir()).expect_err("assertion failed"); } #[test] @@ -121,7 +121,7 @@ fn test_mkfifo() { #[cfg(not(target_os = "redox"))] fn test_mkfifo_directory() { // mkfifo should fail if a directory is given - assert!(mkfifo(&env::temp_dir(), Mode::S_IRUSR).is_err()); + mkfifo(&env::temp_dir(), Mode::S_IRUSR).expect_err("assertion failed"); } #[test] @@ -180,7 +180,8 @@ fn test_mkfifoat_directory_none() { let _m = crate::CWD_LOCK.read(); // mkfifoat should fail if a directory is given - assert!(mkfifoat(None, &env::temp_dir(), Mode::S_IRUSR).is_err()); + mkfifoat(None, &env::temp_dir(), Mode::S_IRUSR) + .expect_err("assertion failed"); } #[test] @@ -198,7 +199,8 @@ fn test_mkfifoat_directory() { let mkfifoat_dir = "mkfifoat_dir"; stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap(); - assert!(mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR).is_err()); + mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR) + .expect_err("assertion failed"); } #[test] @@ -456,10 +458,10 @@ fn test_fchdir() { let tmpdir_path = tmpdir.path().canonicalize().unwrap(); let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd(); - assert!(fchdir(tmpdir_fd).is_ok()); + fchdir(tmpdir_fd).expect("assertion failed"); assert_eq!(getcwd().unwrap(), tmpdir_path); - assert!(close(tmpdir_fd).is_ok()); + close(tmpdir_fd).expect("assertion failed"); } #[test] @@ -469,7 +471,7 @@ fn test_getcwd() { let tmpdir = tempdir().unwrap(); let tmpdir_path = tmpdir.path().canonicalize().unwrap(); - assert!(chdir(&tmpdir_path).is_ok()); + chdir(&tmpdir_path).expect("assertion failed"); assert_eq!(getcwd().unwrap(), tmpdir_path); // make path 500 chars longer so that buffer doubling in getcwd @@ -480,9 +482,10 @@ fn test_getcwd() { for _ in 0..5 { let newdir = "a".repeat(100); inner_tmp_dir.push(newdir); - assert!(mkdir(inner_tmp_dir.as_path(), Mode::S_IRWXU).is_ok()); + mkdir(inner_tmp_dir.as_path(), Mode::S_IRWXU) + .expect("assertion failed"); } - assert!(chdir(inner_tmp_dir.as_path()).is_ok()); + chdir(inner_tmp_dir.as_path()).expect("assertion failed"); assert_eq!(getcwd().unwrap(), inner_tmp_dir.as_path()); } @@ -1166,7 +1169,8 @@ fn test_access_file_exists() { let tempdir = tempdir().unwrap(); let path = tempdir.path().join("does_exist.txt"); let _file = File::create(path.clone()).unwrap(); - assert!(access(&path, AccessFlags::R_OK | AccessFlags::W_OK).is_ok()); + access(&path, AccessFlags::R_OK | AccessFlags::W_OK) + .expect("assertion failed"); } //Clippy false positive https://github.com/rust-lang/rust-clippy/issues/9111 @@ -1210,8 +1214,8 @@ fn test_setfsuid() { let fuid = setfsuid(nobody.uid); // trying to open the temporary file should fail with EACCES let res = fs::File::open(&temp_path); - assert!(res.is_err()); - assert_eq!(res.err().unwrap().kind(), io::ErrorKind::PermissionDenied); + let err = res.expect_err("assertion failed"); + assert_eq!(err.kind(), io::ErrorKind::PermissionDenied); // assert fuid actually changes let prev_fuid = setfsuid(Uid::from_raw(-1i32 as u32)); @@ -1302,5 +1306,5 @@ fn test_getpeereid() { ))] fn test_getpeereid_invalid_fd() { // getpeereid is not POSIX, so error codes are inconsistent between different Unices. - assert!(getpeereid(-1).is_err()); + getpeereid(-1).expect_err("assertion failed"); } From cac1486f17ff350a4c6035cc2eec6a587ba51c3f Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Wed, 3 Aug 2022 22:58:22 -0500 Subject: [PATCH 144/358] Upgrade libc to 0.2.127 This is the last version of libc which will support Rust 1.46, per https://github.com/rust-lang/libc/pull/2845 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4214b16e5e..18e1742d76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { git = "https://github.com/rust-lang/libc", rev = "8dbd2c9", features = [ "extra_traits" ] } +libc = { version = "0.2.127", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } From 6bf07fdbb9e77984bd1c4f080d41a85ff821a2cb Mon Sep 17 00:00:00 2001 From: Matthew Ingwersen Date: Sun, 31 Jul 2022 22:24:22 +0000 Subject: [PATCH 145/358] Add support for the IP_SENDSRCADDR control message This control message (actually just an alias for IP_RECVDSTADDR) sets the IPv4 source address when used with sendmsg. It is available on FreeBSD, NetBSD, OpenBSD, and DragonFlyBSD. --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 27 +++++++++++++++++++++ test/sys/test_socket.rs | 52 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfe811971c..96de857eec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1772](https://github.com/nix-rust/nix/pull/1772)) - Added IPV6_ORIGDSTADDR using Ipv6OrigDstAddr in setsockopt and recvmsg. (#[1772](https://github.com/nix-rust/nix/pull/1772)) +- Added `IP_SENDSRCADDR` using `Ipv4SendSrcAddr` in `sendmsg`. + (#[1776](https://github.com/nix-rust/nix/pull/1776)) ### Changed diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 2dfa8ec6e6..a853777838 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1117,6 +1117,17 @@ pub enum ControlMessage<'a> { #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Ipv6PacketInfo(&'a libc::in6_pktinfo), + /// Configure the IPv4 source address with `IP_SENDSRCADDR`. + #[cfg(any( + target_os = "netbsd", + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + ))] + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + Ipv4SendSrcAddr(&'a libc::in_addr), + /// SO_RXQ_OVFL indicates that an unsigned 32 bit value /// ancilliary msg (cmsg) should be attached to recieved /// skbs indicating the number of packets dropped by the @@ -1226,6 +1237,10 @@ impl<'a> ControlMessage<'a> { target_os = "android", target_os = "ios",))] #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8, + #[cfg(any(target_os = "netbsd", target_os = "freebsd", + target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(feature = "net")] + ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8, #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] ControlMessage::RxqOvfl(drop_count) => { drop_count as *const _ as *const u8 @@ -1285,6 +1300,10 @@ impl<'a> ControlMessage<'a> { target_os = "android", target_os = "ios",))] #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info), + #[cfg(any(target_os = "netbsd", target_os = "freebsd", + target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(feature = "net")] + ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr), #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] ControlMessage::RxqOvfl(drop_count) => { mem::size_of_val(drop_count) @@ -1320,6 +1339,10 @@ impl<'a> ControlMessage<'a> { target_os = "android", target_os = "ios",))] #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6, + #[cfg(any(target_os = "netbsd", target_os = "freebsd", + target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(feature = "net")] + ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP, #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET, #[cfg(target_os = "linux")] @@ -1362,6 +1385,10 @@ impl<'a> ControlMessage<'a> { target_os = "android", target_os = "ios",))] #[cfg(feature = "net")] ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO, + #[cfg(any(target_os = "netbsd", target_os = "freebsd", + target_os = "openbsd", target_os = "dragonfly"))] + #[cfg(feature = "net")] + ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR, #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] ControlMessage::RxqOvfl(_) => { libc::SO_RXQ_OVFL diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 06d5b76166..b4ca279d67 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1122,6 +1122,58 @@ pub fn test_sendmsg_ipv6packetinfo() { .expect("sendmsg"); } +// Verify that ControlMessage::Ipv4SendSrcAddr works for sendmsg. This +// creates a UDP socket bound to all local interfaces (0.0.0.0). It then +// sends message to itself at 127.0.0.1 while explicitly specifying +// 127.0.0.1 as the source address through an Ipv4SendSrcAddr +// (IP_SENDSRCADDR) control message. +// +// Note that binding to 0.0.0.0 is *required* on FreeBSD; sendmsg +// returns EINVAL otherwise. (See FreeBSD's ip(4) man page.) +#[cfg(any( + target_os = "netbsd", + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", +))] +#[test] +pub fn test_sendmsg_ipv4sendsrcaddr() { + use nix::sys::socket::{ + bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags, + SockFlag, SockType, SockaddrIn, + }; + use std::io::IoSlice; + + let sock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + + let unspec_sock_addr = SockaddrIn::new(0, 0, 0, 0, 0); + bind(sock, &unspec_sock_addr).expect("bind failed"); + let bound_sock_addr: SockaddrIn = getsockname(sock).unwrap(); + let localhost_sock_addr: SockaddrIn = + SockaddrIn::new(127, 0, 0, 1, bound_sock_addr.port()); + + let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let iov = [IoSlice::new(&slice)]; + let cmsg = [ControlMessage::Ipv4SendSrcAddr( + &localhost_sock_addr.as_ref().sin_addr, + )]; + + sendmsg( + sock, + &iov, + &cmsg, + MsgFlags::empty(), + Some(&localhost_sock_addr), + ) + .expect("sendmsg"); +} + /// 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 From f8c79c63e5b2779f4b1d4f5e113541cadb51b32f Mon Sep 17 00:00:00 2001 From: Zhang Miaolei Date: Mon, 30 Sep 2019 18:38:27 +0800 Subject: [PATCH 146/358] add faccessat --- CHANGELOG.md | 2 ++ src/unistd.rs | 21 ++++++++++++++ test/test_unistd.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfe811971c..f00b801cc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added `faccessat` + ([#1780](https://github.com/nix-rust/nix/pull/1780)) - Added `memfd` on Android. (#[1773](https://github.com/nix-rust/nix/pull/1773)) - Added ETH_P_ALL to SockProtocol enum diff --git a/src/unistd.rs b/src/unistd.rs index d3915dccc5..70a06b0286 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2900,6 +2900,27 @@ pub fn access(path: &P, amode: AccessFlags) -> Result<()> { })?; Errno::result(res).map(drop) } + +/// Checks the file named by `path` for accessibility according to the flags given by `mode` +/// +/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor. +/// +/// If `dirfd` is `None`, then `path` is relative to the current working directory. +/// +/// # References +/// +/// [faccessat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html) +// illumos: faccessat(2) appears to be supported, but the libc crate does not provide a binding. +// redox: does not appear to support the *at family of syscalls. +#[cfg(not(any(target_os = "illumos", target_os = "redox")))] +pub fn faccessat(dirfd: Option, path: &P, mode: AccessFlags, flags: AtFlags) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { + libc::faccessat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits(), flags.bits()) + } + })?; + Errno::result(res).map(drop) +} } feature! { diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 337ebe4672..b08ab33257 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -1308,3 +1308,71 @@ fn test_getpeereid_invalid_fd() { // getpeereid is not POSIX, so error codes are inconsistent between different Unices. getpeereid(-1).expect_err("assertion failed"); } + +#[test] +#[cfg(not(any(target_os = "illumos", target_os = "redox")))] +fn test_faccessat_none_not_existing() { + use nix::fcntl::AtFlags; + let tempdir = tempfile::tempdir().unwrap(); + let dir = tempdir.path().join("does_not_exist.txt"); + assert_eq!( + faccessat(None, &dir, AccessFlags::F_OK, AtFlags::empty()) + .err() + .unwrap(), + Errno::ENOENT + ); +} + +#[test] +#[cfg(not(any(target_os = "illumos", target_os = "redox")))] +fn test_faccessat_not_existing() { + use nix::fcntl::AtFlags; + let tempdir = tempfile::tempdir().unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let not_exist_file = "does_not_exist.txt"; + assert_eq!( + faccessat( + Some(dirfd), + not_exist_file, + AccessFlags::F_OK, + AtFlags::empty() + ) + .err() + .unwrap(), + Errno::ENOENT + ); +} + +#[test] +#[cfg(not(any(target_os = "illumos", target_os = "redox")))] +fn test_faccessat_none_file_exists() { + use nix::fcntl::AtFlags; + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("does_exist.txt"); + let _file = File::create(path.clone()).unwrap(); + assert!(faccessat( + None, + &path, + AccessFlags::R_OK | AccessFlags::W_OK, + AtFlags::empty() + ) + .is_ok()); +} + +#[test] +#[cfg(not(any(target_os = "illumos", target_os = "redox")))] +fn test_faccessat_file_exists() { + use nix::fcntl::AtFlags; + let tempdir = tempfile::tempdir().unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let exist_file = "does_exist.txt"; + let path = tempdir.path().join(exist_file); + let _file = File::create(path.clone()).unwrap(); + assert!(faccessat( + Some(dirfd), + &path, + AccessFlags::R_OK | AccessFlags::W_OK, + AtFlags::empty() + ) + .is_ok()); +} From d458ecd4e1205d36230ecac85c67472e3227a92d Mon Sep 17 00:00:00 2001 From: SteveLauC Date: Tue, 9 Aug 2022 12:15:52 +0800 Subject: [PATCH 147/358] remove deprecated items --- src/sched.rs | 4 +- src/sys/personality.rs | 2 +- src/sys/quota.rs | 4 +- src/sys/socket/mod.rs | 2 +- src/sys/socket/sockopt.rs | 2 +- src/sys/termios.rs | 10 +- src/sys/time.rs | 62 +++++------ src/unistd.rs | 66 ++++++------ test/sys/test_pthread.rs | 2 +- test/sys/test_ptrace.rs | 52 ++++----- test/test_dir.rs | 2 +- test/test_pty.rs | 6 +- test/test_stat.rs | 66 ++++++------ test/test_unistd.rs | 216 +++++++++++++++++++------------------- 14 files changed, 248 insertions(+), 248 deletions(-) diff --git a/src/sched.rs b/src/sched.rs index e736f8d249..e9a326e261 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -233,8 +233,8 @@ mod sched_affinity { /// use nix::unistd::Pid; /// /// let mut cpu_set = CpuSet::new(); - /// cpu_set.set(0); - /// sched_setaffinity(Pid::from_raw(0), &cpu_set); + /// cpu_set.set(0).unwrap(); + /// sched_setaffinity(Pid::from_raw(0), &cpu_set).unwrap(); /// ``` pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> { let res = unsafe { diff --git a/src/sys/personality.rs b/src/sys/personality.rs index 2af6687823..15b59017be 100644 --- a/src/sys/personality.rs +++ b/src/sys/personality.rs @@ -86,7 +86,7 @@ pub fn get() -> Result { /// # use nix::sys::personality::{self, Persona}; /// let mut pers = personality::get().unwrap(); /// assert!(!pers.contains(Persona::ADDR_NO_RANDOMIZE)); -/// personality::set(pers | Persona::ADDR_NO_RANDOMIZE); +/// personality::set(pers | Persona::ADDR_NO_RANDOMIZE).unwrap().unwrap(); /// ``` pub fn set(persona: Persona) -> Result { let res = unsafe { diff --git a/src/sys/quota.rs b/src/sys/quota.rs index 6e34e38d2b..f3b4c02dee 100644 --- a/src/sys/quota.rs +++ b/src/sys/quota.rs @@ -6,11 +6,11 @@ //! //! ```rust,no_run //! # use nix::sys::quota::{Dqblk, quotactl_on, quotactl_set, QuotaFmt, QuotaType, QuotaValidFlags}; -//! quotactl_on(QuotaType::USRQUOTA, "/dev/sda1", QuotaFmt::QFMT_VFS_V1, "aquota.user"); +//! quotactl_on(QuotaType::USRQUOTA, "/dev/sda1", QuotaFmt::QFMT_VFS_V1, "aquota.user").unwrap(); //! let mut dqblk: Dqblk = Default::default(); //! dqblk.set_blocks_hard_limit(10000); //! dqblk.set_blocks_soft_limit(8000); -//! quotactl_set(QuotaType::USRQUOTA, "/dev/sda1", 50, &dqblk, QuotaValidFlags::QIF_BLIMITS); +//! quotactl_set(QuotaType::USRQUOTA, "/dev/sda1", 50, &dqblk, QuotaValidFlags::QIF_BLIMITS).unwrap(); //! ``` use std::default::Default; use std::{mem, ptr}; diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 2dfa8ec6e6..7e6d60948e 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -677,7 +677,7 @@ pub enum ControlMessageOwned { /// None).unwrap(); /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap(); /// let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); - /// bind(in_socket, &localhost); + /// bind(in_socket, &localhost).unwrap(); /// let address: SockaddrIn = getsockname(in_socket).unwrap(); /// // Get initial time /// let time0 = SystemTime::now(); diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index fff496dbbd..1cbb223ece 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -982,7 +982,7 @@ mod test { let a_cred = getsockopt(a, super::PeerCredentials).unwrap(); let b_cred = getsockopt(b, super::PeerCredentials).unwrap(); assert_eq!(a_cred, b_cred); - assert!(a_cred.pid() != 0); + assert_ne!(a_cred.pid(), 0); } #[test] diff --git a/src/sys/termios.rs b/src/sys/termios.rs index feb52c0ab9..c5b27d28ea 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -64,9 +64,9 @@ //! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! cfsetispeed(&mut t, BaudRate::B9600); -//! cfsetospeed(&mut t, BaudRate::B9600); -//! cfsetspeed(&mut t, BaudRate::B9600); +//! cfsetispeed(&mut t, BaudRate::B9600).unwrap(); +//! cfsetospeed(&mut t, BaudRate::B9600).unwrap(); +//! cfsetspeed(&mut t, BaudRate::B9600).unwrap(); //! # } //! ``` //! @@ -76,10 +76,10 @@ //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetispeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; -//! # cfsetspeed(&mut t, BaudRate::B9600); +//! # cfsetspeed(&mut t, BaudRate::B9600).unwrap(); //! let speed = cfgetispeed(&t); //! assert_eq!(speed, cfgetospeed(&t)); -//! cfsetispeed(&mut t, speed); +//! cfsetispeed(&mut t, speed).unwrap(); //! # } //! ``` //! diff --git a/src/sys/time.rs b/src/sys/time.rs index b7ab3986f8..3627997855 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -7,17 +7,17 @@ use std::time::Duration; use std::{cmp, fmt, ops}; #[cfg(any( - all(feature = "time", any(target_os = "android", target_os = "linux")), - all( - any( - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd" - ), - feature = "time", - feature = "signal" - ) +all(feature = "time", any(target_os = "android", target_os = "linux")), +all( +any( +target_os = "freebsd", +target_os = "illumos", +target_os = "linux", +target_os = "netbsd" +), +feature = "time", +feature = "signal" +) ))] pub(crate) mod timer { use crate::sys::time::TimeSpec; @@ -98,10 +98,10 @@ pub(crate) mod timer { } } #[cfg(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "dragonfly", - target_os = "illumos" + target_os = "freebsd", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "illumos" ))] bitflags! { /// Flags that are used for arming the timer. @@ -114,17 +114,17 @@ pub(crate) mod timer { fn from(timerspec: TimerSpec) -> Expiration { match timerspec { TimerSpec(libc::itimerspec { - it_interval: - libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, - it_value: ts, - }) => Expiration::OneShot(ts.into()), + it_interval: + libc::timespec { + tv_sec: 0, + tv_nsec: 0, + }, + it_value: ts, + }) => Expiration::OneShot(ts.into()), TimerSpec(libc::itimerspec { - it_interval: int_ts, - it_value: val_ts, - }) => { + it_interval: int_ts, + it_value: val_ts, + }) => { if (int_ts.tv_sec == val_ts.tv_sec) && (int_ts.tv_nsec == val_ts.tv_nsec) { @@ -193,7 +193,7 @@ const SECS_PER_MINUTE: i64 = 60; const SECS_PER_HOUR: i64 = 3600; #[cfg(target_pointer_width = "64")] -const TS_MAX_SECONDS: i64 = (::std::i64::MAX / NANOS_PER_SEC) - 1; +const TS_MAX_SECONDS: i64 = (i64::MAX / NANOS_PER_SEC) - 1; #[cfg(target_pointer_width = "32")] const TS_MAX_SECONDS: i64 = ::std::isize::MAX as i64; @@ -453,7 +453,7 @@ pub struct TimeVal(timeval); const MICROS_PER_SEC: i64 = 1_000_000; #[cfg(target_pointer_width = "64")] -const TV_MAX_SECONDS: i64 = (::std::i64::MAX / MICROS_PER_SEC) - 1; +const TV_MAX_SECONDS: i64 = (i64::MAX / MICROS_PER_SEC) - 1; #[cfg(target_pointer_width = "32")] const TV_MAX_SECONDS: i64 = ::std::isize::MAX as i64; @@ -713,7 +713,7 @@ mod test { #[test] pub fn test_timespec() { - assert!(TimeSpec::seconds(1) != TimeSpec::zero()); + assert_ne!(TimeSpec::seconds(1), TimeSpec::zero()); assert_eq!( TimeSpec::seconds(1) + TimeSpec::seconds(2), TimeSpec::seconds(3) @@ -743,7 +743,7 @@ mod test { #[test] pub fn test_timespec_ord() { - assert!(TimeSpec::seconds(1) == TimeSpec::nanoseconds(1_000_000_000)); + assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000)); assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001)); assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999)); assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999)); @@ -765,7 +765,7 @@ mod test { #[test] pub fn test_timeval() { - assert!(TimeVal::seconds(1) != TimeVal::zero()); + assert_ne!(TimeVal::seconds(1), TimeVal::zero()); assert_eq!( TimeVal::seconds(1) + TimeVal::seconds(2), TimeVal::seconds(3) @@ -778,7 +778,7 @@ mod test { #[test] pub fn test_timeval_ord() { - assert!(TimeVal::seconds(1) == TimeVal::microseconds(1_000_000)); + assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000)); assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001)); assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999)); assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999)); diff --git a/src/unistd.rs b/src/unistd.rs index 70a06b0286..69419d640e 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -7,15 +7,15 @@ use crate::fcntl::{at_rawfd, AtFlags}; #[cfg(feature = "fs")] use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; #[cfg(all( - feature = "fs", - any( - target_os = "openbsd", - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios" - ) +feature = "fs", +any( +target_os = "openbsd", +target_os = "netbsd", +target_os = "freebsd", +target_os = "dragonfly", +target_os = "macos", +target_os = "ios" +) ))] use crate::sys::stat::FileFlag; #[cfg(feature = "fs")] @@ -45,20 +45,20 @@ feature! { } #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" +target_os = "android", +target_os = "dragonfly", +target_os = "freebsd", +target_os = "linux", +target_os = "openbsd" ))] pub use self::setres::*; #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" +target_os = "android", +target_os = "dragonfly", +target_os = "freebsd", +target_os = "linux", +target_os = "openbsd" ))] pub use self::getres::*; @@ -1572,7 +1572,7 @@ pub fn getgroups() -> Result> { /// # use std::error::Error; /// # use nix::unistd::*; /// # -/// # fn try_main() -> Result<(), Box> { +/// # fn try_main() -> Result<(), Box> { /// let uid = Uid::from_raw(33); /// let gid = Gid::from_raw(34); /// setgroups(&[gid])?; @@ -1698,7 +1698,7 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result> { /// # use std::ffi::CString; /// # use nix::unistd::*; /// # -/// # fn try_main() -> Result<(), Box> { +/// # fn try_main() -> Result<(), Box> { /// let user = CString::new("www-data").unwrap(); /// let uid = Uid::from_raw(33); /// let gid = Gid::from_raw(33); @@ -2752,11 +2752,11 @@ mod pivot_root { } #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" +target_os = "android", +target_os = "dragonfly", +target_os = "freebsd", +target_os = "linux", +target_os = "openbsd" ))] mod setres { feature! { @@ -2801,11 +2801,11 @@ mod setres { } #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" +target_os = "android", +target_os = "dragonfly", +target_os = "freebsd", +target_os = "linux", +target_os = "openbsd" ))] mod getres { feature! { @@ -3121,7 +3121,7 @@ impl User { /// use nix::unistd::{Uid, User}; /// // Returns an Result>, thus the double unwrap. /// let res = User::from_uid(Uid::from_raw(0)).unwrap().unwrap(); - /// assert!(res.name == "root"); + /// assert_eq!(res.name, "root"); /// ``` pub fn from_uid(uid: Uid) -> Result> { User::from_anything(|pwd, cbuf, cap, res| { @@ -3140,7 +3140,7 @@ impl User { /// use nix::unistd::User; /// // Returns an Result>, thus the double unwrap. /// let res = User::from_name("root").unwrap().unwrap(); - /// assert!(res.name == "root"); + /// assert_eq!(res.name, "root"); /// ``` pub fn from_name(name: &str) -> Result> { let name = CString::new(name).unwrap(); diff --git a/test/sys/test_pthread.rs b/test/sys/test_pthread.rs index 42a4aefaad..ce048bae60 100644 --- a/test/sys/test_pthread.rs +++ b/test/sys/test_pthread.rs @@ -11,7 +11,7 @@ fn test_pthread_self() { #[test] fn test_pthread_self() { let tid = pthread_self(); - assert!(tid != 0); + assert_ne!(tid, 0); } #[test] diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs index e514832b82..1668058329 100644 --- a/test/sys/test_ptrace.rs +++ b/test/sys/test_ptrace.rs @@ -1,7 +1,7 @@ #[cfg(all( - target_os = "linux", - any(target_arch = "x86_64", target_arch = "x86"), - target_env = "gnu" +target_os = "linux", +any(target_arch = "x86_64", target_arch = "x86"), +target_env = "gnu" ))] use memoffset::offset_of; use nix::errno::Errno; @@ -33,7 +33,7 @@ fn test_ptrace_setoptions() { require_capability!("test_ptrace_setoptions", CAP_SYS_PTRACE); let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD) .unwrap_err(); - assert!(err != Errno::EOPNOTSUPP); + assert_ne!(err, Errno::EOPNOTSUPP); } // Just make sure ptrace_getevent can be called at all, for now. @@ -42,7 +42,7 @@ fn test_ptrace_setoptions() { fn test_ptrace_getevent() { require_capability!("test_ptrace_getevent", CAP_SYS_PTRACE); let err = ptrace::getevent(getpid()).unwrap_err(); - assert!(err != Errno::EOPNOTSUPP); + assert_ne!(err, Errno::EOPNOTSUPP); } // Just make sure ptrace_getsiginfo can be called at all, for now. @@ -111,17 +111,17 @@ fn test_ptrace_cont() { ptrace::cont(child, Some(Signal::SIGKILL)).unwrap(); match waitpid(child, None) { Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) - if pid == child => - { - // FIXME It's been observed on some systems (apple) the - // tracee may not be killed but remain as a zombie process - // affecting other wait based tests. Add an extra kill just - // to make sure there are no zombies. - let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); - while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { + if pid == child => + { + // FIXME It's been observed on some systems (apple) the + // tracee may not be killed but remain as a zombie process + // affecting other wait based tests. Add an extra kill just + // to make sure there are no zombies. let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); + while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { + let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); + } } - } _ => panic!("The process should have been killed"), } } @@ -163,13 +163,13 @@ fn test_ptrace_interrupt() { ptrace::detach(child, Some(Signal::SIGKILL)).unwrap(); match waitpid(child, None) { Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) - if pid == child => - { - let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); - while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { + if pid == child => + { let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); + while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { + let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); + } } - } _ => panic!("The process should have been killed"), } } @@ -178,9 +178,9 @@ fn test_ptrace_interrupt() { // ptrace::{setoptions, getregs} are only available in these platforms #[cfg(all( - target_os = "linux", - any(target_arch = "x86_64", target_arch = "x86"), - target_env = "gnu" +target_os = "linux", +any(target_arch = "x86_64", target_arch = "x86"), +target_env = "gnu" ))] #[test] fn test_ptrace_syscall() { @@ -219,18 +219,18 @@ fn test_ptrace_syscall() { .unwrap(); #[cfg(target_arch = "x86_64")] - let get_syscall_id = + let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as libc::c_long; #[cfg(target_arch = "x86")] - let get_syscall_id = + let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as libc::c_long; // this duplicates `get_syscall_id` for the purpose of testing `ptrace::read_user`. #[cfg(target_arch = "x86_64")] - let rax_offset = offset_of!(libc::user_regs_struct, orig_rax); + let rax_offset = offset_of!(libc::user_regs_struct, orig_rax); #[cfg(target_arch = "x86")] - let rax_offset = offset_of!(libc::user_regs_struct, orig_eax); + let rax_offset = offset_of!(libc::user_regs_struct, orig_eax); let get_syscall_from_user_area = || { // Find the offset of `user.regs.rax` (or `user.regs.eax` for x86) diff --git a/test/test_dir.rs b/test/test_dir.rs index 9d2780c0e6..f66299210e 100644 --- a/test/test_dir.rs +++ b/test/test_dir.rs @@ -20,7 +20,7 @@ fn flags() -> OFlag { fn read() { let tmp = tempdir().unwrap(); File::create(&tmp.path().join("foo")).unwrap(); - ::std::os::unix::fs::symlink("foo", tmp.path().join("bar")).unwrap(); + std::os::unix::fs::symlink("foo", tmp.path().join("bar")).unwrap(); let mut dir = Dir::open(tmp.path(), flags(), Mode::empty()).unwrap(); let mut entries: Vec<_> = dir.iter().map(|e| e.unwrap()).collect(); entries.sort_by(|a, b| a.file_name().cmp(b.file_name())); diff --git a/test/test_pty.rs b/test/test_pty.rs index 3b52289e5c..5c27e2d632 100644 --- a/test/test_pty.rs +++ b/test/test_pty.rs @@ -58,7 +58,7 @@ fn test_ptsname_copy() { assert_eq!(slave_name1, slave_name2); // Also make sure that the string was actually copied and they point to different parts of // memory. - assert!(slave_name1.as_ptr() != slave_name2.as_ptr()); + assert_ne!(slave_name1.as_ptr(), slave_name2.as_ptr()); } /// Test data copying of `ptsname_r` @@ -73,7 +73,7 @@ fn test_ptsname_r_copy() { let slave_name1 = ptsname_r(&master_fd).unwrap(); let slave_name2 = ptsname_r(&master_fd).unwrap(); assert_eq!(slave_name1, slave_name2); - assert!(slave_name1.as_ptr() != slave_name2.as_ptr()); + assert_ne!(slave_name1.as_ptr(), slave_name2.as_ptr()); } /// Test that `ptsname` returns different names for different devices @@ -93,7 +93,7 @@ fn test_ptsname_unique() { // Get the name of the slave let slave_name1 = unsafe { ptsname(&master1_fd) }.unwrap(); let slave_name2 = unsafe { ptsname(&master2_fd) }.unwrap(); - assert!(slave_name1 != slave_name2); + assert_ne!(slave_name1, slave_name2); } /// Common setup for testing PTTY pairs diff --git a/test/test_stat.rs b/test/test_stat.rs index 1888c64914..bed33b5456 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -20,11 +20,11 @@ use nix::errno::Errno; #[cfg(not(target_os = "redox"))] use nix::fcntl; #[cfg(any( - target_os = "linux", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd" +target_os = "linux", +target_os = "ios", +target_os = "macos", +target_os = "freebsd", +target_os = "netbsd" ))] use nix::sys::stat::lutimes; #[cfg(not(any(target_os = "redox", target_os = "haiku")))] @@ -234,11 +234,11 @@ fn test_utimes() { #[test] #[cfg(any( - target_os = "linux", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd" +target_os = "linux", +target_os = "ios", +target_os = "macos", +target_os = "freebsd", +target_os = "netbsd" ))] fn test_lutimes() { let tempdir = tempfile::tempdir().unwrap(); @@ -299,7 +299,7 @@ fn test_utimensat() { &TimeSpec::seconds(678), UtimensatFlags::FollowSymlink, ) - .unwrap(); + .unwrap(); assert_times_eq(12345, 678, &fs::metadata(&fullpath).unwrap()); chdir(tempdir.path()).unwrap(); @@ -311,7 +311,7 @@ fn test_utimensat() { &TimeSpec::seconds(800), UtimensatFlags::FollowSymlink, ) - .unwrap(); + .unwrap(); assert_times_eq(500, 800, &fs::metadata(&fullpath).unwrap()); } @@ -356,19 +356,19 @@ fn test_mkdirat_fail() { fcntl::OFlag::O_CREAT, stat::Mode::empty(), ) - .unwrap(); + .unwrap(); let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err(); assert_eq!(result, Errno::ENOTDIR); } #[test] #[cfg(not(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "haiku", - target_os = "redox" +target_os = "dragonfly", +target_os = "freebsd", +target_os = "ios", +target_os = "macos", +target_os = "haiku", +target_os = "redox" )))] fn test_mknod() { use stat::{lstat, mknod, SFlag}; @@ -378,19 +378,19 @@ fn test_mknod() { let target = tempdir.path().join(file_name); mknod(&target, SFlag::S_IFREG, Mode::S_IRWXU, 0).unwrap(); let mode = lstat(&target).unwrap().st_mode as mode_t; - assert!(mode & libc::S_IFREG == libc::S_IFREG); - assert!(mode & libc::S_IRWXU == libc::S_IRWXU); + assert_eq!(mode & libc::S_IFREG, libc::S_IFREG); + assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU); } #[test] #[cfg(not(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "haiku", - target_os = "redox" +target_os = "dragonfly", +target_os = "freebsd", +target_os = "illumos", +target_os = "ios", +target_os = "macos", +target_os = "haiku", +target_os = "redox" )))] fn test_mknodat() { use fcntl::{AtFlags, OFlag}; @@ -408,14 +408,14 @@ fn test_mknodat() { Mode::S_IRWXU, 0, ) - .unwrap(); + .unwrap(); let mode = fstatat( target_dir.as_raw_fd(), file_name, AtFlags::AT_SYMLINK_NOFOLLOW, ) - .unwrap() - .st_mode as mode_t; - assert!(mode & libc::S_IFREG == libc::S_IFREG); - assert!(mode & libc::S_IRWXU == libc::S_IRWXU); + .unwrap() + .st_mode as mode_t; + assert_eq!(mode & libc::S_IFREG, libc::S_IFREG); + assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU); } diff --git a/test/test_unistd.rs b/test/test_unistd.rs index b08ab33257..e4750d4b16 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -6,9 +6,9 @@ use nix::fcntl::OFlag; #[cfg(not(target_os = "redox"))] use nix::fcntl::{self, open}; #[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" +target_os = "redox", +target_os = "fuchsia", +target_os = "haiku" )))] use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt}; #[cfg(not(target_os = "redox"))] @@ -28,9 +28,9 @@ use std::fs::{self, File}; use std::io::Write; use std::os::unix::prelude::*; #[cfg(not(any( - target_os = "fuchsia", - target_os = "redox", - target_os = "haiku" +target_os = "fuchsia", +target_os = "redox", +target_os = "haiku" )))] use std::path::Path; use tempfile::{tempdir, tempfile}; @@ -114,7 +114,7 @@ fn test_mkfifo() { let stats = stat::stat(&mkfifo_fifo).unwrap(); let typ = stat::SFlag::from_bits_truncate(stats.st_mode as mode_t); - assert!(typ == SFlag::S_IFIFO); + assert_eq!(typ, SFlag::S_IFIFO); } #[test] @@ -126,11 +126,11 @@ fn test_mkfifo_directory() { #[test] #[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "redox", - target_os = "haiku" +target_os = "macos", +target_os = "ios", +target_os = "android", +target_os = "redox", +target_os = "haiku" )))] fn test_mkfifoat_none() { let _m = crate::CWD_LOCK.read(); @@ -147,11 +147,11 @@ fn test_mkfifoat_none() { #[test] #[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "redox", - target_os = "haiku" +target_os = "macos", +target_os = "ios", +target_os = "android", +target_os = "redox", +target_os = "haiku" )))] fn test_mkfifoat() { use nix::fcntl; @@ -170,11 +170,11 @@ fn test_mkfifoat() { #[test] #[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "redox", - target_os = "haiku" +target_os = "macos", +target_os = "ios", +target_os = "android", +target_os = "redox", +target_os = "haiku" )))] fn test_mkfifoat_directory_none() { let _m = crate::CWD_LOCK.read(); @@ -186,11 +186,11 @@ fn test_mkfifoat_directory_none() { #[test] #[cfg(not(any( - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "redox", - target_os = "haiku" +target_os = "macos", +target_os = "ios", +target_os = "android", +target_os = "redox", +target_os = "haiku" )))] fn test_mkfifoat_directory() { // mkfifoat should fail if a directory is given @@ -234,11 +234,11 @@ mod linux_android { #[test] // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms #[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" +target_os = "ios", +target_os = "macos", +target_os = "redox", +target_os = "fuchsia", +target_os = "haiku" )))] fn test_setgroups() { // Skip this test when not run as root as `setgroups()` requires root. @@ -263,12 +263,12 @@ fn test_setgroups() { #[test] // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms #[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos" +target_os = "ios", +target_os = "macos", +target_os = "redox", +target_os = "fuchsia", +target_os = "haiku", +target_os = "illumos" )))] fn test_initgroups() { // Skip this test when not run as root as `initgroups()` and `setgroups()` @@ -300,7 +300,7 @@ fn test_initgroups() { } #[cfg(not(any(target_os = "fuchsia", target_os = "redox")))] -macro_rules! execve_test_factory( +macro_rules! execve_test_factory ( ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => ( #[cfg(test)] @@ -609,9 +609,9 @@ cfg_if! { #[test] #[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" +target_os = "redox", +target_os = "fuchsia", +target_os = "haiku" )))] fn test_acct() { use std::process::Command; @@ -685,33 +685,33 @@ fn test_sysconf_unsupported() { } #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" +target_os = "android", +target_os = "dragonfly", +target_os = "freebsd", +target_os = "linux", +target_os = "openbsd" ))] #[test] fn test_getresuid() { let resuids = getresuid().unwrap(); - assert!(resuids.real.as_raw() != libc::uid_t::max_value()); - assert!(resuids.effective.as_raw() != libc::uid_t::max_value()); - assert!(resuids.saved.as_raw() != libc::uid_t::max_value()); + assert_ne!(resuids.real.as_raw(), libc::uid_t::MAX); + assert_ne!(resuids.effective.as_raw(), libc::uid_t::MAX); + assert_ne!(resuids.saved.as_raw(), libc::uid_t::MAX); } #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" +target_os = "android", +target_os = "dragonfly", +target_os = "freebsd", +target_os = "linux", +target_os = "openbsd" ))] #[test] fn test_getresgid() { let resgids = getresgid().unwrap(); - assert!(resgids.real.as_raw() != libc::gid_t::max_value()); - assert!(resgids.effective.as_raw() != libc::gid_t::max_value()); - assert!(resgids.saved.as_raw() != libc::gid_t::max_value()); + assert_ne!(resgids.real.as_raw(), libc::gid_t::MAX); + assert_ne!(resgids.effective.as_raw(), libc::gid_t::MAX); + assert_ne!(resgids.saved.as_raw(), libc::gid_t::MAX); } // Test that we can create a pair of pipes. No need to verify that they pass @@ -733,16 +733,16 @@ fn test_pipe() { // pipe2(2) is the same as pipe(2), except it allows setting some flags. Check // that we can set a flag. #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "redox", - target_os = "solaris" +target_os = "android", +target_os = "dragonfly", +target_os = "emscripten", +target_os = "freebsd", +target_os = "illumos", +target_os = "linux", +target_os = "netbsd", +target_os = "openbsd", +target_os = "redox", +target_os = "solaris" ))] #[test] fn test_pipe2() { @@ -918,7 +918,7 @@ fn test_linkat_file() { newfilename, LinkatFlags::SymlinkFollow, ) - .unwrap(); + .unwrap(); assert!(newfilepath.exists()); } @@ -944,7 +944,7 @@ fn test_linkat_olddirfd_none() { fcntl::OFlag::empty(), stat::Mode::empty(), ) - .unwrap(); + .unwrap(); // Attempt hard link file using curent working directory as relative path for old file path chdir(tempdir_oldfile.path()).unwrap(); @@ -955,7 +955,7 @@ fn test_linkat_olddirfd_none() { newfilename, LinkatFlags::SymlinkFollow, ) - .unwrap(); + .unwrap(); assert!(newfilepath.exists()); } @@ -981,7 +981,7 @@ fn test_linkat_newdirfd_none() { fcntl::OFlag::empty(), stat::Mode::empty(), ) - .unwrap(); + .unwrap(); // Attempt hard link file using current working directory as relative path for new file path chdir(tempdir_newfile.path()).unwrap(); @@ -992,16 +992,16 @@ fn test_linkat_newdirfd_none() { newfilename, LinkatFlags::SymlinkFollow, ) - .unwrap(); + .unwrap(); assert!(newfilepath.exists()); } #[test] #[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "redox", - target_os = "haiku" +target_os = "ios", +target_os = "macos", +target_os = "redox", +target_os = "haiku" )))] fn test_linkat_no_follow_symlink() { let _m = crate::CWD_LOCK.read(); @@ -1035,7 +1035,7 @@ fn test_linkat_no_follow_symlink() { newfilename, LinkatFlags::NoSymlinkFollow, ) - .unwrap(); + .unwrap(); // Assert newfile is actually a symlink to oldfile. assert_eq!( @@ -1078,7 +1078,7 @@ fn test_linkat_follow_symlink() { newfilename, LinkatFlags::SymlinkFollow, ) - .unwrap(); + .unwrap(); let newfilestat = stat::stat(&newfilepath).unwrap(); @@ -1180,10 +1180,10 @@ fn test_access_file_exists() { fn test_user_into_passwd() { // get the UID of the "nobody" user #[cfg(not(target_os = "haiku"))] - let test_username = "nobody"; + let test_username = "nobody"; // "nobody" unavailable on haiku #[cfg(target_os = "haiku")] - let test_username = "user"; + let test_username = "user"; let nobody = User::from_name(test_username).unwrap().unwrap(); let pwd: libc::passwd = nobody.into(); @@ -1221,8 +1221,8 @@ fn test_setfsuid() { let prev_fuid = setfsuid(Uid::from_raw(-1i32 as u32)); assert_ne!(prev_fuid, fuid); }) - .join() - .unwrap(); + .join() + .unwrap(); // open the temporary file with the current thread filesystem UID fs::File::open(temp_path_2).unwrap(); @@ -1230,9 +1230,9 @@ fn test_setfsuid() { #[test] #[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" +target_os = "redox", +target_os = "fuchsia", +target_os = "haiku" )))] fn test_ttyname() { let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); @@ -1262,9 +1262,9 @@ fn test_ttyname_not_pty() { #[test] #[cfg(not(any( - target_os = "redox", - target_os = "fuchsia", - target_os = "haiku" +target_os = "redox", +target_os = "fuchsia", +target_os = "haiku" )))] fn test_ttyname_invalid_fd() { assert_eq!(ttyname(-1), Err(Errno::EBADF)); @@ -1272,12 +1272,12 @@ fn test_ttyname_invalid_fd() { #[test] #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly", +target_os = "macos", +target_os = "ios", +target_os = "freebsd", +target_os = "openbsd", +target_os = "netbsd", +target_os = "dragonfly", ))] fn test_getpeereid() { use std::os::unix::net::UnixStream; @@ -1297,12 +1297,12 @@ fn test_getpeereid() { #[test] #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly", +target_os = "macos", +target_os = "ios", +target_os = "freebsd", +target_os = "openbsd", +target_os = "netbsd", +target_os = "dragonfly", ))] fn test_getpeereid_invalid_fd() { // getpeereid is not POSIX, so error codes are inconsistent between different Unices. @@ -1335,10 +1335,10 @@ fn test_faccessat_not_existing() { Some(dirfd), not_exist_file, AccessFlags::F_OK, - AtFlags::empty() + AtFlags::empty(), ) - .err() - .unwrap(), + .err() + .unwrap(), Errno::ENOENT ); } @@ -1354,9 +1354,9 @@ fn test_faccessat_none_file_exists() { None, &path, AccessFlags::R_OK | AccessFlags::W_OK, - AtFlags::empty() + AtFlags::empty(), ) - .is_ok()); + .is_ok()); } #[test] @@ -1372,7 +1372,7 @@ fn test_faccessat_file_exists() { Some(dirfd), &path, AccessFlags::R_OK | AccessFlags::W_OK, - AtFlags::empty() + AtFlags::empty(), ) - .is_ok()); + .is_ok()); } From 347915bdb590d9b3437b9c5c69c6f1652017d325 Mon Sep 17 00:00:00 2001 From: SteveLauC Date: Tue, 9 Aug 2022 12:17:27 +0800 Subject: [PATCH 148/358] format code --- src/sys/time.rs | 50 +++++------ src/unistd.rs | 58 ++++++------ test/sys/test_ptrace.rs | 48 +++++----- test/test_stat.rs | 58 ++++++------ test/test_unistd.rs | 194 ++++++++++++++++++++-------------------- 5 files changed, 204 insertions(+), 204 deletions(-) diff --git a/src/sys/time.rs b/src/sys/time.rs index 3627997855..e7a72f0205 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -7,17 +7,17 @@ use std::time::Duration; use std::{cmp, fmt, ops}; #[cfg(any( -all(feature = "time", any(target_os = "android", target_os = "linux")), -all( -any( -target_os = "freebsd", -target_os = "illumos", -target_os = "linux", -target_os = "netbsd" -), -feature = "time", -feature = "signal" -) + all(feature = "time", any(target_os = "android", target_os = "linux")), + all( + any( + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd" + ), + feature = "time", + feature = "signal" + ) ))] pub(crate) mod timer { use crate::sys::time::TimeSpec; @@ -98,10 +98,10 @@ pub(crate) mod timer { } } #[cfg(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "dragonfly", - target_os = "illumos" + target_os = "freebsd", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "illumos" ))] bitflags! { /// Flags that are used for arming the timer. @@ -114,17 +114,17 @@ pub(crate) mod timer { fn from(timerspec: TimerSpec) -> Expiration { match timerspec { TimerSpec(libc::itimerspec { - it_interval: - libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, - it_value: ts, - }) => Expiration::OneShot(ts.into()), + it_interval: + libc::timespec { + tv_sec: 0, + tv_nsec: 0, + }, + it_value: ts, + }) => Expiration::OneShot(ts.into()), TimerSpec(libc::itimerspec { - it_interval: int_ts, - it_value: val_ts, - }) => { + it_interval: int_ts, + it_value: val_ts, + }) => { if (int_ts.tv_sec == val_ts.tv_sec) && (int_ts.tv_nsec == val_ts.tv_nsec) { diff --git a/src/unistd.rs b/src/unistd.rs index 69419d640e..2209c06921 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -7,15 +7,15 @@ use crate::fcntl::{at_rawfd, AtFlags}; #[cfg(feature = "fs")] use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; #[cfg(all( -feature = "fs", -any( -target_os = "openbsd", -target_os = "netbsd", -target_os = "freebsd", -target_os = "dragonfly", -target_os = "macos", -target_os = "ios" -) + feature = "fs", + any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios" + ) ))] use crate::sys::stat::FileFlag; #[cfg(feature = "fs")] @@ -45,20 +45,20 @@ feature! { } #[cfg(any( -target_os = "android", -target_os = "dragonfly", -target_os = "freebsd", -target_os = "linux", -target_os = "openbsd" + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" ))] pub use self::setres::*; #[cfg(any( -target_os = "android", -target_os = "dragonfly", -target_os = "freebsd", -target_os = "linux", -target_os = "openbsd" + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" ))] pub use self::getres::*; @@ -2752,11 +2752,11 @@ mod pivot_root { } #[cfg(any( -target_os = "android", -target_os = "dragonfly", -target_os = "freebsd", -target_os = "linux", -target_os = "openbsd" + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" ))] mod setres { feature! { @@ -2801,11 +2801,11 @@ mod setres { } #[cfg(any( -target_os = "android", -target_os = "dragonfly", -target_os = "freebsd", -target_os = "linux", -target_os = "openbsd" + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" ))] mod getres { feature! { diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs index 1668058329..530560fe17 100644 --- a/test/sys/test_ptrace.rs +++ b/test/sys/test_ptrace.rs @@ -1,7 +1,7 @@ #[cfg(all( -target_os = "linux", -any(target_arch = "x86_64", target_arch = "x86"), -target_env = "gnu" + target_os = "linux", + any(target_arch = "x86_64", target_arch = "x86"), + target_env = "gnu" ))] use memoffset::offset_of; use nix::errno::Errno; @@ -111,17 +111,17 @@ fn test_ptrace_cont() { ptrace::cont(child, Some(Signal::SIGKILL)).unwrap(); match waitpid(child, None) { Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) - if pid == child => - { - // FIXME It's been observed on some systems (apple) the - // tracee may not be killed but remain as a zombie process - // affecting other wait based tests. Add an extra kill just - // to make sure there are no zombies. + if pid == child => + { + // FIXME It's been observed on some systems (apple) the + // tracee may not be killed but remain as a zombie process + // affecting other wait based tests. Add an extra kill just + // to make sure there are no zombies. + let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); + while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); - while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { - let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); - } } + } _ => panic!("The process should have been killed"), } } @@ -163,13 +163,13 @@ fn test_ptrace_interrupt() { ptrace::detach(child, Some(Signal::SIGKILL)).unwrap(); match waitpid(child, None) { Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) - if pid == child => - { + if pid == child => + { + let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); + while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); - while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() { - let _ = waitpid(child, Some(WaitPidFlag::WNOHANG)); - } } + } _ => panic!("The process should have been killed"), } } @@ -178,9 +178,9 @@ fn test_ptrace_interrupt() { // ptrace::{setoptions, getregs} are only available in these platforms #[cfg(all( -target_os = "linux", -any(target_arch = "x86_64", target_arch = "x86"), -target_env = "gnu" + target_os = "linux", + any(target_arch = "x86_64", target_arch = "x86"), + target_env = "gnu" ))] #[test] fn test_ptrace_syscall() { @@ -219,18 +219,18 @@ fn test_ptrace_syscall() { .unwrap(); #[cfg(target_arch = "x86_64")] - let get_syscall_id = + let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as libc::c_long; #[cfg(target_arch = "x86")] - let get_syscall_id = + let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as libc::c_long; // this duplicates `get_syscall_id` for the purpose of testing `ptrace::read_user`. #[cfg(target_arch = "x86_64")] - let rax_offset = offset_of!(libc::user_regs_struct, orig_rax); + let rax_offset = offset_of!(libc::user_regs_struct, orig_rax); #[cfg(target_arch = "x86")] - let rax_offset = offset_of!(libc::user_regs_struct, orig_eax); + let rax_offset = offset_of!(libc::user_regs_struct, orig_eax); let get_syscall_from_user_area = || { // Find the offset of `user.regs.rax` (or `user.regs.eax` for x86) diff --git a/test/test_stat.rs b/test/test_stat.rs index bed33b5456..55f15c0771 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -20,11 +20,11 @@ use nix::errno::Errno; #[cfg(not(target_os = "redox"))] use nix::fcntl; #[cfg(any( -target_os = "linux", -target_os = "ios", -target_os = "macos", -target_os = "freebsd", -target_os = "netbsd" + target_os = "linux", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd" ))] use nix::sys::stat::lutimes; #[cfg(not(any(target_os = "redox", target_os = "haiku")))] @@ -234,11 +234,11 @@ fn test_utimes() { #[test] #[cfg(any( -target_os = "linux", -target_os = "ios", -target_os = "macos", -target_os = "freebsd", -target_os = "netbsd" + target_os = "linux", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd" ))] fn test_lutimes() { let tempdir = tempfile::tempdir().unwrap(); @@ -299,7 +299,7 @@ fn test_utimensat() { &TimeSpec::seconds(678), UtimensatFlags::FollowSymlink, ) - .unwrap(); + .unwrap(); assert_times_eq(12345, 678, &fs::metadata(&fullpath).unwrap()); chdir(tempdir.path()).unwrap(); @@ -311,7 +311,7 @@ fn test_utimensat() { &TimeSpec::seconds(800), UtimensatFlags::FollowSymlink, ) - .unwrap(); + .unwrap(); assert_times_eq(500, 800, &fs::metadata(&fullpath).unwrap()); } @@ -356,19 +356,19 @@ fn test_mkdirat_fail() { fcntl::OFlag::O_CREAT, stat::Mode::empty(), ) - .unwrap(); + .unwrap(); let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err(); assert_eq!(result, Errno::ENOTDIR); } #[test] #[cfg(not(any( -target_os = "dragonfly", -target_os = "freebsd", -target_os = "ios", -target_os = "macos", -target_os = "haiku", -target_os = "redox" + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "haiku", + target_os = "redox" )))] fn test_mknod() { use stat::{lstat, mknod, SFlag}; @@ -384,13 +384,13 @@ fn test_mknod() { #[test] #[cfg(not(any( -target_os = "dragonfly", -target_os = "freebsd", -target_os = "illumos", -target_os = "ios", -target_os = "macos", -target_os = "haiku", -target_os = "redox" + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "haiku", + target_os = "redox" )))] fn test_mknodat() { use fcntl::{AtFlags, OFlag}; @@ -408,14 +408,14 @@ fn test_mknodat() { Mode::S_IRWXU, 0, ) - .unwrap(); + .unwrap(); let mode = fstatat( target_dir.as_raw_fd(), file_name, AtFlags::AT_SYMLINK_NOFOLLOW, ) - .unwrap() - .st_mode as mode_t; + .unwrap() + .st_mode as mode_t; assert_eq!(mode & libc::S_IFREG, libc::S_IFREG); assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU); } diff --git a/test/test_unistd.rs b/test/test_unistd.rs index e4750d4b16..eee10103ad 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -6,9 +6,9 @@ use nix::fcntl::OFlag; #[cfg(not(target_os = "redox"))] use nix::fcntl::{self, open}; #[cfg(not(any( -target_os = "redox", -target_os = "fuchsia", -target_os = "haiku" + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" )))] use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt}; #[cfg(not(target_os = "redox"))] @@ -28,9 +28,9 @@ use std::fs::{self, File}; use std::io::Write; use std::os::unix::prelude::*; #[cfg(not(any( -target_os = "fuchsia", -target_os = "redox", -target_os = "haiku" + target_os = "fuchsia", + target_os = "redox", + target_os = "haiku" )))] use std::path::Path; use tempfile::{tempdir, tempfile}; @@ -126,11 +126,11 @@ fn test_mkfifo_directory() { #[test] #[cfg(not(any( -target_os = "macos", -target_os = "ios", -target_os = "android", -target_os = "redox", -target_os = "haiku" + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "redox", + target_os = "haiku" )))] fn test_mkfifoat_none() { let _m = crate::CWD_LOCK.read(); @@ -147,11 +147,11 @@ fn test_mkfifoat_none() { #[test] #[cfg(not(any( -target_os = "macos", -target_os = "ios", -target_os = "android", -target_os = "redox", -target_os = "haiku" + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "redox", + target_os = "haiku" )))] fn test_mkfifoat() { use nix::fcntl; @@ -170,11 +170,11 @@ fn test_mkfifoat() { #[test] #[cfg(not(any( -target_os = "macos", -target_os = "ios", -target_os = "android", -target_os = "redox", -target_os = "haiku" + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "redox", + target_os = "haiku" )))] fn test_mkfifoat_directory_none() { let _m = crate::CWD_LOCK.read(); @@ -186,11 +186,11 @@ fn test_mkfifoat_directory_none() { #[test] #[cfg(not(any( -target_os = "macos", -target_os = "ios", -target_os = "android", -target_os = "redox", -target_os = "haiku" + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "redox", + target_os = "haiku" )))] fn test_mkfifoat_directory() { // mkfifoat should fail if a directory is given @@ -234,11 +234,11 @@ mod linux_android { #[test] // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms #[cfg(not(any( -target_os = "ios", -target_os = "macos", -target_os = "redox", -target_os = "fuchsia", -target_os = "haiku" + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" )))] fn test_setgroups() { // Skip this test when not run as root as `setgroups()` requires root. @@ -263,12 +263,12 @@ fn test_setgroups() { #[test] // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms #[cfg(not(any( -target_os = "ios", -target_os = "macos", -target_os = "redox", -target_os = "fuchsia", -target_os = "haiku", -target_os = "illumos" + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos" )))] fn test_initgroups() { // Skip this test when not run as root as `initgroups()` and `setgroups()` @@ -609,9 +609,9 @@ cfg_if! { #[test] #[cfg(not(any( -target_os = "redox", -target_os = "fuchsia", -target_os = "haiku" + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" )))] fn test_acct() { use std::process::Command; @@ -685,11 +685,11 @@ fn test_sysconf_unsupported() { } #[cfg(any( -target_os = "android", -target_os = "dragonfly", -target_os = "freebsd", -target_os = "linux", -target_os = "openbsd" + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" ))] #[test] fn test_getresuid() { @@ -700,11 +700,11 @@ fn test_getresuid() { } #[cfg(any( -target_os = "android", -target_os = "dragonfly", -target_os = "freebsd", -target_os = "linux", -target_os = "openbsd" + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" ))] #[test] fn test_getresgid() { @@ -733,16 +733,16 @@ fn test_pipe() { // pipe2(2) is the same as pipe(2), except it allows setting some flags. Check // that we can set a flag. #[cfg(any( -target_os = "android", -target_os = "dragonfly", -target_os = "emscripten", -target_os = "freebsd", -target_os = "illumos", -target_os = "linux", -target_os = "netbsd", -target_os = "openbsd", -target_os = "redox", -target_os = "solaris" + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris" ))] #[test] fn test_pipe2() { @@ -918,7 +918,7 @@ fn test_linkat_file() { newfilename, LinkatFlags::SymlinkFollow, ) - .unwrap(); + .unwrap(); assert!(newfilepath.exists()); } @@ -944,7 +944,7 @@ fn test_linkat_olddirfd_none() { fcntl::OFlag::empty(), stat::Mode::empty(), ) - .unwrap(); + .unwrap(); // Attempt hard link file using curent working directory as relative path for old file path chdir(tempdir_oldfile.path()).unwrap(); @@ -955,7 +955,7 @@ fn test_linkat_olddirfd_none() { newfilename, LinkatFlags::SymlinkFollow, ) - .unwrap(); + .unwrap(); assert!(newfilepath.exists()); } @@ -981,7 +981,7 @@ fn test_linkat_newdirfd_none() { fcntl::OFlag::empty(), stat::Mode::empty(), ) - .unwrap(); + .unwrap(); // Attempt hard link file using current working directory as relative path for new file path chdir(tempdir_newfile.path()).unwrap(); @@ -992,16 +992,16 @@ fn test_linkat_newdirfd_none() { newfilename, LinkatFlags::SymlinkFollow, ) - .unwrap(); + .unwrap(); assert!(newfilepath.exists()); } #[test] #[cfg(not(any( -target_os = "ios", -target_os = "macos", -target_os = "redox", -target_os = "haiku" + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "haiku" )))] fn test_linkat_no_follow_symlink() { let _m = crate::CWD_LOCK.read(); @@ -1035,7 +1035,7 @@ fn test_linkat_no_follow_symlink() { newfilename, LinkatFlags::NoSymlinkFollow, ) - .unwrap(); + .unwrap(); // Assert newfile is actually a symlink to oldfile. assert_eq!( @@ -1078,7 +1078,7 @@ fn test_linkat_follow_symlink() { newfilename, LinkatFlags::SymlinkFollow, ) - .unwrap(); + .unwrap(); let newfilestat = stat::stat(&newfilepath).unwrap(); @@ -1180,10 +1180,10 @@ fn test_access_file_exists() { fn test_user_into_passwd() { // get the UID of the "nobody" user #[cfg(not(target_os = "haiku"))] - let test_username = "nobody"; + let test_username = "nobody"; // "nobody" unavailable on haiku #[cfg(target_os = "haiku")] - let test_username = "user"; + let test_username = "user"; let nobody = User::from_name(test_username).unwrap().unwrap(); let pwd: libc::passwd = nobody.into(); @@ -1221,8 +1221,8 @@ fn test_setfsuid() { let prev_fuid = setfsuid(Uid::from_raw(-1i32 as u32)); assert_ne!(prev_fuid, fuid); }) - .join() - .unwrap(); + .join() + .unwrap(); // open the temporary file with the current thread filesystem UID fs::File::open(temp_path_2).unwrap(); @@ -1230,9 +1230,9 @@ fn test_setfsuid() { #[test] #[cfg(not(any( -target_os = "redox", -target_os = "fuchsia", -target_os = "haiku" + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" )))] fn test_ttyname() { let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed"); @@ -1262,9 +1262,9 @@ fn test_ttyname_not_pty() { #[test] #[cfg(not(any( -target_os = "redox", -target_os = "fuchsia", -target_os = "haiku" + target_os = "redox", + target_os = "fuchsia", + target_os = "haiku" )))] fn test_ttyname_invalid_fd() { assert_eq!(ttyname(-1), Err(Errno::EBADF)); @@ -1272,12 +1272,12 @@ fn test_ttyname_invalid_fd() { #[test] #[cfg(any( -target_os = "macos", -target_os = "ios", -target_os = "freebsd", -target_os = "openbsd", -target_os = "netbsd", -target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", ))] fn test_getpeereid() { use std::os::unix::net::UnixStream; @@ -1297,12 +1297,12 @@ fn test_getpeereid() { #[test] #[cfg(any( -target_os = "macos", -target_os = "ios", -target_os = "freebsd", -target_os = "openbsd", -target_os = "netbsd", -target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", ))] fn test_getpeereid_invalid_fd() { // getpeereid is not POSIX, so error codes are inconsistent between different Unices. @@ -1337,8 +1337,8 @@ fn test_faccessat_not_existing() { AccessFlags::F_OK, AtFlags::empty(), ) - .err() - .unwrap(), + .err() + .unwrap(), Errno::ENOENT ); } @@ -1356,7 +1356,7 @@ fn test_faccessat_none_file_exists() { AccessFlags::R_OK | AccessFlags::W_OK, AtFlags::empty(), ) - .is_ok()); + .is_ok()); } #[test] @@ -1374,5 +1374,5 @@ fn test_faccessat_file_exists() { AccessFlags::R_OK | AccessFlags::W_OK, AtFlags::empty(), ) - .is_ok()); + .is_ok()); } From 4d5e5d83f824f0ff2368636753e68ec189cf3a52 Mon Sep 17 00:00:00 2001 From: SteveLauC Date: Tue, 9 Aug 2022 12:22:41 +0800 Subject: [PATCH 149/358] remove deprecated items --- src/sys/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/time.rs b/src/sys/time.rs index e7a72f0205..0cac7e8a29 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -196,7 +196,7 @@ const SECS_PER_HOUR: i64 = 3600; const TS_MAX_SECONDS: i64 = (i64::MAX / NANOS_PER_SEC) - 1; #[cfg(target_pointer_width = "32")] -const TS_MAX_SECONDS: i64 = ::std::isize::MAX as i64; +const TS_MAX_SECONDS: i64 = isize::MAX as i64; const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS; @@ -456,7 +456,7 @@ const MICROS_PER_SEC: i64 = 1_000_000; const TV_MAX_SECONDS: i64 = (i64::MAX / MICROS_PER_SEC) - 1; #[cfg(target_pointer_width = "32")] -const TV_MAX_SECONDS: i64 = ::std::isize::MAX as i64; +const TV_MAX_SECONDS: i64 = isize::MAX as i64; const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS; From 8c65c3702d8db4c06d155e3e9dc6bb18aba01c15 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 11 Aug 2022 17:47:10 -0600 Subject: [PATCH 150/358] Disable cargo-hack in CI Serde accidentally raised its MSRV to 1.51.0 in a patch release. They don't intent to fix it. Nix uses Serde via cargo-hack in CI. Disable it so we can publish a final release at 1.46.0. --- .cirrus.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 49f259a130..f5c56ab8cb 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -11,6 +11,9 @@ env: # The MSRV TOOLCHAIN: 1.46.0 ZFLAGS: + # Temporarily disable cargo-hack until we raise the MSRV to 1.51.0 or later. + # See https://github.com/nix-rust/nix/pull/1792 + NOHACK: 1 # Tests that don't require executing the build binaries build: &BUILD @@ -64,7 +67,7 @@ task: - cargo test --target i686-unknown-freebsd i386_feature_script: - . $HOME/.cargo/env - - cargo hack check --each-feature --target i686-unknown-freebsd + - if [ -z "$NOHACK" ]; then cargo hack check --each-feature --target i686-unknown-freebsd; fi before_cache_script: rm -rf $CARGO_HOME/registry/index # Test macOS x86_64 in a full VM From 8a63e3e5d9f56ee1745b026945614c65f95a5a25 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 11 Aug 2022 17:57:10 -0600 Subject: [PATCH 151/358] Also raise the MSRV just for cross-tests. Cross uses Serde too. --- .cirrus.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.cirrus.yml b/.cirrus.yml index f5c56ab8cb..ff993086d6 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -95,6 +95,9 @@ task: PATH: $HOME/.cargo/bin:$PATH RUSTFLAGS: --cfg qemu -D warnings TOOL: cross + # Cross needs at least 1.51.0 after Serde accidentally raised its MSRV. + # And Clippy has too many false positives from 1.51.0 through 1.53.0 + TOOLCHAIN: 1.54.0 matrix: - name: Linux arm gnueabi env: From 384d47d25e39b3e2cdbc2a8c28ec68abb709de64 Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Wed, 10 Aug 2022 08:55:45 +0800 Subject: [PATCH 152/358] Folloup for !1778, remove some of the less helpful error msgs --- src/sys/signalfd.rs | 9 ++++----- test/sys/test_aio.rs | 12 ++++-------- test/sys/test_termios.rs | 2 +- test/test_time.rs | 10 +++++----- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/sys/signalfd.rs b/src/sys/signalfd.rs index 3d82b5ba5a..166bb9d246 100644 --- a/src/sys/signalfd.rs +++ b/src/sys/signalfd.rs @@ -147,18 +147,17 @@ mod tests { #[test] fn create_signalfd() { let mask = SigSet::empty(); - let fd = SignalFd::new(&mask); - fd.expect("assert failed"); + SignalFd::new(&mask).unwrap(); } #[test] fn create_signalfd_with_opts() { let mask = SigSet::empty(); - let fd = SignalFd::with_flags( + SignalFd::with_flags( &mask, SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK, - ); - fd.expect("assert failed"); + ) + .unwrap(); } #[test] diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index 12749b1d59..6a36f3e7cf 100644 --- a/test/sys/test_aio.rs +++ b/test/sys/test_aio.rs @@ -101,8 +101,7 @@ mod aio_fsync { 0, SigevNotify::SigevNone, )); - let err = aiof.as_mut().submit(); - err.expect("assert failed"); + aiof.as_mut().submit().unwrap(); poll_aio!(&mut aiof).unwrap(); aiof.as_mut().aio_return().unwrap(); } @@ -148,8 +147,7 @@ mod aio_read { Box::pin(AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone)); aior.as_mut().submit().unwrap(); - let cancelstat = aior.as_mut().cancel(); - cancelstat.expect("assert failed"); + aior.as_mut().cancel().unwrap(); // Wait for aiow to complete, but don't care whether it succeeded let _ = poll_aio!(&mut aior); @@ -341,8 +339,7 @@ mod aio_write { let err = aiow.as_mut().error(); assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); - let cancelstat = aiow.as_mut().cancel(); - cancelstat.expect("assert failed"); + aiow.as_mut().cancel().unwrap(); // Wait for aiow to complete, but don't care whether it succeeded let _ = poll_aio!(&mut aiow); @@ -564,8 +561,7 @@ fn test_aio_cancel_all() { let err = aiocb.as_mut().error(); assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS)); - let cancelstat = aio_cancel_all(f.as_raw_fd()); - cancelstat.expect("assert failed"); + aio_cancel_all(f.as_raw_fd()).unwrap(); // Wait for aiocb to complete, but don't care whether it succeeded let _ = poll_aio!(&mut aiocb); diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs index 11a08cb5f8..aaf00084fa 100644 --- a/test/sys/test_termios.rs +++ b/test/sys/test_termios.rs @@ -22,7 +22,7 @@ fn test_tcgetattr_pty() { let _m = crate::PTSNAME_MTX.lock(); let pty = openpty(None, None).expect("openpty failed"); - termios::tcgetattr(pty.slave).expect("assert failed"); + termios::tcgetattr(pty.slave).unwrap(); close(pty.master).expect("closing the master failed"); close(pty.slave).expect("closing the slave failed"); } diff --git a/test/test_time.rs b/test/test_time.rs index 3e8af653dc..5f76e61a2d 100644 --- a/test/test_time.rs +++ b/test/test_time.rs @@ -29,18 +29,18 @@ pub fn test_clock_gettime() { #[test] pub fn test_clock_getcpuclockid() { let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap(); - clock_gettime(clock_id).expect("assert failed"); + clock_gettime(clock_id).unwrap(); } #[cfg(not(target_os = "redox"))] #[test] pub fn test_clock_id_res() { - ClockId::CLOCK_REALTIME.res().expect("assert failed"); + ClockId::CLOCK_REALTIME.res().unwrap(); } #[test] pub fn test_clock_id_now() { - ClockId::CLOCK_REALTIME.now().expect("assert failed"); + ClockId::CLOCK_REALTIME.now().unwrap(); } #[cfg(any( @@ -54,6 +54,6 @@ pub fn test_clock_id_now() { pub fn test_clock_id_pid_cpu_clock_id() { ClockId::pid_cpu_clock_id(nix::unistd::Pid::this()) .map(ClockId::now) - .expect("assert failed") - .expect("assert failed"); + .unwrap() + .unwrap(); } From 901857f85229e946558c456032ad8e40abae8006 Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Thu, 11 Aug 2022 13:49:32 -0400 Subject: [PATCH 153/358] minor terminology fix in User docs Passwords are hashed, not encrypted. --- src/unistd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unistd.rs b/src/unistd.rs index 70a06b0286..dc8ea820be 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2937,7 +2937,7 @@ feature! { pub struct User { /// Username pub name: String, - /// User password (probably encrypted) + /// User password (probably hashed) pub passwd: CString, /// User ID pub uid: Uid, From 217c3b514148ff2c7bcfdfa808df2316d56db281 Mon Sep 17 00:00:00 2001 From: SteveLauC Date: Fri, 12 Aug 2022 09:13:57 +0800 Subject: [PATCH 154/358] fix CI error --- src/sys/personality.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/personality.rs b/src/sys/personality.rs index 15b59017be..9e285ae6e0 100644 --- a/src/sys/personality.rs +++ b/src/sys/personality.rs @@ -86,7 +86,7 @@ pub fn get() -> Result { /// # use nix::sys::personality::{self, Persona}; /// let mut pers = personality::get().unwrap(); /// assert!(!pers.contains(Persona::ADDR_NO_RANDOMIZE)); -/// personality::set(pers | Persona::ADDR_NO_RANDOMIZE).unwrap().unwrap(); +/// personality::set(pers | Persona::ADDR_NO_RANDOMIZE).unwrap(); /// ``` pub fn set(persona: Persona) -> Result { let res = unsafe { From 29fe67d4cce6c3d79e501a77d3320bb950dc6d0d Mon Sep 17 00:00:00 2001 From: SteveLauC Date: Fri, 12 Aug 2022 12:53:03 +0800 Subject: [PATCH 155/358] feat nix-rust#1733: add F_GET_SEALS and F_ADD_SEALS on FreeBSD --- src/fcntl.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fcntl.rs b/src/fcntl.rs index 0f0c811f34..160b022d77 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -378,7 +378,7 @@ pub(crate) fn at_rawfd(fd: Option) -> raw::c_int { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] #[cfg(feature = "fs")] libc_bitflags!( /// Additional flags for file sealing, which allows for limiting operations on a file. @@ -427,9 +427,9 @@ pub enum FcntlArg<'a> { F_OFD_SETLKW(&'a libc::flock), #[cfg(any(target_os = "linux", target_os = "android"))] F_OFD_GETLK(&'a mut libc::flock), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] F_ADD_SEALS(SealFlag), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] F_GET_SEALS, #[cfg(any(target_os = "macos", target_os = "ios"))] F_FULLFSYNC, @@ -475,9 +475,9 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result { F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock), #[cfg(any(target_os = "android", target_os = "linux"))] F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS), #[cfg(any(target_os = "macos", target_os = "ios"))] F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC), From 42ca951f60ae22a54aa46281bf4dca681884a04b Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 12 Aug 2022 15:50:38 -0600 Subject: [PATCH 156/358] Reenable cargo-hack in CI But instead of building it from source, download pre-built binaries. --- .cirrus.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index ff993086d6..0ab93ff389 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -11,9 +11,6 @@ env: # The MSRV TOOLCHAIN: 1.46.0 ZFLAGS: - # Temporarily disable cargo-hack until we raise the MSRV to 1.51.0 or later. - # See https://github.com/nix-rust/nix/pull/1792 - NOHACK: 1 # Tests that don't require executing the build binaries build: &BUILD @@ -24,7 +21,8 @@ build: &BUILD - $TOOL +$TOOLCHAIN $BUILD $ZFLAGS --target $TARGET --all-targets - $TOOL +$TOOLCHAIN doc $ZFLAGS --no-deps --target $TARGET - $TOOL +$TOOLCHAIN clippy $ZFLAGS --target $TARGET --all-targets -- -D warnings - - if [ -z "$NOHACK" ]; then $TOOL +$TOOLCHAIN install --version 0.5.14 cargo-hack; fi + - if [ -z "$NOHACK" ]; then mkdir -p $HOME/.cargo/bin; export PATH=$HOME/.cargo/bin:$PATH; fi + - if [ -z "$NOHACK" ]; then curl -LsSf https://github.com/taiki-e/cargo-hack/releases/latest/download/cargo-hack-${HOST:-$TARGET}.tar.gz | tar xzf - -C ~/.cargo/bin; fi - if [ -z "$NOHACK" ]; then $TOOL +$TOOLCHAIN hack $ZFLAGS check --target $TARGET --each-feature; fi # Tests that do require executing the binaries @@ -92,6 +90,7 @@ task: env: RUST_TEST_THREADS: 1 # QEMU works best with 1 thread HOME: /tmp/home + HOST: x86_64-unknown-linux-gnu PATH: $HOME/.cargo/bin:$PATH RUSTFLAGS: --cfg qemu -D warnings TOOL: cross @@ -187,6 +186,7 @@ task: image: rust:1.46 env: BUILD: check + HOST: x86_64-unknown-linux-gnu matrix: # Cross claims to support Android, but when it tries to run Nix's tests it # reports undefined symbol references. @@ -276,6 +276,7 @@ task: BUILD: check name: Redox x86_64 env: + HOST: x86_64-unknown-linux-gnu TARGET: x86_64-unknown-redox # Redox's MSRV policy is unclear. Until they define it, use nightly. TOOLCHAIN: nightly @@ -292,6 +293,7 @@ task: image: rustlang/rust:nightly env: BUILD: check + HOST: x86_64-unknown-linux-gnu TOOLCHAIN: nightly ZFLAGS: -Zbuild-std matrix: @@ -318,6 +320,7 @@ task: task: name: Minver env: + HOST: x86_64-unknown-linux-gnu TOOLCHAIN: nightly container: image: rustlang/rust:nightly From 92c76bdab0be998366747ede700c450595756fb5 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 13 Aug 2022 08:46:51 -0600 Subject: [PATCH 157/358] [skip ci] reformat CHANGELOG prior to 0.25.0 release --- CHANGELOG.md | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac0e3f8c69..561b3caacf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1780](https://github.com/nix-rust/nix/pull/1780)) - Added `memfd` on Android. (#[1773](https://github.com/nix-rust/nix/pull/1773)) -- Added ETH_P_ALL to SockProtocol enum +- Added `ETH_P_ALL` to `SockProtocol` enum (#[1768](https://github.com/nix-rust/nix/pull/1768)) - Added four non-standard Linux `SysconfVar` variants (#[1761](https://github.com/nix-rust/nix/pull/1761)) @@ -22,10 +22,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1713](https://github.com/nix-rust/nix/pull/1713)) - impl `From` for `Uid` and `From` for `Gid` (#[1727](https://github.com/nix-rust/nix/pull/1727)) -- impl From for std::net::SocketAddrV4 and - impl From for std::net::SocketAddrV6. +- impl `From` for `std::net::SocketAddrV4` and + impl `From` for `std::net::SocketAddrV6`. (#[1711](https://github.com/nix-rust/nix/pull/1711)) -- Fixed compilation and updated support on Haiku - Added support for the `x86_64-unknown-haiku` target. (#[1703](https://github.com/nix-rust/nix/pull/1703)) - Added `ptrace::read_user` and `ptrace::write_user` for Linux. @@ -36,11 +35,11 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1752](https://github.com/nix-rust/nix/pull/1752)) - Added `signal::SigSet::from_sigset_t_unchecked()`. (#[1741](https://github.com/nix-rust/nix/pull/1741)) -- Added IP_ORIGDSTADDR using Ipv4OrigDstAddr in setsockopt and recvmsg. +- Added the `Ipv4OrigDstAddr` sockopt and control message. (#[1772](https://github.com/nix-rust/nix/pull/1772)) -- Added IPV6_ORIGDSTADDR using Ipv6OrigDstAddr in setsockopt and recvmsg. +- Added the `Ipv6OrigDstAddr` sockopt and control message. (#[1772](https://github.com/nix-rust/nix/pull/1772)) -- Added `IP_SENDSRCADDR` using `Ipv4SendSrcAddr` in `sendmsg`. +- Added the `Ipv4SendSrcAddr` control message. (#[1776](https://github.com/nix-rust/nix/pull/1776)) ### Changed @@ -58,7 +57,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). - `signal:SigSet` is now marked as `repr(transparent)`. (#[1741](https://github.com/nix-rust/nix/pull/1741)) -### Fixed ### Removed - Removed support for resubmitting partially complete `lio_listio` operations. @@ -67,11 +65,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1713](https://github.com/nix-rust/nix/pull/1713)) ## [0.24.2] - 2022-07-17 -### Added -### Changed ### Fixed -- Fixed buffer overflow in nix::sys::socket::recvfrom. +- Fixed buffer overflow in `nix::sys::socket::recvfrom`. (#[1763](https://github.com/nix-rust/nix/pull/1763)) - Enabled `SockaddrStorage::{as_link_addr, as_link_addr_mut}` for Linux-like operating systems. @@ -81,15 +77,11 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1736](https://github.com/nix-rust/nix/pull/1736)) ## [0.24.1] - 2022-04-22 -### Added -### Changed ### Fixed - Fixed `UnixAddr::size` on Linux-based OSes. (#[1702](https://github.com/nix-rust/nix/pull/1702)) -### Removed - ## [0.24.0] - 2022-04-21 ### Added @@ -199,7 +191,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [0.23.1] - 2021-12-16 -### Added ### Changed - Relaxed the bitflags requirement from 1.3.1 to 1.1. This partially reverts From 4d4754a14b080b32b1af16de54dfb822b28b5f06 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 13 Aug 2022 10:02:42 -0600 Subject: [PATCH 158/358] (cargo-release) version 0.25.0 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 561b3caacf..f06e412d93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). -## [Unreleased] - ReleaseDate +## [0.25.0] - 2022-08-13 ### Added - Added `faccessat` diff --git a/Cargo.toml b/Cargo.toml index 18e1742d76..1d96efe548 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2018" -version = "0.24.1" +version = "0.25.0" rust-version = "1.46" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" From 564d72edc7296c0644e471796534b3d3c8de82d3 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 13 Aug 2022 10:03:03 -0600 Subject: [PATCH 159/358] (cargo-release) start next development iteration 0.25.1-alpha.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1d96efe548..565ca9b08d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2018" -version = "0.25.0" +version = "0.25.1-alpha.0" rust-version = "1.46" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" From 596db4ed00f0ccde62353de85f0468529f8059d4 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 13 Aug 2022 10:06:30 -0600 Subject: [PATCH 160/358] [skip ci] add a CHANGELOG section for the next release --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f06e412d93..51f0f31655 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +## [Unreleased] - ReleaseDate +### Added + +### Changed + +### Fixed + +### Removed + ## [0.25.0] - 2022-08-13 ### Added From ea4f1ba5c2bfb69126c88bab5e3fefb0f1b8cecc Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 13 Aug 2022 10:12:44 -0600 Subject: [PATCH 161/358] [skip ci] Rollback master branch to 0.25.0 cargo-release automatically incremented the master branch's version post-release. I don't like that, because it makes it harder for consumers, especially indirect consumers, to use a `[patch.crates-io]` section in their Cargo.toml files. Also, configure cargo-release not to do this again in the future. --- Cargo.toml | 2 +- release.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 565ca9b08d..1d96efe548 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2018" -version = "0.25.1-alpha.0" +version = "0.25.0" rust-version = "1.46" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" diff --git a/release.toml b/release.toml index 23488fbfa5..a47a0f8271 100644 --- a/release.toml +++ b/release.toml @@ -1,3 +1,4 @@ +dev-version = false pre-release-replacements = [ { file="CHANGELOG.md", search="Unreleased", replace="{{version}}" }, { file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}" } From 2cba3afa78d1eed14db72c0f5f6ab9393efb6eb1 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 11 Aug 2022 17:29:31 -0600 Subject: [PATCH 162/358] Raise the MSRV to 1.56.1 in anticipation of the next release And fix some documentation lints warned about by the newer rustdoc. --- .cirrus.yml | 28 ++++++---------------------- CHANGELOG.md | 3 +++ Cargo.toml | 2 +- README.md | 2 +- src/sys/signal.rs | 5 +++-- src/sys/socket/addr.rs | 2 +- 6 files changed, 15 insertions(+), 27 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 0ab93ff389..584d916c5a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -9,7 +9,7 @@ env: RUSTDOCFLAGS: -D warnings TOOL: cargo # The MSRV - TOOLCHAIN: 1.46.0 + TOOLCHAIN: 1.56.1 ZFLAGS: # Tests that don't require executing the build binaries @@ -94,9 +94,6 @@ task: PATH: $HOME/.cargo/bin:$PATH RUSTFLAGS: --cfg qemu -D warnings TOOL: cross - # Cross needs at least 1.51.0 after Serde accidentally raised its MSRV. - # And Clippy has too many false positives from 1.51.0 through 1.53.0 - TOOLCHAIN: 1.54.0 matrix: - name: Linux arm gnueabi env: @@ -146,18 +143,18 @@ task: matrix: - name: Linux aarch64 arm_container: - image: rust:1.46 + image: rust:1.56 env: RUSTFLAGS: --cfg graviton -D warnings TARGET: aarch64-unknown-linux-gnu - name: Linux x86_64 container: - image: rust:1.46 + image: rust:1.56 env: TARGET: x86_64-unknown-linux-gnu - name: Linux x86_64 musl container: - image: rust:1.46 + image: rust:1.56 env: TARGET: x86_64-unknown-linux-musl setup_script: @@ -183,7 +180,7 @@ task: # Tasks for cross-compiling, but no testing task: container: - image: rust:1.46 + image: rust:1.56 env: BUILD: check HOST: x86_64-unknown-linux-gnu @@ -214,10 +211,6 @@ task: - name: Illumos env: TARGET: x86_64-unknown-illumos - # illumos toolchain isn't available via rustup until 1.50 - TOOLCHAIN: 1.50.0 - container: - image: rust:1.50 # Cross claims to support running tests on iOS, but it actually doesn't. # https://github.com/rust-embedded/cross/issues/535 - name: iOS aarch64 @@ -225,16 +218,11 @@ task: # cargo hack tries to invoke the iphonesimulator SDK for iOS NOHACK: 1 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 a macOS - # host, but macOS VMs are more expensive than Linux VMs. - TOOLCHAIN: 1.49.0 - name: iOS x86_64 env: # cargo hack tries to invoke the iphonesimulator SDK for iOS NOHACK: 1 TARGET: x86_64-apple-ios - TOOLCHAIN: 1.49.0 # Cross testing on powerpc fails with "undefined reference to renameat2". # Perhaps cross is using too-old a version? - name: Linux powerpc @@ -254,10 +242,6 @@ task: - name: macOS aarch64 env: TARGET: aarch64-apple-darwin - # macOS aarch64 toolchain isn't available via rustup until 1.49 - TOOLCHAIN: 1.49.0 - container: - image: rust:1.49 - name: NetBSD x86_64 env: TARGET: x86_64-unknown-netbsd @@ -271,7 +255,7 @@ task: task: container: - image: rust:1.46 + image: rust:1.56 env: BUILD: check name: Redox x86_64 diff --git a/CHANGELOG.md b/CHANGELOG.md index 51f0f31655..56ab09fff2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Changed +- The MSRV is now 1.56.1 + ([#1792](https://github.com/nix-rust/nix/pull/1792)) + ### Fixed ### Removed diff --git a/Cargo.toml b/Cargo.toml index 1d96efe548..38a4225800 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2018" version = "0.25.0" -rust-version = "1.46" +rust-version = "1.56" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" license = "MIT" diff --git a/README.md b/README.md index 7c13cf201c..7597ba0afc 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Tier 3: ## Minimum Supported Rust Version (MSRV) -nix is supported on Rust 1.46.0 and higher. Its MSRV will not be +nix is supported on Rust 1.56.1 and higher. Its MSRV will not be changed in the future without bumping the major or minor version. ## Contributing diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 0da9c74ad6..cd3e87ecab 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -911,10 +911,11 @@ pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut Si /// # Arguments /// /// * `pid` - Specifies which processes should receive the signal. -/// - If positive, specifies an individual process +/// - 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`]. +#[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")] +#[cfg_attr(not(target_os = "fuchsia"), doc = "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 diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index ad917cd08f..6b2ba21c20 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -2244,7 +2244,7 @@ pub mod sys_control { /// /// # References /// - /// https://developer.apple.com/documentation/kernel/sockaddr_ctl + /// #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct SysControlAddr(pub(in super::super) libc::sockaddr_ctl); From c6371db662a0b647dc9e45258393017cf27bd6c2 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 14 Aug 2022 10:12:57 -0600 Subject: [PATCH 163/358] Fix a new clippy lint --- test/sys/test_timerfd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sys/test_timerfd.rs b/test/sys/test_timerfd.rs index 927cc70d1d..08e292106c 100644 --- a/test/sys/test_timerfd.rs +++ b/test/sys/test_timerfd.rs @@ -65,5 +65,5 @@ pub fn test_timerfd_unset() { timer.unset().unwrap(); - assert!(timer.get().unwrap() == None); + assert!(timer.get().unwrap().is_none()); } From 7109eb9d2e953f40ee0bbf79e8d427e8dd059930 Mon Sep 17 00:00:00 2001 From: "S.J.R. van Schaik" Date: Thu, 18 Aug 2022 21:49:14 -0400 Subject: [PATCH 164/358] fix microsecond calculation for TimeSpec --- CHANGELOG.md | 3 +++ src/sys/time.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56ab09fff2..2e383277a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Fixed +- Fix microsecond calculation for `TimeSpec`. + ([#1801](https://github.com/nix-rust/nix/pull/1801)) + ### Removed ## [0.25.0] - 2022-08-13 diff --git a/src/sys/time.rs b/src/sys/time.rs index 0cac7e8a29..da65d516b6 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -319,7 +319,7 @@ impl TimeValLike for TimeSpec { } fn num_microseconds(&self) -> i64 { - self.num_nanoseconds() / 1_000_000_000 + self.num_nanoseconds() / 1_000 } fn num_nanoseconds(&self) -> i64 { From e479e8fd48952ae9fdedfb4c7ae57fc722cc15e2 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sat, 20 Aug 2022 19:57:10 -0500 Subject: [PATCH 165/358] Remove MSRV-related workaround for doc aliases --- Cargo.toml | 3 --- build.rs | 7 ------- src/dir.rs | 2 +- src/sys/signal.rs | 12 ++++++------ src/sys/timer.rs | 8 ++++---- src/sys/timerfd.rs | 8 ++++---- src/unistd.rs | 12 ++++++------ 7 files changed, 21 insertions(+), 31 deletions(-) delete mode 100644 build.rs diff --git a/Cargo.toml b/Cargo.toml index 38a4225800..a0f3934c5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,9 +35,6 @@ pin-utils = { version = "0.1.0", optional = true } [target.'cfg(not(target_os = "redox"))'.dependencies] memoffset = { version = "0.6.3", optional = true } -[build-dependencies] -autocfg = "1.1.0" - [features] default = [ "acct", "aio", "dir", "env", "event", "feature", "fs", diff --git a/build.rs b/build.rs deleted file mode 100644 index ad78ab3ffa..0000000000 --- a/build.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let cfg = autocfg::new(); - - if cfg.probe_rustc_version(1, 52) { - autocfg::emit("has_doc_alias"); - } -} diff --git a/src/dir.rs b/src/dir.rs index 6d5fc3b925..cbcd1ea7b5 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -55,7 +55,7 @@ impl Dir { } /// Converts from a file descriptor, closing it on success or failure. - #[cfg_attr(has_doc_alias, doc(alias("fdopendir")))] + #[doc(alias("fdopendir"))] pub fn from_fd(fd: RawFd) -> Result { let d = ptr::NonNull::new(unsafe { libc::fdopendir(fd) }).ok_or_else(|| { let e = Error::last(); diff --git a/src/sys/signal.rs b/src/sys/signal.rs index cd3e87ecab..d3746e609a 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -475,7 +475,7 @@ pub struct SigSet { impl SigSet { /// Initialize to include all signals. - #[cfg_attr(has_doc_alias, doc(alias("sigfillset")))] + #[doc(alias("sigfillset"))] pub fn all() -> SigSet { let mut sigset = mem::MaybeUninit::uninit(); let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) }; @@ -484,7 +484,7 @@ impl SigSet { } /// Initialize to include nothing. - #[cfg_attr(has_doc_alias, doc(alias("sigemptyset")))] + #[doc(alias("sigemptyset"))] pub fn empty() -> SigSet { let mut sigset = mem::MaybeUninit::uninit(); let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) }; @@ -493,25 +493,25 @@ impl SigSet { } /// Add the specified signal to the set. - #[cfg_attr(has_doc_alias, doc(alias("sigaddset")))] + #[doc(alias("sigaddset"))] 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. - #[cfg_attr(has_doc_alias, doc(alias("sigemptyset")))] + #[doc(alias("sigemptyset"))] pub fn clear(&mut self) { unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) }; } /// Remove the specified signal from this set. - #[cfg_attr(has_doc_alias, doc(alias("sigdelset")))] + #[doc(alias("sigdelset"))] 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. - #[cfg_attr(has_doc_alias, doc(alias("sigismember")))] + #[doc(alias("sigismember"))] pub fn contains(&self, signal: Signal) -> bool { let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) }; diff --git a/src/sys/timer.rs b/src/sys/timer.rs index 45ce0e5bf6..dac5e9b599 100644 --- a/src/sys/timer.rs +++ b/src/sys/timer.rs @@ -70,7 +70,7 @@ pub struct Timer(libc::timer_t); impl Timer { /// Creates a new timer based on the clock defined by `clockid`. The details /// of the signal and its handler are defined by the passed `sigevent`. - #[cfg_attr(has_doc_alias, doc(alias("timer_create")))] + #[doc(alias("timer_create"))] pub fn new(clockid: ClockId, mut sigevent: SigEvent) -> Result { let mut timer_id: mem::MaybeUninit = mem::MaybeUninit::uninit(); Errno::result(unsafe { @@ -123,7 +123,7 @@ impl Timer { /// /// Note: Setting a one shot alarm with a 0s TimeSpec disable the alarm /// altogether. - #[cfg_attr(has_doc_alias, doc(alias("timer_settime")))] + #[doc(alias("timer_settime"))] pub fn set(&mut self, expiration: Expiration, flags: TimerSetTimeFlags) -> Result<()> { let timerspec: TimerSpec = expiration.into(); Errno::result(unsafe { @@ -138,7 +138,7 @@ impl Timer { } /// Get the parameters for the alarm currently set, if any. - #[cfg_attr(has_doc_alias, doc(alias("timer_gettime")))] + #[doc(alias("timer_gettime"))] pub fn get(&self) -> Result> { let mut timerspec = TimerSpec::none(); Errno::result(unsafe { libc::timer_gettime(self.0, timerspec.as_mut()) }).map(|_| { @@ -161,7 +161,7 @@ impl Timer { /// 'overrun'. This function returns how many times that has happened to /// this timer, up to `libc::DELAYTIMER_MAX`. If more than the maximum /// number of overruns have happened the return is capped to the maximum. - #[cfg_attr(has_doc_alias, doc(alias("timer_getoverrun")))] + #[doc(alias("timer_getoverrun"))] pub fn overruns(&self) -> i32 { unsafe { libc::timer_getoverrun(self.0) } } diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs index 42860658aa..b57d33c3ba 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -92,7 +92,7 @@ impl TimerFd { /// Creates a new timer based on the clock defined by `clockid`. The /// underlying fd can be assigned specific flags with `flags` (CLOEXEC, /// NONBLOCK). The underlying fd will be closed on drop. - #[cfg_attr(has_doc_alias, doc(alias("timerfd_create")))] + #[doc(alias("timerfd_create"))] pub fn new(clockid: ClockId, flags: TimerFlags) -> Result { Errno::result(unsafe { libc::timerfd_create(clockid as i32, flags.bits()) }) .map(|fd| Self { fd }) @@ -134,7 +134,7 @@ impl TimerFd { /// /// Note: Setting a one shot alarm with a 0s TimeSpec disables the alarm /// altogether. - #[cfg_attr(has_doc_alias, doc(alias("timerfd_settime")))] + #[doc(alias("timerfd_settime"))] pub fn set(&self, expiration: Expiration, flags: TimerSetTimeFlags) -> Result<()> { let timerspec: TimerSpec = expiration.into(); Errno::result(unsafe { @@ -149,7 +149,7 @@ impl TimerFd { } /// Get the parameters for the alarm currently set, if any. - #[cfg_attr(has_doc_alias, doc(alias("timerfd_gettime")))] + #[doc(alias("timerfd_gettime"))] pub fn get(&self) -> Result> { let mut timerspec = TimerSpec::none(); Errno::result(unsafe { libc::timerfd_gettime(self.fd, timerspec.as_mut()) }).map(|_| { @@ -166,7 +166,7 @@ impl TimerFd { } /// Remove the alarm if any is set. - #[cfg_attr(has_doc_alias, doc(alias("timerfd_settime")))] + #[doc(alias("timerfd_settime"))] pub fn unset(&self) -> Result<()> { Errno::result(unsafe { libc::timerfd_settime( diff --git a/src/unistd.rs b/src/unistd.rs index 42e1456aab..02fe4ff68e 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -79,13 +79,13 @@ impl Uid { } /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`. - #[cfg_attr(has_doc_alias, doc(alias("getuid")))] + #[doc(alias("getuid"))] pub fn current() -> Self { getuid() } /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`. - #[cfg_attr(has_doc_alias, doc(alias("geteuid")))] + #[doc(alias("geteuid"))] pub fn effective() -> Self { geteuid() } @@ -136,13 +136,13 @@ impl Gid { } /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`. - #[cfg_attr(has_doc_alias, doc(alias("getgid")))] + #[doc(alias("getgid"))] pub fn current() -> Self { getgid() } /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`. - #[cfg_attr(has_doc_alias, doc(alias("getegid")))] + #[doc(alias("getegid"))] pub fn effective() -> Self { getegid() } @@ -188,13 +188,13 @@ impl Pid { } /// Returns PID of calling process - #[cfg_attr(has_doc_alias, doc(alias("getpid")))] + #[doc(alias("getpid"))] pub fn this() -> Self { getpid() } /// Returns PID of parent of calling process - #[cfg_attr(has_doc_alias, doc(alias("getppid")))] + #[doc(alias("getppid"))] pub fn parent() -> Self { getppid() } From 810f74abbe2a8a4657b5f784ba11599f21ab984a Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Sun, 21 Aug 2022 00:37:17 +0200 Subject: [PATCH 166/358] add line field to Termios struct --- CHANGELOG.md | 3 +++ src/sys/termios.rs | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56ab09fff2..6c296fad5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added `line_discipline` field to `Termios` on Linux, Android and Haiku + ([#1805](https://github.com/nix-rust/nix/pull/1805)) + ### Changed - The MSRV is now 1.56.1 diff --git a/src/sys/termios.rs b/src/sys/termios.rs index c5b27d28ea..b4bb3d85ad 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -181,6 +181,15 @@ pub struct Termios { pub local_flags: LocalFlags, /// Control characters (see `termios.c_cc` documentation) pub control_chars: [libc::cc_t; NCCS], + /// Line discipline (see `termios.c_line` documentation) + #[cfg(any( + target_os = "linux", + target_os = "android", + ))] + pub line_discipline: libc::cc_t, + /// Line discipline (see `termios.c_line` documentation) + #[cfg(target_os = "haiku")] + pub line_discipline: libc::c_char, } impl Termios { @@ -196,6 +205,14 @@ impl Termios { termios.c_cflag = self.control_flags.bits(); termios.c_lflag = self.local_flags.bits(); termios.c_cc = self.control_chars; + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "haiku", + ))] + { + termios.c_line = self.line_discipline; + } } self.inner.borrow() } @@ -214,6 +231,14 @@ impl Termios { termios.c_cflag = self.control_flags.bits(); termios.c_lflag = self.local_flags.bits(); termios.c_cc = self.control_chars; + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "haiku", + ))] + { + termios.c_line = self.line_discipline; + } } self.inner.as_ptr() } @@ -226,6 +251,14 @@ impl Termios { self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag); self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag); self.control_chars = termios.c_cc; + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "haiku", + ))] + { + self.line_discipline = termios.c_line; + } } } @@ -238,6 +271,12 @@ impl From for Termios { control_flags: ControlFlags::from_bits_truncate(termios.c_cflag), local_flags: LocalFlags::from_bits_truncate(termios.c_lflag), control_chars: termios.c_cc, + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "haiku", + ))] + line_discipline: termios.c_line, } } } From 3dc163e780492fa7b2027460d062bc93adc22d77 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sat, 20 Aug 2022 16:36:05 -0500 Subject: [PATCH 167/358] Add sched_getaffinity and sched_setaffinity on FreeBSD --- CHANGELOG.md | 4 +++- src/sched.rs | 16 ++++++++++++---- test/test.rs | 1 + 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7862427f69..9aabc244d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added `sched_getaffinity` and `sched_setaffinity` on FreeBSD. + ([#1804](https://github.com/nix-rust/nix/pull/1804)) - Added `line_discipline` field to `Termios` on Linux, Android and Haiku - ([#1805](https://github.com/nix-rust/nix/pull/1805)) + ([#1805](https://github.com/nix-rust/nix/pull/1805)) ### Changed diff --git a/src/sched.rs b/src/sched.rs index e9a326e261..943ed6ecb0 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -142,10 +142,10 @@ mod sched_linux_like { } } -#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] pub use self::sched_affinity::*; -#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] mod sched_affinity { use crate::errno::Errno; use std::mem; @@ -157,10 +157,13 @@ mod sched_affinity { /// sched_getaffinity for example. /// /// This is a wrapper around `libc::cpu_set_t`. - #[repr(C)] + #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct CpuSet { + #[cfg(not(target_os = "freebsd"))] cpu_set: libc::cpu_set_t, + #[cfg(target_os = "freebsd")] + cpu_set: libc::cpuset_t, } impl CpuSet { @@ -205,7 +208,12 @@ mod sched_affinity { /// Return the maximum number of CPU in CpuSet pub const fn count() -> usize { - 8 * mem::size_of::() + #[cfg(not(target_os = "freebsd"))] + let bytes = mem::size_of::(); + #[cfg(target_os = "freebsd")] + let bytes = mem::size_of::(); + + 8 * bytes } } diff --git a/test/test.rs b/test/test.rs index f725ef97a0..6b42aad950 100644 --- a/test/test.rs +++ b/test/test.rs @@ -36,6 +36,7 @@ mod test_resource; #[cfg(any( target_os = "android", target_os = "dragonfly", + all(target_os = "freebsd", fbsd14), target_os = "linux" ))] mod test_sched; From 29f4d52df6307d2c181c1eeaf81785ba0df1dfac Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 25 Aug 2022 19:25:00 -0600 Subject: [PATCH 168/358] Eliminate Cargo.lock.msrv We no longer need it since updating our MSRV to 1.56.1. Issue #1809 --- .cirrus.yml | 5 - Cargo.lock.msrv | 366 ------------------------------------------------ 2 files changed, 371 deletions(-) delete mode 100644 Cargo.lock.msrv diff --git a/.cirrus.yml b/.cirrus.yml index 584d916c5a..30f1b122a2 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -56,7 +56,6 @@ task: - . $HOME/.cargo/env - rustup target add i686-unknown-freebsd - rustup component add --toolchain $TOOLCHAIN clippy - - cp Cargo.lock.msrv Cargo.lock << : *TEST i386_test_script: - . $HOME/.cargo/env @@ -80,7 +79,6 @@ task: - sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN - . $HOME/.cargo/env - rustup component add --toolchain $TOOLCHAIN clippy - - cp Cargo.lock.msrv Cargo.lock << : *TEST before_cache_script: rm -rf $CARGO_HOME/registry/index @@ -134,7 +132,6 @@ task: - sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN - . $HOME/.cargo/env - cargo install cross --version 0.2.1 # cross 0.2.2 bumped the MSRV to 1.58.1 - - cp Cargo.lock.msrv Cargo.lock << : *TEST before_cache_script: rm -rf $CARGO_HOME/registry/index @@ -160,7 +157,6 @@ task: setup_script: - rustup target add $TARGET - rustup component add clippy - - cp Cargo.lock.msrv Cargo.lock << : *TEST before_cache_script: rm -rf $CARGO_HOME/registry/index @@ -249,7 +245,6 @@ task: - rustup target add $TARGET - rustup toolchain install $TOOLCHAIN --profile minimal --target $TARGET - rustup component add --toolchain $TOOLCHAIN clippy - - cp Cargo.lock.msrv Cargo.lock << : *BUILD before_cache_script: rm -rf $CARGO_HOME/registry/index diff --git a/Cargo.lock.msrv b/Cargo.lock.msrv deleted file mode 100644 index a917bb6bb6..0000000000 --- a/Cargo.lock.msrv +++ /dev/null @@ -1,366 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "assert-impl" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40e79d69c321c1d98eb55e4890ed07e885c071b9575960a9e742d2931581f496" - -[[package]] -name = "autocfg" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" - -[[package]] -name = "bitflags" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" - -[[package]] -name = "byteorder" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" - -[[package]] -name = "caps" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d092fbb6657fb1f98a7da70c14335ac97e5a9477e1a8156d4bbf19a3a7aece51" -dependencies = [ - "errno", - "libc", - "thiserror", -] - -[[package]] -name = "cfg-if" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "errno" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2c858c42ac0b88532f48fca88b0ed947cad4f1f64d904bcd6c9f138f7b95d70" -dependencies = [ - "kernel32-sys", - "libc", - "winapi 0.2.4", -] - -[[package]] -name = "getrandom" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" -dependencies = [ - "cfg-if 0.1.2", - "libc", - "wasi", -] - -[[package]] -name = "instant" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1ca084b49bfd975182288e1a5f1d27ea34ff2d6ae084ae5e66e1652427eada" -dependencies = [ - "winapi 0.2.4", - "winapi-build", -] - -[[package]] -name = "lazy_static" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" - -[[package]] -name = "libc" -version = "0.2.112" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" - -[[package]] -name = "lock_api" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "memoffset" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d" -dependencies = [ - "autocfg", -] - -[[package]] -name = "nix" -version = "0.23.1" -dependencies = [ - "assert-impl", - "bitflags", - "caps", - "cfg-if 1.0.0", - "lazy_static", - "libc", - "memoffset", - "parking_lot", - "rand", - "semver", - "sysctl", - "tempfile", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi 0.3.9", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" - -[[package]] -name = "proc-macro2" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f287c234c9b2d0308d692dee5c449c1a171167a6f8150f7cf2a49d8fd96967" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab938ebe6f1c82426b5fb82eaf10c3e3028c53deaa3fbe38f5904b37cf4d767" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76330fb486679b4ace3670f117bbc9e16204005c4bde9c4bd372f45bed34f12" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", - "rand_hc", -] - -[[package]] -name = "rand_chacha" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", -] - -[[package]] -name = "redox_syscall" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" -dependencies = [ - "bitflags", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc5b3ce5d5ea144bb04ebd093a9e14e9765bcfec866aecda9b6dec43b3d1e24" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b5842e81eb9bbea19276a9dbbda22ac042532f390a67ab08b895617978abf3" - -[[package]] -name = "smallvec" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" - -[[package]] -name = "syn" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f8c8eab7d9f493cd89d4068085651d81ac7d39c56eb64f7158ea514b156e280" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "sysctl" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7da87d95ab91294ebf2132bf36e1c4f6ac1df11db4c63105858cb175e2141c" -dependencies = [ - "byteorder", - "errno", - "libc", -] - -[[package]] -name = "tempfile" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "rand", - "redox_syscall", - "remove_dir_all", - "winapi 0.3.9", -] - -[[package]] -name = "thiserror" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d032db01164196ffdea5d016aa5cacd9d163a4fb00b85e9fc3ad18c5b1a3951d" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d53f5a0d2bd66d1d841e69a4beb74a226216b3f158ff0c534578f76e7beac9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-xid" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "winapi" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5350e40d908c7e8b9e5c9edb541ca47cc617c6229d3575a46da6f550f36c96fd" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" From cf15c2bb5505231bc3128ef61522336e315e2169 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Tue, 23 Aug 2022 17:05:19 -0500 Subject: [PATCH 169/358] expose memfd on freebsd --- CHANGELOG.md | 2 ++ src/sys/memfd.rs | 19 ++++++++++++++++++- src/sys/mod.rs | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aabc244d9..5891b4126f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1804](https://github.com/nix-rust/nix/pull/1804)) - Added `line_discipline` field to `Termios` on Linux, Android and Haiku ([#1805](https://github.com/nix-rust/nix/pull/1805)) +- Expose the memfd module on FreeBSD (memfd was added in FreeBSD 13) + ([#1808](https://github.com/nix-rust/nix/pull/1808)) ### Changed diff --git a/src/sys/memfd.rs b/src/sys/memfd.rs index 642676b431..9f08dbb2bf 100644 --- a/src/sys/memfd.rs +++ b/src/sys/memfd.rs @@ -1,6 +1,8 @@ //! Interfaces for managing memory-backed files. use std::os::unix::io::RawFd; +use cfg_if::cfg_if; + use crate::Result; use crate::errno::Errno; use std::ffi::CStr; @@ -40,7 +42,22 @@ libc_bitflags!( /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result { let res = unsafe { - libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits()) + cfg_if! { + if #[cfg(all( + // Android does not have a memfd_create symbol + not(target_os = "android"), + any( + target_os = "freebsd", + // If the OS is Linux, gnu and musl expose a memfd_create symbol but not uclibc + target_env = "gnu", + target_env = "musl", + )))] + { + libc::memfd_create(name.as_ptr(), flags.bits()) + } else { + libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits()) + } + } }; Errno::result(res).map(|r| r as RawFd) diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 979d623b89..2065059de8 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -50,7 +50,7 @@ feature! { #[macro_use] pub mod ioctl; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] feature! { #![feature = "fs"] pub mod memfd; From 4d38456cab60843d212a62af7066ceac7bc6011e Mon Sep 17 00:00:00 2001 From: WATANABE Yuki Date: Sun, 11 Sep 2022 23:01:08 +0900 Subject: [PATCH 170/358] Handle unacceptable name gracefully in {User,Group}::from_name Calling `unwrap` on the result of `CString::new` may cause the current thread to panic, which is a bit surprising undocumented behavior. It would be more reasonable to treat the erroneous name as a non-existing user or group. --- CHANGELOG.md | 3 +++ src/unistd.rs | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aabc244d9..63cea70dcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fix microsecond calculation for `TimeSpec`. ([#1801](https://github.com/nix-rust/nix/pull/1801)) +- Fix `User::from_name` and `Group::from_name` panicking + when given a name containing a nul. + ([#1815](https://github.com/nix-rust/nix/pull/1815)) ### Removed diff --git a/src/unistd.rs b/src/unistd.rs index 02fe4ff68e..63795cac22 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -3143,7 +3143,10 @@ impl User { /// assert_eq!(res.name, "root"); /// ``` pub fn from_name(name: &str) -> Result> { - let name = CString::new(name).unwrap(); + let name = match CString::new(name) { + Ok(c_str) => c_str, + Err(_nul_error) => return Ok(None), + }; User::from_anything(|pwd, cbuf, cap, res| { unsafe { libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) } }) @@ -3268,7 +3271,10 @@ impl Group { /// assert!(res.name == "root"); /// ``` pub fn from_name(name: &str) -> Result> { - let name = CString::new(name).unwrap(); + let name = match CString::new(name) { + Ok(c_str) => c_str, + Err(_nul_error) => return Ok(None), + }; Group::from_anything(|grp, cbuf, cap, res| { unsafe { libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) } }) From 3aedbfa08ee7459025d8f45bda034d8fd4d5c9b7 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 11 Sep 2022 16:25:33 -0600 Subject: [PATCH 171/358] Clippy cleanup --- src/fcntl.rs | 4 +--- src/sys/socket/mod.rs | 2 +- src/sys/socket/sockopt.rs | 2 +- test/test_fcntl.rs | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/fcntl.rs b/src/fcntl.rs index 160b022d77..650828345b 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -809,9 +809,7 @@ pub fn fspacectl_all(fd: RawFd, offset: libc::off_t, len: libc::off_t) 0, // No flags are currently supported &mut rqsr )}; - if let Err(e) = Errno::result(res) { - return Err(e); - } + Errno::result(res)?; } Ok(()) } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index ecbf30ad44..6677420551 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1459,7 +1459,7 @@ pub fn sendmsg(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage], // because subsequent code will not clear the padding bytes. let mut cmsg_buffer = vec![0u8; capacity]; - let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], &iov, &cmsgs, addr); + let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], iov, cmsgs, addr); let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) }; diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 1cbb223ece..b3828b316f 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -816,7 +816,7 @@ struct SetBool { impl<'a> Set<'a, bool> for SetBool { fn new(val: &'a bool) -> SetBool { - SetBool { val: if *val { 1 } else { 0 } } + SetBool { val: i32::from(*val) } } fn ffi_ptr(&self) -> *const c_void { diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index f4adee21fc..bc65b2601a 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -216,7 +216,7 @@ fn test_readlink() { let src = tempdir.path().join("a"); let dst = tempdir.path().join("b"); println!("a: {:?}, b: {:?}", &src, &dst); - fs::symlink(&src.as_path(), &dst.as_path()).unwrap(); + fs::symlink(src.as_path(), dst.as_path()).unwrap(); let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); let expected_dir = src.to_str().unwrap(); From e0918dc4d100a03756772fb6ac5152b4019c388d Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Mon, 12 Sep 2022 07:07:36 +0800 Subject: [PATCH 172/358] fix issue1814 --- CHANGELOG.md | 2 ++ src/sys/utsname.rs | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aabc244d9..558733d810 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1804](https://github.com/nix-rust/nix/pull/1804)) - Added `line_discipline` field to `Termios` on Linux, Android and Haiku ([#1805](https://github.com/nix-rust/nix/pull/1805)) +- Added `domainname` field of `UtsName` on Android and Linux + ([#1817](https://github.com/nix-rust/nix/pull/1817)) ### Changed diff --git a/src/sys/utsname.rs b/src/sys/utsname.rs index 5bd3a539ae..0448cb2990 100644 --- a/src/sys/utsname.rs +++ b/src/sys/utsname.rs @@ -35,6 +35,12 @@ impl UtsName { pub fn machine(&self) -> &OsStr { cast_and_trim(&self.0.machine) } + + /// NIS or YP domain name of this machine. + #[cfg(any(target_os = "android", target_os = "linux"))] + pub fn domainname(&self) -> &OsStr { + cast_and_trim(&self.0.domainname) + } } /// Get system identification From 9b232dd5815c9f78d13e061a407468a6fad53142 Mon Sep 17 00:00:00 2001 From: wdsgyj Date: Sun, 25 Sep 2022 02:17:51 +0800 Subject: [PATCH 173/358] fix crash on Android platform --- CHANGELOG.md | 2 ++ src/unistd.rs | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5982d70c97..7356b005a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fix `User::from_name` and `Group::from_name` panicking when given a name containing a nul. ([#1815](https://github.com/nix-rust/nix/pull/1815)) +- Fix `User::from_uid` and `User::from_name` crash on Android platform. + ([#1824](https://github.com/nix-rust/nix/pull/1824)) ### Removed diff --git a/src/unistd.rs b/src/unistd.rs index 63795cac22..e7a64dabb4 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2984,12 +2984,12 @@ impl From<&libc::passwd> for User { fn from(pw: &libc::passwd) -> User { unsafe { User { - name: CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned(), - passwd: CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes()).unwrap(), + name: if pw.pw_name.is_null() { Default::default() } else { CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned() }, + passwd: if pw.pw_passwd.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes()).unwrap() }, #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] - gecos: CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes()).unwrap(), - dir: PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_dir).to_bytes())), - shell: PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_shell).to_bytes())), + gecos: if pw.pw_gecos.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes()).unwrap() }, + dir: if pw.pw_dir.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_dir).to_bytes())) }, + shell: if pw.pw_shell.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_shell).to_bytes())) }, uid: Uid::from_raw(pw.pw_uid), gid: Gid::from_raw(pw.pw_gid), #[cfg(not(any(target_os = "android", From 5ae4f8299e7c3ac38fd7c7cb4d05b1fe7402be86 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sun, 25 Sep 2022 16:54:19 +0800 Subject: [PATCH 174/358] bump libc to 0.2.133 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a0f3934c5c..240a3f0b7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.127", features = [ "extra_traits" ] } +libc = { version = "0.2.133", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } From 945f743aa7003b6cb6c646d9208713052cbc2701 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 27 Sep 2022 14:26:35 +0200 Subject: [PATCH 175/358] Add a `sched_getcpu` wrapper --- CHANGELOG.md | 2 ++ src/sched.rs | 7 +++++++ test/test_sched.rs | 6 +++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5982d70c97..21d397e2fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added `sched_getcpu` on platforms that support it. + ([#1825](https://github.com/nix-rust/nix/pull/1825)) - Added `sched_getaffinity` and `sched_setaffinity` on FreeBSD. ([#1804](https://github.com/nix-rust/nix/pull/1804)) - Added `line_discipline` field to `Termios` on Linux, Android and Haiku diff --git a/src/sched.rs b/src/sched.rs index 943ed6ecb0..aa2b90b4d8 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -290,6 +290,13 @@ mod sched_affinity { Errno::result(res).and(Ok(cpuset)) } + + /// Determines the CPU on which the calling thread is running. + pub fn sched_getcpu() -> Result { + let res = unsafe { libc::sched_getcpu() }; + + Errno::result(res).map(|int| int as usize) + } } /// Explicitly yield the processor to other threads. diff --git a/test/test_sched.rs b/test/test_sched.rs index ebf346db16..c52616b8bb 100644 --- a/test/test_sched.rs +++ b/test/test_sched.rs @@ -1,4 +1,4 @@ -use nix::sched::{sched_getaffinity, sched_setaffinity, CpuSet}; +use nix::sched::{sched_getaffinity, sched_getcpu, sched_setaffinity, CpuSet}; use nix::unistd::Pid; #[test] @@ -30,6 +30,10 @@ fn test_sched_affinity() { ) } + // Now check that we're also currently running on the CPU in question. + let cur_cpu = sched_getcpu().unwrap(); + assert_eq!(cur_cpu, last_valid_cpu); + // Finally, reset the initial CPU set sched_setaffinity(Pid::from_raw(0), &initial_affinity).unwrap(); } From c20fab79b0afab280dcdb557abf3fb28b800f29d Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Mon, 26 Sep 2022 16:27:11 +0200 Subject: [PATCH 176/358] statfs: add namespace fs magic Namespace filesystem magic is missing from FsType constants. --- CHANGELOG.md | 2 ++ src/sys/statfs.rs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45e191a62f..e0c2e3b88f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added `NSFS_MAGIC` FsType on Linux and Android. + ([#1829](https://github.com/nix-rust/nix/pull/1829)) - Added `sched_getcpu` on platforms that support it. ([#1825](https://github.com/nix-rust/nix/pull/1825)) - Added `sched_getaffinity` and `sched_setaffinity` on FreeBSD. diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index e8c06e4e3f..8d2b283beb 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -205,6 +205,9 @@ pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC as #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const XENFS_SUPER_MAGIC: FsType = FsType(libc::XENFS_SUPER_MAGIC as fs_type_t); +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(missing_docs)] +pub const NSFS_MAGIC: FsType = FsType(libc::NSFS_MAGIC as fs_type_t); impl Statfs { From 55022bb67a13829263455f5ff68da52b23b643fe Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 30 Sep 2022 11:07:55 -0300 Subject: [PATCH 177/358] libc: bump libc to 0.2.134 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 240a3f0b7a..290ba8e330 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.133", features = [ "extra_traits" ] } +libc = { version = "0.2.134", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } From 5ec038e915542391a98499aaf6149542e4cb16ea Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sun, 2 Oct 2022 10:46:22 +0800 Subject: [PATCH 178/358] re-export RLIM_INFINITY from libc --- CHANGELOG.md | 2 ++ src/sys/resource.rs | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0c2e3b88f..080ea0e7f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1808](https://github.com/nix-rust/nix/pull/1808)) - Added `domainname` field of `UtsName` on Android and Linux ([#1817](https://github.com/nix-rust/nix/pull/1817)) +- Re-export `RLIM_INFINITY` from `libc` + ([#1831](https://github.com/nix-rust/nix/pull/1831)) ### Changed diff --git a/src/sys/resource.rs b/src/sys/resource.rs index e9a11d95d4..788444d876 100644 --- a/src/sys/resource.rs +++ b/src/sys/resource.rs @@ -6,6 +6,7 @@ use crate::errno::Errno; use crate::sys::time::TimeVal; use crate::Result; pub use libc::rlim_t; +pub use libc::RLIM_INFINITY; use std::mem; cfg_if! { @@ -175,7 +176,7 @@ libc_enum! { /// Get the current processes resource limits /// -/// The special value `RLIM_INFINITY` indicates that no limit will be +/// The special value [`RLIM_INFINITY`] indicates that no limit will be /// enforced. /// /// # Parameters @@ -224,7 +225,7 @@ pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> { /// * `hard_limit`: The ceiling for the soft limit. Must be lower or equal to /// the current hard limit for non-root users. /// -/// The special value `RLIM_INFINITY` indicates that no limit will be +/// The special value [`RLIM_INFINITY`] indicates that no limit will be /// enforced. /// /// # Examples From e7992231a34963a57d2297fe1ea7cdaf090efa8b Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sat, 8 Oct 2022 12:53:37 +0800 Subject: [PATCH 179/358] add syncfs on linux --- CHANGELOG.md | 2 ++ src/unistd.rs | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 080ea0e7f2..8678e3ed86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1817](https://github.com/nix-rust/nix/pull/1817)) - Re-export `RLIM_INFINITY` from `libc` ([#1831](https://github.com/nix-rust/nix/pull/1831)) +- Added `syncfs(2)` on Linux + ([#1833](https://github.com/nix-rust/nix/pull/1833)) ### Changed diff --git a/src/unistd.rs b/src/unistd.rs index e7a64dabb4..daa76b74d0 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -1354,6 +1354,17 @@ pub fn sync() { unsafe { libc::sync() }; } +/// Commit filesystem caches containing file referred to by the open file +/// descriptor `fd` to disk +/// +/// See also [syncfs(2)](https://man7.org/linux/man-pages/man2/sync.2.html) +#[cfg(target_os = "linux")] +pub fn syncfs(fd: RawFd) -> Result<()> { + let res = unsafe { libc::syncfs(fd) }; + + Errno::result(res).map(drop) +} + /// Synchronize changes to a file /// /// See also [fsync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html) From 6e7bddd1540565a9da7f7e56ddf5851d1786a3dd Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sat, 8 Oct 2022 13:48:59 -0500 Subject: [PATCH 180/358] Fix clippy warnings on nightly Clippy is now smarter about detecting unnecessary casts and useless conversions, which means we need to be more explicit about when the conversions are needed for a subset of platforms. Required changes found by repeatedly running the following command against a list of the supported platforms. `xargs -t -I {} sh -c "cargo clippy -Zbuild-std --target {} --all-targets -- -D warnings || exit 255"` I removed the casts it complained about, and then restored them with an `#[allow]` if a later target needed the cast. --- src/dir.rs | 2 ++ src/errno.rs | 2 +- src/sys/pthread.rs | 1 + src/sys/socket/addr.rs | 32 +++++++++++++++++--------------- src/sys/socket/mod.rs | 12 +++++++++--- src/sys/socket/sockopt.rs | 2 +- src/sys/statfs.rs | 4 ++++ src/sys/sysinfo.rs | 4 ++++ src/sys/termios.rs | 4 ++++ src/sys/time.rs | 8 ++++++++ src/sys/uio.rs | 2 +- test/sys/test_ioctl.rs | 8 ++++++++ test/sys/test_stat.rs | 2 ++ test/test_mount.rs | 4 ++-- 14 files changed, 64 insertions(+), 23 deletions(-) diff --git a/src/dir.rs b/src/dir.rs index cbcd1ea7b5..e36a8aa650 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -208,6 +208,8 @@ pub enum Type { impl Entry { /// Returns the inode number (`d_ino`) of the underlying `dirent`. #[allow(clippy::useless_conversion)] // Not useless on all OSes + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] pub fn ino(&self) -> u64 { cfg_if! { if #[cfg(any(target_os = "android", diff --git a/src/errno.rs b/src/errno.rs index 912fb94f55..0c5b0edaa5 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -47,7 +47,7 @@ fn clear() { /// Returns the platform-specific value of errno pub fn errno() -> i32 { - unsafe { (*errno_location()) as i32 } + unsafe { *errno_location() } } impl Errno { diff --git a/src/sys/pthread.rs b/src/sys/pthread.rs index fd81f3ed38..6bad03a4d4 100644 --- a/src/sys/pthread.rs +++ b/src/sys/pthread.rs @@ -28,6 +28,7 @@ feature! { /// won't send any signal. /// /// [`pthread_kill(3)`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_kill.html +#[allow(clippy::not_unsafe_ptr_arg_deref)] #[cfg(not(target_os = "redox"))] pub fn pthread_kill(thread: Pthread, signal: T) -> Result<()> where T: Into> diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 6b2ba21c20..07d68e1fd0 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -935,7 +935,7 @@ impl SockaddrLike for UnixAddr { return None; } } - if (*addr).sa_family as i32 != libc::AF_UNIX as i32 { + if (*addr).sa_family as i32 != libc::AF_UNIX { return None; } let mut su: libc::sockaddr_un = mem::zeroed(); @@ -1192,7 +1192,7 @@ impl SockaddrLike for SockaddrIn { return None; } } - if (*addr).sa_family as i32 != libc::AF_INET as i32 { + if (*addr).sa_family as i32 != libc::AF_INET { return None; } Some(Self(ptr::read_unaligned(addr as *const _))) @@ -1298,7 +1298,7 @@ impl SockaddrLike for SockaddrIn6 { return None; } } - if (*addr).sa_family as i32 != libc::AF_INET6 as i32 { + if (*addr).sa_family as i32 != libc::AF_INET6 { return None; } Some(Self(ptr::read_unaligned(addr as *const _))) @@ -2101,7 +2101,7 @@ pub mod netlink { return None; } } - if (*addr).sa_family as i32 != libc::AF_NETLINK as i32 { + if (*addr).sa_family as i32 != libc::AF_NETLINK { return None; } Some(Self(ptr::read_unaligned(addr as *const _))) @@ -2145,7 +2145,7 @@ pub mod alg { return None; } } - if (*addr).sa_family as i32 != libc::AF_ALG as i32 { + if (*addr).sa_family as i32 != libc::AF_ALG { return None; } Some(Self(ptr::read_unaligned(addr as *const _))) @@ -2259,7 +2259,7 @@ pub mod sys_control { return None; } } - if (*addr).sa_family as i32 != libc::AF_SYSTEM as i32 { + if (*addr).sa_family as i32 != libc::AF_SYSTEM { return None; } Some(Self(ptr::read_unaligned(addr as *const _))) @@ -2366,12 +2366,12 @@ mod datalink { // Returns an Option just for cross-platform compatibility pub fn addr(&self) -> Option<[u8; 6]> { Some([ - self.0.sll_addr[0] as u8, - self.0.sll_addr[1] as u8, - self.0.sll_addr[2] as u8, - self.0.sll_addr[3] as u8, - self.0.sll_addr[4] as u8, - self.0.sll_addr[5] as u8, + self.0.sll_addr[0], + self.0.sll_addr[1], + self.0.sll_addr[2], + self.0.sll_addr[3], + self.0.sll_addr[4], + self.0.sll_addr[5], ]) } } @@ -2402,7 +2402,7 @@ mod datalink { return None; } } - if (*addr).sa_family as i32 != libc::AF_PACKET as i32 { + if (*addr).sa_family as i32 != libc::AF_PACKET { return None; } Some(Self(ptr::read_unaligned(addr as *const _))) @@ -2477,6 +2477,8 @@ mod datalink { } /// Physical-layer address (MAC) + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] pub fn addr(&self) -> Option<[u8; 6]> { let nlen = self.nlen(); let data = self.0.sdl_data; @@ -2522,7 +2524,7 @@ mod datalink { return None; } } - if (*addr).sa_family as i32 != libc::AF_LINK as i32 { + if (*addr).sa_family as i32 != libc::AF_LINK { return None; } Some(Self(ptr::read_unaligned(addr as *const _))) @@ -2566,7 +2568,7 @@ pub mod vsock { return None; } } - if (*addr).sa_family as i32 != libc::AF_VSOCK as i32 { + if (*addr).sa_family as i32 != libc::AF_VSOCK { return None; } Some(Self(ptr::read_unaligned(addr as *const _))) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 6677420551..461607d12f 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -839,6 +839,8 @@ impl ControlMessageOwned { unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned { let p = CMSG_DATA(header); + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] let len = header as *const _ as usize + header.cmsg_len as usize - p as usize; match (header.cmsg_level, header.cmsg_type) { @@ -1643,7 +1645,7 @@ pub fn recvmmsg<'a, I, S>( } ); - (msg_controllen as usize, &mut d.cmsg_buffer) + (msg_controllen, &mut d.cmsg_buffer) }).collect(); let timeout = if let Some(mut t) = timeout { @@ -1662,6 +1664,8 @@ pub fn recvmmsg<'a, I, S>( .zip(addresses.iter().map(|addr| unsafe{addr.assume_init()})) .zip(results.into_iter()) .map(|((mmsghdr, address), (msg_controllen, cmsg_buffer))| { + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] unsafe { read_mhdr( mmsghdr.msg_hdr, @@ -1684,6 +1688,8 @@ unsafe fn read_mhdr<'a, 'b, S>( ) -> RecvMsg<'b, S> where S: SockaddrLike { + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] let cmsghdr = { if mhdr.msg_controllen > 0 { // got control message(s) @@ -2131,7 +2137,7 @@ pub fn sockaddr_storage_to_addr( match c_int::from(addr.ss_family) { #[cfg(feature = "net")] libc::AF_INET => { - assert!(len as usize >= mem::size_of::()); + assert!(len >= mem::size_of::()); let sin = unsafe { *(addr as *const sockaddr_storage as *const sockaddr_in) }; @@ -2139,7 +2145,7 @@ pub fn sockaddr_storage_to_addr( } #[cfg(feature = "net")] libc::AF_INET6 => { - assert!(len as usize >= mem::size_of::()); + assert!(len >= mem::size_of::()); let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) }; diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index b3828b316f..90111ec54d 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -863,7 +863,7 @@ struct SetU8 { impl<'a> Set<'a, u8> for SetU8 { fn new(val: &'a u8) -> SetU8 { - SetU8 { val: *val as u8 } + SetU8 { val: *val } } fn ffi_ptr(&self) -> *const c_void { diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 8d2b283beb..a1c1aaa931 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -705,6 +705,8 @@ mod test { assert_fs_equals(fs, vfs); } + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] fn assert_fs_equals(fs: Statfs, vfs: Statvfs) { assert_eq!(fs.files() as u64, vfs.files() as u64); assert_eq!(fs.blocks() as u64, vfs.blocks() as u64); @@ -752,6 +754,8 @@ mod test { assert_fs_equals_strict(fs.unwrap(), vfs.unwrap()) } + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) { assert_eq!(fs.files_free() as u64, vfs.files_free() as u64); assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64); diff --git a/src/sys/sysinfo.rs b/src/sys/sysinfo.rs index 96f0433075..e8aa00b00d 100644 --- a/src/sys/sysinfo.rs +++ b/src/sys/sysinfo.rs @@ -30,6 +30,8 @@ impl SysInfo { } /// Returns the time since system boot. + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] pub fn uptime(&self) -> Duration { // Truncate negative values to 0 Duration::from_secs(cmp::max(self.0.uptime, 0) as u64) @@ -64,6 +66,8 @@ impl SysInfo { self.scale_mem(self.0.freeram) } + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] fn scale_mem(&self, units: mem_blocks_t) -> u64 { units as u64 * self.0.mem_unit as u64 } diff --git a/src/sys/termios.rs b/src/sys/termios.rs index b4bb3d85ad..4ff4e674da 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -933,6 +933,8 @@ cfg_if!{ /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). /// /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] pub fn cfgetispeed(termios: &Termios) -> u32 { let inner_termios = termios.get_libc_termios(); unsafe { libc::cfgetispeed(&*inner_termios) as u32 } @@ -942,6 +944,8 @@ cfg_if!{ /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). /// /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] pub fn cfgetospeed(termios: &Termios) -> u32 { let inner_termios = termios.get_libc_termios(); unsafe { libc::cfgetospeed(&*inner_termios) as u32 } diff --git a/src/sys/time.rs b/src/sys/time.rs index da65d516b6..a724084950 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -306,6 +306,8 @@ impl TimeValLike for TimeSpec { }) } + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] fn num_seconds(&self) -> i64 { if self.tv_sec() < 0 && self.tv_nsec() > 0 { (self.tv_sec() + 1) as i64 @@ -322,6 +324,8 @@ impl TimeValLike for TimeSpec { self.num_nanoseconds() / 1_000 } + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] fn num_nanoseconds(&self) -> i64 { let secs = self.num_seconds() * 1_000_000_000; let nsec = self.nanos_mod_sec(); @@ -549,6 +553,8 @@ impl TimeValLike for TimeVal { }) } + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] fn num_seconds(&self) -> i64 { if self.tv_sec() < 0 && self.tv_usec() > 0 { (self.tv_sec() + 1) as i64 @@ -561,6 +567,8 @@ impl TimeValLike for TimeVal { self.num_microseconds() / 1_000 } + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] fn num_microseconds(&self) -> i64 { let secs = self.num_seconds() * 1_000_000; let usec = self.micros_mod_sec(); diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 1908973b49..7cddb37265 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -153,7 +153,7 @@ impl IoVec { unsafe { slice::from_raw_parts( self.0.iov_base as *const u8, - self.0.iov_len as usize) + self.0.iov_len) } } } diff --git a/test/sys/test_ioctl.rs b/test/sys/test_ioctl.rs index 7a603c5bba..40f60cfdbc 100644 --- a/test/sys/test_ioctl.rs +++ b/test/sys/test_ioctl.rs @@ -30,6 +30,8 @@ ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32); #[cfg(any(target_os = "linux", target_os = "android"))] mod linux { + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] #[test] fn test_op_none() { if cfg!(any( @@ -46,6 +48,8 @@ mod linux { } } + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] #[test] fn test_op_write() { if cfg!(any( @@ -78,6 +82,8 @@ mod linux { } } + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] #[test] fn test_op_read() { if cfg!(any( @@ -110,6 +116,8 @@ mod linux { } } + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] #[test] fn test_op_read_write() { assert_eq!(request_code_readwrite!(b'z', 10, 1) as u32, 0xC001_7A0A); diff --git a/test/sys/test_stat.rs b/test/sys/test_stat.rs index 2f26e789c7..426b4b6588 100644 --- a/test/sys/test_stat.rs +++ b/test/sys/test_stat.rs @@ -1,3 +1,5 @@ +// The conversion is not useless on all platforms. +#[allow(clippy::useless_conversion)] #[cfg(target_os = "freebsd")] #[test] fn test_chflags() { diff --git a/test/test_mount.rs b/test/test_mount.rs index febcadfbca..2fd612e358 100644 --- a/test/test_mount.rs +++ b/test/test_mount.rs @@ -108,7 +108,7 @@ exit 23"; // EROFS: Read-only file system assert_eq!( - EROFS as i32, + EROFS, File::create(tempdir.path().join("test")) .unwrap_err() .raw_os_error() @@ -156,7 +156,7 @@ exit 23"; // EACCES: Permission denied assert_eq!( - EACCES as i32, + EACCES, Command::new(&test_path) .status() .unwrap_err() From aa395cde3a7a72c02acb7f9034ba6a55bcb3bb9b Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Sat, 8 Oct 2022 21:13:40 -0500 Subject: [PATCH 181/358] Upgrade parking_lot dev-dependency to 0.12 We were previously stuck on 0.11 for MSRV reasons, but since bumping nix's MSRV to Rust 1.56 this is no longer the case. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 290ba8e330..855478e930 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,7 +80,7 @@ zerocopy = ["fs", "uio"] [dev-dependencies] assert-impl = "0.1" lazy_static = "1.4" -parking_lot = "0.11.2" +parking_lot = "0.12" rand = "0.8" tempfile = "3.3.0" semver = "1.0.7" From d19f1d3ce5797f5ea6dab8336034a3b3d080e4cf Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Mon, 10 Oct 2022 21:17:55 +0800 Subject: [PATCH 182/358] add faccessat on illumos --- CHANGELOG.md | 2 ++ Cargo.toml | 2 +- src/unistd.rs | 3 +-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8678e3ed86..6d45b963c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1831](https://github.com/nix-rust/nix/pull/1831)) - Added `syncfs(2)` on Linux ([#1833](https://github.com/nix-rust/nix/pull/1833)) +- Added `faccessat(2)` on illumos + ([#1841](https://github.com/nix-rust/nix/pull/1841)) ### Changed diff --git a/Cargo.toml b/Cargo.toml index 855478e930..2edb003b41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.134", features = [ "extra_traits" ] } +libc = { version = "0.2.135", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } diff --git a/src/unistd.rs b/src/unistd.rs index daa76b74d0..5be59b6c10 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2921,9 +2921,8 @@ pub fn access(path: &P, amode: AccessFlags) -> Result<()> { /// # References /// /// [faccessat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html) -// illumos: faccessat(2) appears to be supported, but the libc crate does not provide a binding. // redox: does not appear to support the *at family of syscalls. -#[cfg(not(any(target_os = "illumos", target_os = "redox")))] +#[cfg(not(target_os = "redox"))] pub fn faccessat(dirfd: Option, path: &P, mode: AccessFlags, flags: AtFlags) -> Result<()> { let res = path.with_nix_path(|cstr| { unsafe { From 353527e8dffdb791991aa8a6225daa095aba7698 Mon Sep 17 00:00:00 2001 From: Yusuke Tanaka Date: Tue, 11 Oct 2022 19:40:18 +0900 Subject: [PATCH 183/358] Remove unnecessary verb from doc comment of `dup` --- src/unistd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unistd.rs b/src/unistd.rs index 5be59b6c10..3b0df74fc9 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -417,7 +417,7 @@ feature! { /// Create a copy of the specified file descriptor (see /// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)). /// -/// The new file descriptor will be have a new index but refer to the same +/// The new file descriptor will have a new index but refer to the same /// resource as the old file descriptor and the old and new file descriptors may /// be used interchangeably. The new and old file descriptor share the same /// underlying resource, offset, and file status flags. The actual index used From 04e409b376615080e1d910e302b28b144dcbff71 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Thu, 13 Oct 2022 09:23:09 +0800 Subject: [PATCH 184/358] add eaccess on FreeBSD, DragonFly and Linux (musl and glibc) --- CHANGELOG.md | 2 ++ src/unistd.rs | 21 +++++++++++++++++++++ test/test_unistd.rs | 37 +++++++++++++++++++++++++++++++++---- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d45b963c0..b1f74a89f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1833](https://github.com/nix-rust/nix/pull/1833)) - Added `faccessat(2)` on illumos ([#1841](https://github.com/nix-rust/nix/pull/1841)) +- Added `eaccess()` on FreeBSD, DragonFly and Linux (glibc and musl). + ([#1842](https://github.com/nix-rust/nix/pull/1842)) ### Changed diff --git a/src/unistd.rs b/src/unistd.rs index 5be59b6c10..dc452d2d5e 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2931,6 +2931,27 @@ pub fn faccessat(dirfd: Option, path: &P, mode: Acce })?; Errno::result(res).map(drop) } + +/// Checks the file named by `path` for accessibility according to the flags given +/// by `mode` using effective UID, effective GID and supplementary group lists. +/// +/// # References +/// +/// * [FreeBSD man page](https://www.freebsd.org/cgi/man.cgi?query=eaccess&sektion=2&n=1) +/// * [Linux man page](https://man7.org/linux/man-pages/man3/euidaccess.3.html) +#[cfg(any( + all(target_os = "linux", not(target_env = "uclibc")), + target_os = "freebsd", + target_os = "dragonfly" +))] +pub fn eaccess(path: &P, mode: AccessFlags) -> Result<()> { + let res = path.with_nix_path(|cstr| { + unsafe { + libc::eaccess(cstr.as_ptr(), mode.bits) + } + })?; + Errno::result(res).map(drop) +} } feature! { diff --git a/test/test_unistd.rs b/test/test_unistd.rs index eee10103ad..8ad6340c15 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -1310,7 +1310,7 @@ fn test_getpeereid_invalid_fd() { } #[test] -#[cfg(not(any(target_os = "illumos", target_os = "redox")))] +#[cfg(not(target_os = "redox"))] fn test_faccessat_none_not_existing() { use nix::fcntl::AtFlags; let tempdir = tempfile::tempdir().unwrap(); @@ -1324,7 +1324,7 @@ fn test_faccessat_none_not_existing() { } #[test] -#[cfg(not(any(target_os = "illumos", target_os = "redox")))] +#[cfg(not(target_os = "redox"))] fn test_faccessat_not_existing() { use nix::fcntl::AtFlags; let tempdir = tempfile::tempdir().unwrap(); @@ -1344,7 +1344,7 @@ fn test_faccessat_not_existing() { } #[test] -#[cfg(not(any(target_os = "illumos", target_os = "redox")))] +#[cfg(not(target_os = "redox"))] fn test_faccessat_none_file_exists() { use nix::fcntl::AtFlags; let tempdir = tempfile::tempdir().unwrap(); @@ -1360,7 +1360,7 @@ fn test_faccessat_none_file_exists() { } #[test] -#[cfg(not(any(target_os = "illumos", target_os = "redox")))] +#[cfg(not(target_os = "redox"))] fn test_faccessat_file_exists() { use nix::fcntl::AtFlags; let tempdir = tempfile::tempdir().unwrap(); @@ -1376,3 +1376,32 @@ fn test_faccessat_file_exists() { ) .is_ok()); } + +#[test] +#[cfg(any( + all(target_os = "linux", not(target_env = "uclibc")), + target_os = "freebsd", + target_os = "dragonfly" +))] +fn test_eaccess_not_existing() { + let tempdir = tempdir().unwrap(); + let dir = tempdir.path().join("does_not_exist.txt"); + assert_eq!( + eaccess(&dir, AccessFlags::F_OK).err().unwrap(), + Errno::ENOENT + ); +} + +#[test] +#[cfg(any( + all(target_os = "linux", not(target_env = "uclibc")), + target_os = "freebsd", + target_os = "dragonfly" +))] +fn test_eaccess_file_exists() { + let tempdir = tempdir().unwrap(); + let path = tempdir.path().join("does_exist.txt"); + let _file = File::create(path.clone()).unwrap(); + eaccess(&path, AccessFlags::R_OK | AccessFlags::W_OK) + .expect("assertion failed"); +} From f28262564da77c0746d0e98312a1aa24979055fb Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Wed, 12 Oct 2022 20:36:15 -0500 Subject: [PATCH 185/358] fix '' being interpreted as html --- src/unistd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unistd.rs b/src/unistd.rs index 3b0df74fc9..2197d2bc86 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2207,7 +2207,7 @@ pub enum SysconfVar { /// Unless otherwise noted, the maximum length, in bytes, of a utility's /// input line (either standard input or another file), when the utility is /// described as processing text files. The length includes room for the - /// trailing . + /// trailing newline. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] LINE_MAX = libc::_SC_LINE_MAX, From e78473c32163abe5fb48ddcd858e5d0da20910fd Mon Sep 17 00:00:00 2001 From: MrCroxx Date: Thu, 13 Oct 2022 12:18:34 +0800 Subject: [PATCH 186/358] add XFS_SUPER_NUMBER to nix::sys::statfs --- src/sys/statfs.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index a1c1aaa931..83196dbadc 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -208,7 +208,9 @@ pub const XENFS_SUPER_MAGIC: FsType = FsType(libc::XENFS_SUPER_MAGIC as fs_type_ #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const NSFS_MAGIC: FsType = FsType(libc::NSFS_MAGIC as fs_type_t); - +#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "musl")))] +#[allow(missing_docs)] +pub const XFS_SUPER_MAGIC: FsType = FsType(libc::XFS_SUPER_MAGIC as fs_type_t); impl Statfs { /// Magic code defining system type From 482a6b10460aa8121c440b01a83511d29b132412 Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Mon, 13 Jun 2022 09:30:24 +0800 Subject: [PATCH 187/358] socket: stop setting vector length inside read_mhdr CMSG_FIRSTHDR/CMSG_NEXTHDR operate in terms of pointers contained inside msghdr structure, vector capacity doesn't matter for them. This would change external behavior of recvmsg/recvmmsg in a sense that buffer passed to store controll messages won't have it's length updated but intended way to receive control messages is with cmsgs iterator on `RecvMsg` which would still work. This change is required to allow using a single vector to store control messages from multiple packets --- src/sys/socket/mod.rs | 270 ++++++++++++++++++++---------------------- 1 file changed, 131 insertions(+), 139 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 461607d12f..ac616548fd 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1,21 +1,23 @@ //! Socket interface functions //! //! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html) -use cfg_if::cfg_if; -use crate::{Result, errno::Errno}; -use libc::{self, c_void, c_int, iovec, socklen_t, size_t, - CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN}; -use std::convert::TryInto; -use std::{mem, ptr, slice}; -use std::os::unix::io::RawFd; -#[cfg(feature = "net")] -use std::net; #[cfg(target_os = "linux")] #[cfg(feature = "uio")] use crate::sys::time::TimeSpec; #[cfg(feature = "uio")] use crate::sys::time::TimeVal; +use crate::{errno::Errno, Result}; +use cfg_if::cfg_if; +use libc::{ + self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR, + CMSG_LEN, CMSG_NXTHDR, +}; +use std::convert::TryInto; use std::io::{IoSlice, IoSliceMut}; +#[cfg(feature = "net")] +use std::net; +use std::os::unix::io::RawFd; +use std::{mem, ptr, slice}; #[deny(missing_docs)] mod addr; @@ -32,60 +34,44 @@ pub use self::addr::{SockaddrLike, SockaddrStorage}; #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] #[allow(deprecated)] -pub use self::addr::{ - AddressFamily, - SockAddr, - UnixAddr, -}; -#[allow(deprecated)] -#[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "haiku")))] -#[cfg(feature = "net")] -pub use self::addr::{ - InetAddr, - IpAddr, - Ipv4Addr, - Ipv6Addr, - LinkAddr, - SockaddrIn, - SockaddrIn6 -}; +pub use self::addr::{AddressFamily, SockAddr, UnixAddr}; #[cfg(any(target_os = "illumos", target_os = "solaris"))] #[allow(deprecated)] +pub use self::addr::{AddressFamily, SockAddr, UnixAddr}; +#[allow(deprecated)] +#[cfg(not(any( + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" +)))] +#[cfg(feature = "net")] pub use self::addr::{ - AddressFamily, - SockAddr, - UnixAddr, + InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, LinkAddr, SockaddrIn, SockaddrIn6, }; #[allow(deprecated)] -#[cfg(any(target_os = "illumos", target_os = "solaris", target_os = "haiku"))] +#[cfg(any( + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" +))] #[cfg(feature = "net")] pub use self::addr::{ - InetAddr, - IpAddr, - Ipv4Addr, - Ipv6Addr, - SockaddrIn, - SockaddrIn6 + InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, SockaddrIn, SockaddrIn6, }; +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use crate::sys::socket::addr::alg::AlgAddr; +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use crate::sys::socket::addr::netlink::NetlinkAddr; #[cfg(any(target_os = "ios", target_os = "macos"))] #[cfg(feature = "ioctl")] pub use crate::sys::socket::addr::sys_control::SysControlAddr; #[cfg(any(target_os = "android", target_os = "linux"))] -pub use crate::sys::socket::addr::netlink::NetlinkAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use crate::sys::socket::addr::alg::AlgAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] pub use crate::sys::socket::addr::vsock::VsockAddr; #[cfg(feature = "uio")] pub use libc::{cmsghdr, msghdr}; -pub use libc::{ - sa_family_t, - sockaddr, - sockaddr_storage, - sockaddr_un, -}; +pub use libc::{sa_family_t, sockaddr, sockaddr_storage, sockaddr_un}; #[cfg(feature = "net")] pub use libc::{sockaddr_in, sockaddr_in6}; @@ -245,7 +231,7 @@ libc_bitflags! { } } -libc_bitflags!{ +libc_bitflags! { /// Additional socket options pub struct SockFlag: c_int { /// Set non-blocking mode on the new socket @@ -280,7 +266,7 @@ libc_bitflags!{ } } -libc_bitflags!{ +libc_bitflags! { /// Flags for send/recv and their relatives pub struct MsgFlags: c_int { /// Sends or requests out-of-band data on sockets that support this notion @@ -462,7 +448,7 @@ cfg_if! { } } -cfg_if!{ +cfg_if! { if #[cfg(any( target_os = "dragonfly", target_os = "freebsd", @@ -1645,7 +1631,7 @@ pub fn recvmmsg<'a, I, S>( } ); - (msg_controllen, &mut d.cmsg_buffer) + msg_controllen as usize }).collect(); let timeout = if let Some(mut t) = timeout { @@ -1663,40 +1649,31 @@ pub fn recvmmsg<'a, I, S>( .take(ret as usize) .zip(addresses.iter().map(|addr| unsafe{addr.assume_init()})) .zip(results.into_iter()) - .map(|((mmsghdr, address), (msg_controllen, cmsg_buffer))| { - // The cast is not unnecessary on all platforms. - #[allow(clippy::unnecessary_cast)] + .map(|((mmsghdr, address), msg_controllen)| { unsafe { read_mhdr( mmsghdr.msg_hdr, mmsghdr.msg_len as isize, msg_controllen, address, - cmsg_buffer ) } }) .collect()) } -unsafe fn read_mhdr<'a, 'b, S>( +unsafe fn read_mhdr<'a, S>( mhdr: msghdr, r: isize, msg_controllen: usize, address: S, - cmsg_buffer: &'a mut Option<&'b mut Vec> -) -> RecvMsg<'b, S> +) -> RecvMsg<'a, S> where S: SockaddrLike { // The cast is not unnecessary on all platforms. #[allow(clippy::unnecessary_cast)] let cmsghdr = { if mhdr.msg_controllen > 0 { - // got control message(s) - cmsg_buffer - .as_mut() - .unwrap() - .set_len(mhdr.msg_controllen as usize); debug_assert!(!mhdr.msg_control.is_null()); debug_assert!(msg_controllen >= mhdr.msg_controllen as usize); CMSG_FIRSTHDR(&mhdr as *const msghdr) @@ -1827,11 +1804,10 @@ pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'i let r = Errno::result(ret)?; - Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init(), &mut cmsg_buffer) }) + Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init()) }) } } - /// Create an endpoint for communication /// /// The `protocol` specifies a particular protocol to be used with the @@ -1842,7 +1818,12 @@ pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'i /// specified in this manner. /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html) -pub fn socket>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result { +pub fn socket>>( + domain: AddressFamily, + ty: SockType, + flags: SockFlag, + protocol: T, +) -> Result { let protocol = match protocol.into() { None => 0, Some(p) => p as c_int, @@ -1862,8 +1843,12 @@ pub fn socket>>(domain: AddressFamily, ty: SockType /// Create a pair of connected sockets /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html) -pub fn socketpair>>(domain: AddressFamily, ty: SockType, protocol: T, - flags: SockFlag) -> Result<(RawFd, RawFd)> { +pub fn socketpair>>( + domain: AddressFamily, + ty: SockType, + protocol: T, + flags: SockFlag, +) -> Result<(RawFd, RawFd)> { let protocol = match protocol.into() { None => 0, Some(p) => p as c_int, @@ -1877,7 +1862,9 @@ pub fn socketpair>>(domain: AddressFamily, ty: Sock let mut fds = [-1, -1]; - let res = unsafe { libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) }; + let res = unsafe { + libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) + }; Errno::result(res)?; Ok((fds[0], fds[1])) @@ -1896,9 +1883,7 @@ pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> { /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html) pub fn bind(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { - let res = unsafe { - libc::bind(fd, addr.as_ptr(), addr.len()) - }; + let res = unsafe { libc::bind(fd, addr.as_ptr(), addr.len()) }; Errno::result(res).map(drop) } @@ -1915,24 +1900,28 @@ pub fn accept(sockfd: RawFd) -> Result { /// Accept a connection on a socket /// /// [Further reading](https://man7.org/linux/man-pages/man2/accept.2.html) -#[cfg(any(all( - target_os = "android", - any( - target_arch = "aarch64", - target_arch = "x86", - target_arch = "x86_64" - ) - ), - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd"))] +#[cfg(any( + all( + target_os = "android", + any( + target_arch = "aarch64", + target_arch = "x86", + target_arch = "x86_64" + ) + ), + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd" +))] pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result { - let res = unsafe { libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) }; + let res = unsafe { + libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) + }; Errno::result(res) } @@ -1941,9 +1930,7 @@ pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result { /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html) pub fn connect(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { - let res = unsafe { - libc::connect(fd, addr.as_ptr(), addr.len()) - }; + let res = unsafe { libc::connect(fd, addr.as_ptr(), addr.len()) }; Errno::result(res).map(drop) } @@ -1958,7 +1945,8 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result { sockfd, buf.as_ptr() as *mut c_void, buf.len() as size_t, - flags.bits()); + flags.bits(), + ); Errno::result(ret).map(|r| r as usize) } @@ -1969,9 +1957,10 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result { /// address of the sender. /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html) -pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) - -> Result<(usize, Option)> -{ +pub fn recvfrom( + sockfd: RawFd, + buf: &mut [u8], +) -> Result<(usize, Option)> { unsafe { let mut addr = mem::MaybeUninit::::uninit(); let mut len = mem::size_of_val(&addr) as socklen_t; @@ -1982,11 +1971,15 @@ pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) buf.len() as size_t, 0, addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len as *mut socklen_t))? as usize; - - Ok((ret, T::from_raw( - addr.assume_init().as_ptr() as *const libc::sockaddr, - Some(len)) + &mut len as *mut socklen_t, + ))? as usize; + + Ok(( + ret, + T::from_raw( + addr.assume_init().as_ptr() as *const libc::sockaddr, + Some(len), + ), )) } } @@ -1994,7 +1987,12 @@ pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) /// Send a message to a socket /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html) -pub fn sendto(fd: RawFd, buf: &[u8], addr: &dyn SockaddrLike, flags: MsgFlags) -> Result { +pub fn sendto( + fd: RawFd, + buf: &[u8], + addr: &dyn SockaddrLike, + flags: MsgFlags, +) -> Result { let ret = unsafe { libc::sendto( fd, @@ -2002,7 +2000,7 @@ pub fn sendto(fd: RawFd, buf: &[u8], addr: &dyn SockaddrLike, flags: MsgFlags) - buf.len() as size_t, flags.bits(), addr.as_ptr(), - addr.len() + addr.len(), ) }; @@ -2014,7 +2012,12 @@ pub fn sendto(fd: RawFd, buf: &[u8], addr: &dyn SockaddrLike, flags: MsgFlags) - /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html) pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result { let ret = unsafe { - libc::send(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits()) + libc::send( + fd, + buf.as_ptr() as *const c_void, + buf.len() as size_t, + flags.bits(), + ) }; Errno::result(ret).map(|r| r as usize) @@ -2027,7 +2030,7 @@ pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result { */ /// Represents a socket option that can be retrieved. -pub trait GetSockOpt : Copy { +pub trait GetSockOpt: Copy { type Val; /// Look up the value of this socket option on the given socket. @@ -2035,7 +2038,7 @@ pub trait GetSockOpt : Copy { } /// Represents a socket option that can be set. -pub trait SetSockOpt : Clone { +pub trait SetSockOpt: Clone { type Val; /// Set the value of this socket option on the given socket. @@ -2066,7 +2069,11 @@ pub fn getsockopt(fd: RawFd, opt: O) -> Result { /// let res = setsockopt(fd, KeepAlive, &true); /// assert!(res.is_ok()); /// ``` -pub fn setsockopt(fd: RawFd, opt: O, val: &O::Val) -> Result<()> { +pub fn setsockopt( + fd: RawFd, + opt: O, + val: &O::Val, +) -> Result<()> { opt.set(fd, val) } @@ -2081,13 +2088,12 @@ pub fn getpeername(fd: RawFd) -> Result { let ret = libc::getpeername( fd, addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len + &mut len, ); Errno::result(ret)?; - T::from_raw(addr.assume_init().as_ptr(), Some(len)) - .ok_or(Errno::EINVAL) + T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL) } } @@ -2102,13 +2108,12 @@ pub fn getsockname(fd: RawFd) -> Result { let ret = libc::getsockname( fd, addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len + &mut len, ); Errno::result(ret)?; - T::from_raw(addr.assume_init().as_ptr(), Some(len)) - .ok_or(Errno::EINVAL) + T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL) } } @@ -2127,8 +2132,8 @@ pub fn getsockname(fd: RawFd) -> Result { #[allow(deprecated)] pub fn sockaddr_storage_to_addr( addr: &sockaddr_storage, - len: usize) -> Result { - + len: usize, +) -> Result { assert!(len <= mem::size_of::()); if len < mem::size_of_val(&addr.ss_family) { return Err(Errno::ENOTCONN); @@ -2146,18 +2151,14 @@ pub fn sockaddr_storage_to_addr( #[cfg(feature = "net")] libc::AF_INET6 => { assert!(len >= mem::size_of::()); - let sin6 = unsafe { - *(addr as *const _ as *const sockaddr_in6) - }; + let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) }; Ok(SockAddr::Inet(InetAddr::V6(sin6))) } - libc::AF_UNIX => { - unsafe { - let sun = *(addr as *const _ as *const sockaddr_un); - let sun_len = len.try_into().unwrap(); - Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len))) - } - } + libc::AF_UNIX => unsafe { + let sun = *(addr as *const _ as *const sockaddr_un); + let sun_len = len.try_into().unwrap(); + Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len))) + }, #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg(feature = "net")] libc::AF_PACKET => { @@ -2166,40 +2167,31 @@ pub fn sockaddr_storage_to_addr( // Apparently the Linux kernel can return smaller sizes when // the value in the last element of sockaddr_ll (`sll_addr`) is // smaller than the declared size of that field - let sll = unsafe { - *(addr as *const _ as *const sockaddr_ll) - }; + let sll = unsafe { *(addr as *const _ as *const sockaddr_ll) }; Ok(SockAddr::Link(LinkAddr(sll))) } #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_NETLINK => { use libc::sockaddr_nl; - let snl = unsafe { - *(addr as *const _ as *const sockaddr_nl) - }; + let snl = unsafe { *(addr as *const _ as *const sockaddr_nl) }; Ok(SockAddr::Netlink(NetlinkAddr(snl))) } #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_ALG => { use libc::sockaddr_alg; - let salg = unsafe { - *(addr as *const _ as *const sockaddr_alg) - }; + let salg = unsafe { *(addr as *const _ as *const sockaddr_alg) }; Ok(SockAddr::Alg(AlgAddr(salg))) } #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_VSOCK => { use libc::sockaddr_vm; - let svm = unsafe { - *(addr as *const _ as *const sockaddr_vm) - }; + let svm = unsafe { *(addr as *const _ as *const sockaddr_vm) }; Ok(SockAddr::Vsock(VsockAddr(svm))) } af => panic!("unexpected address family {}", af), } } - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum Shutdown { /// Further receptions will be disallowed. @@ -2218,9 +2210,9 @@ pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> { use libc::shutdown; let how = match how { - Shutdown::Read => libc::SHUT_RD, + Shutdown::Read => libc::SHUT_RD, Shutdown::Write => libc::SHUT_WR, - Shutdown::Both => libc::SHUT_RDWR, + Shutdown::Both => libc::SHUT_RDWR, }; Errno::result(shutdown(df, how)).map(drop) From dd1d4fd5eb8d1aca10c9f101d1570da1860725d4 Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Mon, 13 Jun 2022 09:56:21 +0800 Subject: [PATCH 188/358] pack_mhdr_to_receive: pass pointer and capacity directly This is already an unsafe function, dealing with pointers directly does not make it much more unsafe but simplifies lifetimes later on and similar to a previous commit allows to alocate a single buffer to store all the control messages --- src/sys/socket/mod.rs | 54 +++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index ac616548fd..72e1556211 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1616,10 +1616,14 @@ pub fn recvmmsg<'a, I, S>( .into_boxed_slice(); let results: Vec<_> = iter.enumerate().map(|(i, d)| { - let (msg_controllen, mhdr) = unsafe { - pack_mhdr_to_receive( + let (msg_control, msg_controllen) = d.cmsg_buffer.as_mut() + .map(|v| (v.as_mut_ptr(), v.capacity())) + .unwrap_or((ptr::null_mut(), 0)); + let mhdr = unsafe { + pack_mhdr_to_receive( d.iov.as_ref(), - &mut d.cmsg_buffer, + msg_control, + msg_controllen, addresses[i].as_mut_ptr(), ) }; @@ -1693,33 +1697,26 @@ unsafe fn read_mhdr<'a, S>( unsafe fn pack_mhdr_to_receive<'outer, 'inner, I, S>( iov: I, - cmsg_buffer: &mut Option<&mut Vec>, + cmsg_buffer: *const u8, + cmsg_capacity: usize, address: *mut S, -) -> (usize, msghdr) +) -> msghdr where I: AsRef<[IoSliceMut<'inner>]> + 'outer, S: SockaddrLike + 'outer { - let (msg_control, msg_controllen) = cmsg_buffer.as_mut() - .map(|v| (v.as_mut_ptr(), v.capacity())) - .unwrap_or((ptr::null_mut(), 0)); - - let mhdr = { - // Musl's msghdr has private fields, so this is the only way to - // initialize it. - let mut mhdr = mem::MaybeUninit::::zeroed(); - let p = mhdr.as_mut_ptr(); - (*p).msg_name = (*address).as_mut_ptr() as *mut c_void; - (*p).msg_namelen = S::size(); - (*p).msg_iov = iov.as_ref().as_ptr() as *mut iovec; - (*p).msg_iovlen = iov.as_ref().len() as _; - (*p).msg_control = msg_control as *mut c_void; - (*p).msg_controllen = msg_controllen as _; - (*p).msg_flags = 0; - mhdr.assume_init() - }; - - (msg_controllen, mhdr) + // Musl's msghdr has private fields, so this is the only way to + // initialize it. + let mut mhdr = mem::MaybeUninit::::zeroed(); + let p = mhdr.as_mut_ptr(); + (*p).msg_name = (*address).as_mut_ptr() as *mut c_void; + (*p).msg_namelen = S::size(); + (*p).msg_iov = iov.as_ref().as_ptr() as *mut iovec; + (*p).msg_iovlen = iov.as_ref().len() as _; + (*p).msg_control = cmsg_buffer as *mut c_void; + (*p).msg_controllen = cmsg_capacity as _; + (*p).msg_flags = 0; + mhdr.assume_init() } fn pack_mhdr_to_send<'a, I, C, S>( @@ -1796,8 +1793,11 @@ pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'i { let mut address = mem::MaybeUninit::uninit(); - let (msg_controllen, mut mhdr) = unsafe { - pack_mhdr_to_receive::<_, S>(iov, &mut cmsg_buffer, address.as_mut_ptr()) + let (msg_control, msg_controllen) = cmsg_buffer.as_mut() + .map(|v| (v.as_mut_ptr(), v.capacity())) + .unwrap_or((ptr::null_mut(), 0)); + let mut mhdr = unsafe { + pack_mhdr_to_receive::<_, S>(iov, msg_control, msg_controllen, address.as_mut_ptr()) }; let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; From d600ddd86014bb91a6dba13a41d4ecde92049906 Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Mon, 13 Jun 2022 11:41:18 +0800 Subject: [PATCH 189/358] pack_mhdr_to_receive: pass iovec ptr and capacity separately We'll be using that to reinitialize buffers later --- src/sys/socket/mod.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 72e1556211..cabc2301f1 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1621,7 +1621,8 @@ pub fn recvmmsg<'a, I, S>( .unwrap_or((ptr::null_mut(), 0)); let mhdr = unsafe { pack_mhdr_to_receive( - d.iov.as_ref(), + d.iov.as_ref().as_ptr(), + d.iov.as_ref().len(), msg_control, msg_controllen, addresses[i].as_mut_ptr(), @@ -1695,15 +1696,15 @@ unsafe fn read_mhdr<'a, S>( } } -unsafe fn pack_mhdr_to_receive<'outer, 'inner, I, S>( - iov: I, +unsafe fn pack_mhdr_to_receive( + iov_buffer: *const IoSliceMut, + iov_buffer_len: usize, cmsg_buffer: *const u8, cmsg_capacity: usize, address: *mut S, ) -> msghdr where - I: AsRef<[IoSliceMut<'inner>]> + 'outer, - S: SockaddrLike + 'outer + S: SockaddrLike { // Musl's msghdr has private fields, so this is the only way to // initialize it. @@ -1711,8 +1712,8 @@ unsafe fn pack_mhdr_to_receive<'outer, 'inner, I, S>( let p = mhdr.as_mut_ptr(); (*p).msg_name = (*address).as_mut_ptr() as *mut c_void; (*p).msg_namelen = S::size(); - (*p).msg_iov = iov.as_ref().as_ptr() as *mut iovec; - (*p).msg_iovlen = iov.as_ref().len() as _; + (*p).msg_iov = iov_buffer as *mut iovec; + (*p).msg_iovlen = iov_buffer_len as _; (*p).msg_control = cmsg_buffer as *mut c_void; (*p).msg_controllen = cmsg_capacity as _; (*p).msg_flags = 0; @@ -1797,7 +1798,7 @@ pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'i .map(|v| (v.as_mut_ptr(), v.capacity())) .unwrap_or((ptr::null_mut(), 0)); let mut mhdr = unsafe { - pack_mhdr_to_receive::<_, S>(iov, msg_control, msg_controllen, address.as_mut_ptr()) + pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr()) }; let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; From 7f0fdf237c7d05523944c14c79fecbae45723598 Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Mon, 13 Jun 2022 10:38:39 +0800 Subject: [PATCH 190/358] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1f74a89f4..de01c2f7f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -85,6 +85,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Changed +- Reimplemented sendmmsg/recvmmsg to avoid allocations and with better API + (#[1744](https://github.com/nix-rust/nix/pull/1744)) + - Rewrote the aio module. The new module: * Does more type checking at compile time rather than runtime. * Gives the caller control over whether and when to `Box` an aio operation. From 19c83afbbfa8dd509e803ef972be0c52f32acb87 Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Mon, 13 Jun 2022 11:48:24 +0800 Subject: [PATCH 191/358] reimplement recvmsg/sendmmsg New implementation performs no allocations after all the necessary structures are created, removes potentially unsound code that was used by the old version (see below) and adds a bit more documentation about bugs in how timeout is actually handled ``` let timeout = if let Some(mut t) = timeout { t.as_mut() as *mut libc::timespec } else { ptr::null_mut() }; ``` --- src/sys/socket/mod.rs | 509 ++++++++++++++++++++++++++++------------ test/sys/test_socket.rs | 108 ++++----- 2 files changed, 420 insertions(+), 197 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index cabc2301f1..aec09dc8b1 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -567,15 +567,20 @@ macro_rules! cmsg_space { } #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct RecvMsg<'a, S> { +/// Contains outcome of sending or receiving a message +/// +/// Use [`cmsgs`][RecvMsg::cmsgs] to access all the control messages present, and +/// [`iovs`][RecvMsg::iovs`] to access underlying io slices. +pub struct RecvMsg<'a, 's, S> { pub bytes: usize, cmsghdr: Option<&'a cmsghdr>, pub address: Option, pub flags: MsgFlags, + iobufs: std::marker::PhantomData<& 's()>, mhdr: msghdr, } -impl<'a, S> RecvMsg<'a, S> { +impl<'a, S> RecvMsg<'a, '_, S> { /// Iterate over the valid control messages pointed to by this /// msghdr. pub fn cmsgs(&self) -> CmsgIterator { @@ -1454,24 +1459,6 @@ pub fn sendmsg(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage], Errno::result(ret).map(|r| r as usize) } -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "netbsd", -))] -#[derive(Debug)] -pub struct SendMmsgData<'a, I, C, S> - where - I: AsRef<[IoSlice<'a>]>, - C: AsRef<[ControlMessage<'a>]>, - S: SockaddrLike + 'a -{ - pub iov: I, - pub cmsgs: C, - pub addr: Option, - pub _lt: std::marker::PhantomData<&'a I>, -} /// An extension of `sendmsg` that allows the caller to transmit multiple /// messages on a socket using a single system call. This has performance @@ -1496,51 +1483,66 @@ pub struct SendMmsgData<'a, I, C, S> target_os = "freebsd", target_os = "netbsd", ))] -pub fn sendmmsg<'a, I, C, S>( +pub fn sendmmsg<'a, XS, AS, C, I, S>( fd: RawFd, - data: impl std::iter::IntoIterator>, + data: &'a mut MultiHeaders, + slices: XS, + // one address per group of slices + addrs: AS, + // shared across all the messages + cmsgs: C, flags: MsgFlags -) -> Result> +) -> crate::Result> where + XS: IntoIterator, + AS: AsRef<[Option]>, I: AsRef<[IoSlice<'a>]> + 'a, C: AsRef<[ControlMessage<'a>]> + 'a, S: SockaddrLike + 'a { - let iter = data.into_iter(); - let size_hint = iter.size_hint(); - let reserve_items = size_hint.1.unwrap_or(size_hint.0); + let mut count = 0; - let mut output = Vec::::with_capacity(reserve_items); - let mut cmsgs_buffers = Vec::>::with_capacity(reserve_items); + for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() { + let mut p = &mut mmsghdr.msg_hdr; + p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; + p.msg_iovlen = slice.as_ref().len() as _; - for d in iter { - let capacity: usize = d.cmsgs.as_ref().iter().map(|c| c.space()).sum(); - let mut cmsgs_buffer = vec![0u8; capacity]; + p.msg_namelen = addr.as_ref().map_or(0, S::len); + p.msg_name = addr.as_ref().map_or(ptr::null(), S::as_ptr) as _; - output.push(libc::mmsghdr { - msg_hdr: pack_mhdr_to_send( - &mut cmsgs_buffer, - &d.iov, - &d.cmsgs, - d.addr.as_ref() - ), - msg_len: 0, - }); - cmsgs_buffers.push(cmsgs_buffer); - }; + // Encode each cmsg. This must happen after initializing the header because + // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. + // CMSG_FIRSTHDR is always safe + let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(p) }; + for cmsg in cmsgs.as_ref() { + assert_ne!(pmhdr, ptr::null_mut()); + // Safe because we know that pmhdr is valid, and we initialized it with + // sufficient space + unsafe { cmsg.encode_into(pmhdr) }; + // Safe because mhdr is valid + pmhdr = unsafe { CMSG_NXTHDR(p, pmhdr) }; + } - let ret = unsafe { libc::sendmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _) }; + count = i+1; + } - let sent_messages = Errno::result(ret)? as usize; - let mut sent_bytes = Vec::with_capacity(sent_messages); + let sent = Errno::result(unsafe { + libc::sendmmsg( + fd, + data.items.as_mut_ptr(), + count as _, + flags.bits() as _ + ) + })? as usize; - for item in &output { - sent_bytes.push(item.msg_len as usize); - } + Ok(MultiResults { + rmm: data, + current_index: 0, + received: sent + }) - Ok(sent_bytes) } @@ -1551,128 +1553,334 @@ pub fn sendmmsg<'a, I, C, S>( target_os = "netbsd", ))] #[derive(Debug)] -pub struct RecvMmsgData<'a, I> +/// Preallocated structures needed for [`recvmmsg`] and [`sendmmsg`] functions +pub struct MultiHeaders { + // preallocated boxed slice of mmsghdr + items: Box<[libc::mmsghdr]>, + addresses: Box<[mem::MaybeUninit]>, + // while we are not using it directly - this is used to store control messages + // and we retain pointers to them inside items array + #[allow(dead_code)] + cmsg_buffers: Option>, + msg_controllen: usize, +} + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", +))] +impl MultiHeaders { + /// Preallocate structure used by [`recvmmsg`] and [`sendmmsg`] takes number of headers to preallocate + /// + /// `cmsg_buffer` should be created with [`cmsg_space!`] if needed + pub fn preallocate(num_slices: usize, cmsg_buffer: Option>) -> Self where - I: AsRef<[IoSliceMut<'a>]> + 'a, -{ - pub iov: I, - pub cmsg_buffer: Option<&'a mut Vec>, + S: Copy + SockaddrLike, + { + // we will be storing pointers to addresses inside mhdr - convert it into boxed + // slice so it can'be changed later by pushing anything into self.addresses + let mut addresses = vec![std::mem::MaybeUninit::uninit(); num_slices].into_boxed_slice(); + + let msg_controllen = cmsg_buffer.as_ref().map_or(0, |v| v.capacity()); + + // we'll need a cmsg_buffer for each slice, we preallocate a vector and split + // it into "slices" parts + let cmsg_buffers = + cmsg_buffer.map(|v| vec![0u8; v.capacity() * num_slices].into_boxed_slice()); + + let items = addresses + .iter_mut() + .enumerate() + .map(|(ix, address)| { + let (ptr, cap) = match &cmsg_buffers { + Some(v) => ((&v[ix * msg_controllen] as *const u8), msg_controllen), + None => (std::ptr::null(), 0), + }; + let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.as_mut_ptr()) }; + libc::mmsghdr { + msg_hdr, + msg_len: 0, + } + }) + .collect::>(); + + Self { + items: items.into_boxed_slice(), + addresses, + cmsg_buffers, + msg_controllen, + } + } } -/// An extension of `recvmsg` that allows the caller to receive multiple -/// messages from a socket using a single system call. This has -/// performance benefits for some applications. -/// -/// `iov` and `cmsg_buffer` should be constructed similarly to `recvmsg` -/// -/// Multiple allocations are performed +/// An extension of recvmsg that allows the caller to receive multiple messages from a socket using a single system call. /// -/// # Arguments -/// -/// * `fd`: Socket file descriptor -/// * `data`: Struct that implements `IntoIterator` with `RecvMmsgData` items -/// * `flags`: Optional flags passed directly to the operating system. +/// This has performance benefits for some applications. /// -/// # RecvMmsgData +/// This method performs no allocations. /// -/// * `iov`: Scatter-gather list of buffers to receive the message -/// * `cmsg_buffer`: Space to receive ancillary data. Should be created by -/// [`cmsg_space!`](../../macro.cmsg_space.html) +/// Returns an iterator producing [`RecvMsg`], one per received messages. Each `RecvMsg` can produce +/// iterators over [`IoSlice`] with [`iovs`][RecvMsg::iovs`] and +/// `ControlMessageOwned` with [`cmsgs`][RecvMsg::cmsgs]. /// -/// # Returns -/// A `Vec` with multiple `RecvMsg`, one per received message +/// # Bugs (in underlying implementation, at least in Linux) +/// The timeout argument does not work as intended. The timeout is checked only after the receipt +/// of each datagram, so that if up to `vlen`-1 datagrams are received before the timeout expires, +/// but then no further datagrams are received, the call will block forever. /// -/// # References -/// - [`recvmsg`](fn.recvmsg.html) -/// - [`RecvMsg`](struct.RecvMsg.html) +/// If an error occurs after at least one message has been received, the call succeeds, and returns +/// the number of messages received. The error code is expected to be returned on a subsequent +/// call to recvmmsg(). In the current implementation, however, the error code can be +/// overwritten in the meantime by an unrelated network event on a socket, for example an +/// incoming ICMP packet. #[cfg(any( target_os = "linux", target_os = "android", target_os = "freebsd", target_os = "netbsd", ))] -#[allow(clippy::needless_collect)] // Complicated false positive -pub fn recvmmsg<'a, I, S>( +pub fn recvmmsg<'a, XS, S, I>( fd: RawFd, - data: impl std::iter::IntoIterator, - IntoIter=impl ExactSizeIterator + Iterator>>, + data: &'a mut MultiHeaders, + slices: XS, flags: MsgFlags, - timeout: Option -) -> Result>> - where - I: AsRef<[IoSliceMut<'a>]> + 'a, - S: Copy + SockaddrLike + 'a + mut timeout: Option, +) -> crate::Result> +where + XS: IntoIterator, + I: AsRef<[IoSliceMut<'a>]> + 'a, { - let iter = data.into_iter(); - - let num_messages = iter.len(); - - let mut output: Vec = Vec::with_capacity(num_messages); - - // Addresses should be pre-allocated. pack_mhdr_to_receive will store them - // as raw pointers, so we may not move them. Turn the vec into a boxed - // slice so we won't inadvertently reallocate the vec. - let mut addresses = vec![mem::MaybeUninit::uninit(); num_messages] - .into_boxed_slice(); - - let results: Vec<_> = iter.enumerate().map(|(i, d)| { - let (msg_control, msg_controllen) = d.cmsg_buffer.as_mut() - .map(|v| (v.as_mut_ptr(), v.capacity())) - .unwrap_or((ptr::null_mut(), 0)); - let mhdr = unsafe { - pack_mhdr_to_receive( - d.iov.as_ref().as_ptr(), - d.iov.as_ref().len(), - msg_control, - msg_controllen, - addresses[i].as_mut_ptr(), + let mut count = 0; + for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() { + let mut p = &mut mmsghdr.msg_hdr; + p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; + p.msg_iovlen = slice.as_ref().len() as _; + count = i + 1; + } + + let timeout_ptr = timeout + .as_mut() + .map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec); + + let received = Errno::result(unsafe { + libc::recvmmsg( + fd, + data.items.as_mut_ptr(), + count as _, + flags.bits() as _, + timeout_ptr, + ) + })? as usize; + + Ok(MultiResults { + rmm: data, + current_index: 0, + received, + }) +} + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", +))] +#[derive(Debug)] +/// Iterator over results of [`recvmmsg`]/[`sendmmsg`] +/// +/// +pub struct MultiResults<'a, S> { + // preallocated structures + rmm: &'a MultiHeaders, + current_index: usize, + received: usize, +} + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", +))] +impl<'a, S> Iterator for MultiResults<'a, S> +where + S: Copy + SockaddrLike, +{ + type Item = RecvMsg<'a, 'a, S>; + + fn next(&mut self) -> Option { + if self.current_index >= self.received { + return None; + } + let mmsghdr = self.rmm.items[self.current_index]; + + // as long as we are not reading past the index writen by recvmmsg - address + // will be initialized + let address = unsafe { self.rmm.addresses[self.current_index].assume_init() }; + + self.current_index += 1; + Some(unsafe { + read_mhdr( + mmsghdr.msg_hdr, + mmsghdr.msg_len as isize, + self.rmm.msg_controllen, + address, ) + }) + } +} + +impl<'a, S> RecvMsg<'_, 'a, S> { + /// Iterate over the filled io slices pointed by this msghdr + pub fn iovs(&self) -> IoSliceIterator<'a> { + IoSliceIterator { + index: 0, + remaining: self.bytes, + slices: unsafe { + // safe for as long as mgdr is properly initialized and references are valid. + // for multi messages API we initialize it with an empty + // slice and replace with a concrete buffer + // for single message API we hold a lifetime reference to ioslices + std::slice::from_raw_parts(self.mhdr.msg_iov as *const _, self.mhdr.msg_iovlen as _) + }, + } + } +} + +#[derive(Debug)] +pub struct IoSliceIterator<'a> { + index: usize, + remaining: usize, + slices: &'a [IoSlice<'a>], +} + +impl<'a> Iterator for IoSliceIterator<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option { + if self.index >= self.slices.len() { + return None; + } + let slice = &self.slices[self.index][..self.remaining.min(self.slices[self.index].len())]; + self.remaining -= slice.len(); + self.index += 1; + if slice.is_empty() { + return None; + } + + Some(slice) + } +} + +// test contains both recvmmsg and timestaping which is linux only +// there are existing tests for recvmmsg only in tests/ +#[cfg(target_os = "linux")] +#[cfg(test)] +mod test { + use crate::sys::socket::{AddressFamily, ControlMessageOwned}; + use crate::*; + use std::str::FromStr; + + #[cfg_attr(qemu, ignore)] + #[test] + fn test_recvmm2() -> crate::Result<()> { + use crate::sys::socket::{ + sendmsg, setsockopt, socket, sockopt::Timestamping, MsgFlags, SockFlag, SockType, + SockaddrIn, TimestampingFlag, }; + use std::io::{IoSlice, IoSliceMut}; - output.push( - libc::mmsghdr { - msg_hdr: mhdr, - msg_len: 0, - } - ); + let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); - msg_controllen as usize - }).collect(); + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + )?; - let timeout = if let Some(mut t) = timeout { - t.as_mut() as *mut libc::timespec - } else { - ptr::null_mut() - }; + let rsock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::SOCK_NONBLOCK, + None, + )?; + + crate::sys::socket::bind(rsock, &sock_addr)?; + + setsockopt(rsock, Timestamping, &TimestampingFlag::all())?; + + let sbuf = (0..400).map(|i| i as u8).collect::>(); + + let mut recv_buf = vec![0; 1024]; - let ret = unsafe { libc::recvmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _, timeout) }; - - let _ = Errno::result(ret)?; - - Ok(output - .into_iter() - .take(ret as usize) - .zip(addresses.iter().map(|addr| unsafe{addr.assume_init()})) - .zip(results.into_iter()) - .map(|((mmsghdr, address), msg_controllen)| { - unsafe { - read_mhdr( - mmsghdr.msg_hdr, - mmsghdr.msg_len as isize, - msg_controllen, - address, - ) + let mut recv_iovs = Vec::new(); + let mut pkt_iovs = Vec::new(); + + for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() { + pkt_iovs.push(IoSliceMut::new(chunk)); + if ix % 2 == 1 { + recv_iovs.push(pkt_iovs); + pkt_iovs = Vec::new(); + } + } + drop(pkt_iovs); + + let flags = MsgFlags::empty(); + let iov1 = [IoSlice::new(&sbuf)]; + + let cmsg = cmsg_space!(crate::sys::socket::Timestamps); + sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); + + let mut data = super::MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg)); + + let t = sys::time::TimeSpec::from_duration(std::time::Duration::from_secs(10)); + + let recv = super::recvmmsg(rsock, &mut data, recv_iovs.iter(), flags, Some(t))?; + + for rmsg in recv { + #[cfg(not(qemu))] + let mut saw_time = false; + let mut recvd = 0; + for cmsg in rmsg.cmsgs() { + if let ControlMessageOwned::ScmTimestampsns(timestamps) = cmsg { + let ts = timestamps.system; + + let sys_time = + crate::time::clock_gettime(crate::time::ClockId::CLOCK_REALTIME)?; + let diff = if ts > sys_time { + ts - sys_time + } else { + sys_time - ts + }; + assert!(std::time::Duration::from(diff).as_secs() < 60); + #[cfg(not(qemu))] + { + saw_time = true; + } + } } - }) - .collect()) -} -unsafe fn read_mhdr<'a, S>( + #[cfg(not(qemu))] + assert!(saw_time); + + for iov in rmsg.iovs() { + recvd += iov.len(); + } + assert_eq!(recvd, 400); + } + + Ok(()) + } +} +unsafe fn read_mhdr<'a, 'i, S>( mhdr: msghdr, r: isize, msg_controllen: usize, address: S, -) -> RecvMsg<'a, S> +) -> RecvMsg<'a, 'i, S> where S: SockaddrLike { // The cast is not unnecessary on all platforms. @@ -1693,9 +1901,21 @@ unsafe fn read_mhdr<'a, S>( address: Some(address), flags: MsgFlags::from_bits_truncate(mhdr.msg_flags), mhdr, + iobufs: std::marker::PhantomData, } } +/// Pack pointers to various structures into into msghdr +/// +/// # Safety +/// `iov_buffer` and `iov_buffer_len` must point to a slice +/// of `IoSliceMut` and number of available elements or be a null pointer and 0 +/// +/// `cmsg_buffer` and `cmsg_capacity` must point to a byte buffer used +/// to store control headers later or be a null pointer and 0 if control +/// headers are not used +/// +/// Buffers must remain valid for the whole lifetime of msghdr unsafe fn pack_mhdr_to_receive( iov_buffer: *const IoSliceMut, iov_buffer_len: usize, @@ -1789,8 +2009,9 @@ fn pack_mhdr_to_send<'a, I, C, S>( /// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>], mut cmsg_buffer: Option<&'a mut Vec>, - flags: MsgFlags) -> Result> - where S: SockaddrLike + 'a + flags: MsgFlags) -> Result> + where S: SockaddrLike + 'a, + 'inner: 'outer { let mut address = mem::MaybeUninit::uninit(); diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index b4ca279d67..7ab60ecc28 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -501,31 +501,31 @@ mod recvfrom { rsock, ssock, move |s, m, flags| { - let iov = [IoSlice::new(m)]; - let mut msgs = vec![SendMmsgData { - iov: &iov, - cmsgs: &[], - addr: Some(sock_addr), - _lt: Default::default(), - }]; - let batch_size = 15; + let mut iovs = Vec::with_capacity(1 + batch_size); + let mut addrs = Vec::with_capacity(1 + batch_size); + let mut data = MultiHeaders::preallocate(1 + batch_size, None); + let iov = IoSlice::new(m); + // first chunk: + iovs.push([iov]); + addrs.push(Some(sock_addr)); for _ in 0..batch_size { - msgs.push(SendMmsgData { - iov: &iov, - cmsgs: &[], - addr: Some(sock_addr2), - _lt: Default::default(), - }); + iovs.push([iov]); + addrs.push(Some(sock_addr2)); } - sendmmsg(s, msgs.iter(), flags).map(move |sent_bytes| { - assert!(!sent_bytes.is_empty()); - for sent in &sent_bytes { - assert_eq!(*sent, m.len()); - } - sent_bytes.len() - }) + + let res = sendmmsg(s, &mut data, &iovs, addrs, [], flags)?; + let mut sent_messages = 0; + let mut sent_bytes = 0; + for item in res { + sent_messages += 1; + sent_bytes += item.bytes; + } + // + assert_eq!(sent_messages, iovs.len()); + assert_eq!(sent_bytes, sent_messages * m.len()); + Ok(sent_messages) }, |_, _| {}, ); @@ -577,21 +577,19 @@ mod recvfrom { // Buffers to receive exactly `NUM_MESSAGES_SENT` messages let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT]; - let iovs: Vec<_> = receive_buffers - .iter_mut() - .map(|buf| [IoSliceMut::new(&mut buf[..])]) - .collect(); + msgs.extend( + receive_buffers + .iter_mut() + .map(|buf| [IoSliceMut::new(&mut buf[..])]), + ); - for iov in &iovs { - msgs.push_back(RecvMmsgData { - iov, - cmsg_buffer: None, - }) - } + let mut data = + MultiHeaders::::preallocate(msgs.len(), None); let res: Vec> = - recvmmsg(rsock, &mut msgs, MsgFlags::empty(), None) - .expect("recvmmsg"); + recvmmsg(rsock, &mut data, msgs.iter(), MsgFlags::empty(), None) + .expect("recvmmsg") + .collect(); assert_eq!(res.len(), DATA.len()); for RecvMsg { address, bytes, .. } in res.into_iter() { @@ -655,21 +653,26 @@ mod recvfrom { // will return when there are fewer than requested messages in the // kernel buffers when using `MSG_DONTWAIT`. let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2]; - let iovs: Vec<_> = receive_buffers - .iter_mut() - .map(|buf| [IoSliceMut::new(&mut buf[..])]) - .collect(); + msgs.extend( + receive_buffers + .iter_mut() + .map(|buf| [IoSliceMut::new(&mut buf[..])]), + ); - for iov in &iovs { - msgs.push_back(RecvMmsgData { - iov, - cmsg_buffer: None, - }) - } + let mut data = MultiHeaders::::preallocate( + NUM_MESSAGES_SENT + 2, + None, + ); - let res: Vec> = - recvmmsg(rsock, &mut msgs, MsgFlags::MSG_DONTWAIT, None) - .expect("recvmmsg"); + let res: Vec> = recvmmsg( + rsock, + &mut data, + msgs.iter(), + MsgFlags::MSG_DONTWAIT, + None, + ) + .expect("recvmmsg") + .collect(); assert_eq!(res.len(), NUM_MESSAGES_SENT); for RecvMsg { address, bytes, .. } in res.into_iter() { @@ -2205,14 +2208,13 @@ fn test_recvmmsg_timestampns() { assert_eq!(message.len(), l); // Receive the message let mut buffer = vec![0u8; message.len()]; - let mut cmsgspace = nix::cmsg_space!(TimeSpec); - let iov = [IoSliceMut::new(&mut buffer)]; - let mut data = vec![RecvMmsgData { - iov, - cmsg_buffer: Some(&mut cmsgspace), - }]; + let cmsgspace = nix::cmsg_space!(TimeSpec); + let iov = vec![[IoSliceMut::new(&mut buffer)]]; + let mut data = MultiHeaders::preallocate(1, Some(cmsgspace)); let r: Vec> = - recvmmsg(in_socket, &mut data, flags, None).unwrap(); + recvmmsg(in_socket, &mut data, iov.iter(), flags, None) + .unwrap() + .collect(); let rtime = match r[0].cmsgs().next() { Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, Some(_) => panic!("Unexpected control message"), From 475819c22bb86faa5d3b5a9ed681bd0afdb02eba Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Fri, 14 Oct 2022 09:00:58 -0400 Subject: [PATCH 192/358] disable a flaky test on aarch64 See https://github.com/nix-rust/nix/pull/1744 for more details --- src/sys/socket/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index aec09dc8b1..e11a70b1b9 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1841,7 +1841,7 @@ mod test { let recv = super::recvmmsg(rsock, &mut data, recv_iovs.iter(), flags, Some(t))?; for rmsg in recv { - #[cfg(not(qemu))] + #[cfg(not(any(qemu, target_arch = "aarch64")))] let mut saw_time = false; let mut recvd = 0; for cmsg in rmsg.cmsgs() { @@ -1856,14 +1856,14 @@ mod test { sys_time - ts }; assert!(std::time::Duration::from(diff).as_secs() < 60); - #[cfg(not(qemu))] + #[cfg(not(any(qemu, target_arch = "aarch64")))] { saw_time = true; } } } - #[cfg(not(qemu))] + #[cfg(not(any(qemu, target_arch = "aarch64")))] assert!(saw_time); for iov in rmsg.iovs() { From d13c2ccf996059f7e0f9be99b67d1ffe6c16d8bc Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Fri, 14 Oct 2022 10:13:43 -0400 Subject: [PATCH 193/358] include docs --- src/sys/socket/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index e11a70b1b9..04a6f937a4 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1635,6 +1635,11 @@ impl MultiHeaders { /// call to recvmmsg(). In the current implementation, however, the error code can be /// overwritten in the meantime by an unrelated network event on a socket, for example an /// incoming ICMP packet. + +// On aarch64 linux using recvmmsg and trying to get hardware/kernel timestamps might not +// always produce the desired results - see https://github.com/nix-rust/nix/pull/1744 for more +// details + #[cfg(any( target_os = "linux", target_os = "android", From 0696987995427cc61fe2268ab67c46a669026286 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 23 Oct 2022 09:09:10 -0600 Subject: [PATCH 194/358] Suppress deprecation warnings from the latest libc https://github.com/rust-lang/libc/pull/2963 --- src/sys/socket/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 04a6f937a4..af19c52dfd 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -272,14 +272,17 @@ libc_bitflags! { /// Sends or requests out-of-band data on sockets that support this notion /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also /// support out-of-band data. + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_OOB; /// Peeks at an incoming message. The data is treated as unread and the next /// [`recv()`](fn.recv.html) /// or similar function shall still return this data. + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_PEEK; /// Receive operation blocks until the full amount of data can be /// returned. The function may return smaller amount of data if a signal /// is caught, an error or disconnect occurs. + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_WAITALL; /// Enables nonblocking operation; if the operation would block, /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar @@ -291,8 +294,10 @@ libc_bitflags! { /// which will affect all threads in /// the calling process and as well as other processes that hold /// file descriptors referring to the same open file description. + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_DONTWAIT; /// Receive flags: Control Data was discarded (buffer too small) + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_CTRUNC; /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram /// (since Linux 2.4.27/2.6.8), @@ -302,15 +307,18 @@ libc_bitflags! { /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets. /// /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp). + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_TRUNC; /// Terminates a record (when this notion is supported, as for /// sockets of type [`SeqPacket`](enum.SockType.html)). + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_EOR; /// This flag specifies that queued errors should be received from /// the socket error queue. (For more details, see /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom)) #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_ERRQUEUE; /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain /// file descriptor using the `SCM_RIGHTS` operation (described in @@ -326,6 +334,7 @@ libc_bitflags! { target_os = "netbsd", target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_CMSG_CLOEXEC; /// Requests not to send `SIGPIPE` errors when the other end breaks the connection. /// (For more details, see [send(2)](https://linux.die.net/man/2/send)). @@ -340,6 +349,7 @@ libc_bitflags! { target_os = "openbsd", target_os = "solaris"))] #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_NOSIGNAL; } } From d6fdd5952deb826a0428ba54f08f8048291030c0 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 17 Oct 2022 17:19:49 -0600 Subject: [PATCH 195/358] On Linux-like operating systems, use statfs64 instead of statfs. And fstatfs64 instead of fstatfs. --- src/sys/statfs.rs | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 83196dbadc..a302b4e891 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -7,6 +7,8 @@ use std::os::unix::io::AsRawFd; #[cfg(not(any(target_os = "linux", target_os = "android")))] use std::ffi::CStr; +use cfg_if::cfg_if; + use crate::{NixPath, Result, errno::Errno}; /// Identifies a mounted file system @@ -18,10 +20,30 @@ pub type fsid_t = libc::__fsid_t; #[cfg_attr(docsrs, doc(cfg(all())))] pub type fsid_t = libc::fsid_t; +cfg_if! { + if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] { + type type_of_statfs = libc::statfs64; + const LIBC_FSTATFS: unsafe extern fn + (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int + = libc::fstatfs64; + const LIBC_STATFS: unsafe extern fn + (path: *const libc::c_char, buf: *mut type_of_statfs) -> libc::c_int + = libc::statfs64; + } else { + type type_of_statfs = libc::statfs; + const LIBC_FSTATFS: unsafe extern fn + (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int + = libc::fstatfs; + const LIBC_STATFS: unsafe extern fn + (path: *const libc::c_char, buf: *mut type_of_statfs) -> libc::c_int + = libc::statfs; + } +} + /// Describes a mounted file system #[derive(Clone, Copy)] #[repr(transparent)] -pub struct Statfs(libc::statfs); +pub struct Statfs(type_of_statfs); #[cfg(target_os = "freebsd")] type fs_type_t = u32; @@ -642,8 +664,8 @@ impl Debug for Statfs { /// `path` - Path to any file within the file system to describe pub fn statfs(path: &P) -> Result { unsafe { - let mut stat = mem::MaybeUninit::::uninit(); - let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), stat.as_mut_ptr()))?; + let mut stat = mem::MaybeUninit::::uninit(); + let res = path.with_nix_path(|path| LIBC_STATFS(path.as_ptr(), stat.as_mut_ptr()))?; Errno::result(res).map(|_| Statfs(stat.assume_init())) } } @@ -658,8 +680,8 @@ pub fn statfs(path: &P) -> Result { /// `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(); - Errno::result(libc::fstatfs(fd.as_raw_fd(), stat.as_mut_ptr())) + let mut stat = mem::MaybeUninit::::uninit(); + Errno::result(LIBC_FSTATFS(fd.as_raw_fd(), stat.as_mut_ptr())) .map(|_| Statfs(stat.assume_init())) } } From 3f66d1f4ce06403f646876864260c59ca3627ee4 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 18 Oct 2022 08:38:16 -0600 Subject: [PATCH 196/358] Define `MntFlags` and `unmount` on all of the BSDs. --- CHANGELOG.md | 2 + Cargo.toml | 2 +- src/lib.rs | 1 - src/mount/bsd.rs | 32 +++++++++---- src/sys/statfs.rs | 111 +++++++++++----------------------------------- 5 files changed, 51 insertions(+), 97 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de01c2f7f0..5c3a3d1d02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Add `MntFlags` and `unmount` on all of the BSDs. + ([#1849](https://github.com/nix-rust/nix/pull/1849)) - Added `NSFS_MAGIC` FsType on Linux and Android. ([#1829](https://github.com/nix-rust/nix/pull/1829)) - Added `sched_getcpu` on platforms that support it. diff --git a/Cargo.toml b/Cargo.toml index 2edb003b41..e09f758a25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.135", features = [ "extra_traits" ] } +libc = { git = "https://github.com/rust-lang/libc", rev = "cc19b6f0801", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } diff --git a/src/lib.rs b/src/lib.rs index 770258dd36..6b82125761 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,7 +106,6 @@ feature! { #[allow(missing_docs)] pub mod kmod; } -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] feature! { #![feature = "mount"] pub mod mount; diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs index 109522f9fb..1ba8b80902 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd.rs @@ -1,16 +1,22 @@ +#[cfg(target_os = "freebsd")] use crate::{ Error, +}; +use crate::{ Errno, NixPath, Result, }; -use libc::{c_char, c_int, c_uint, c_void}; +#[cfg(target_os = "freebsd")] +use libc::{c_char, c_uint, c_void}; +use libc::c_int; +#[cfg(target_os = "freebsd")] use std::{ borrow::Cow, ffi::{CString, CStr}, + marker::PhantomData, fmt, io, - marker::PhantomData, }; @@ -110,12 +116,14 @@ libc_bitflags!( /// /// It wraps an [`Errno`], but also may contain an additional message returned /// by `nmount(2)`. +#[cfg(target_os = "freebsd")] #[derive(Debug)] pub struct NmountError { errno: Error, errmsg: Option } +#[cfg(target_os = "freebsd")] impl NmountError { /// Returns the additional error string sometimes generated by `nmount(2)`. pub fn errmsg(&self) -> Option<&str> { @@ -135,8 +143,10 @@ impl NmountError { } } +#[cfg(target_os = "freebsd")] impl std::error::Error for NmountError {} +#[cfg(target_os = "freebsd")] impl fmt::Display for NmountError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(errmsg) = &self.errmsg { @@ -147,6 +157,7 @@ impl fmt::Display for NmountError { } } +#[cfg(target_os = "freebsd")] impl From for io::Error { fn from(err: NmountError) -> Self { err.errno.into() @@ -154,6 +165,7 @@ impl From for io::Error { } /// Result type of [`Nmount::nmount`]. +#[cfg(target_os = "freebsd")] pub type NmountResult = std::result::Result<(), NmountError>; /// Mount a FreeBSD file system. @@ -425,13 +437,15 @@ impl<'a> Drop for Nmount<'a> { /// /// Useful flags include /// * `MNT_FORCE` - Unmount even if still in use. -/// * `MNT_BYFSID` - `mountpoint` is not a path, but a file system ID -/// encoded as `FSID:val0:val1`, where `val0` and `val1` -/// are the contents of the `fsid_t val[]` array in decimal. -/// The file system that has the specified file system ID -/// will be unmounted. See -/// [`statfs`](crate::sys::statfs::statfs) to determine the -/// `fsid`. +#[cfg_attr(target_os = "freebsd", doc = " +* `MNT_BYFSID` - `mountpoint` is not a path, but a file system ID + encoded as `FSID:val0:val1`, where `val0` and `val1` + are the contents of the `fsid_t val[]` array in decimal. + The file system that has the specified file system ID + will be unmounted. See + [`statfs`](crate::sys::statfs::statfs) to determine the + `fsid`. +")] pub fn unmount

(mountpoint: &P, flags: MntFlags) -> Result<()> where P: ?Sized + NixPath { diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index a302b4e891..acbc75cd1d 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -422,7 +422,9 @@ impl Statfs { target_os = "macos", target_os = "android", target_os = "freebsd", + target_os = "fuchsia", target_os = "openbsd", + target_os = "linux", ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks(&self) -> u64 { @@ -437,24 +439,9 @@ impl Statfs { } /// Total data blocks in filesystem - #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(target_os = "emscripten")] #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks(&self) -> u64 { - self.0.f_blocks - } - - /// Total data blocks in filesystem - #[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks(&self) -> libc::c_ulong { + pub fn blocks(&self) -> u32 { self.0.f_blocks } @@ -464,7 +451,9 @@ impl Statfs { target_os = "macos", target_os = "android", target_os = "freebsd", + target_os = "fuchsia", target_os = "openbsd", + target_os = "linux", ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_free(&self) -> u64 { @@ -479,29 +468,20 @@ impl Statfs { } /// Free blocks in filesystem - #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(target_os = "emscripten")] #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_free(&self) -> u64 { + pub fn blocks_free(&self) -> u32 { self.0.f_bfree } - /// Free blocks in filesystem - #[cfg(not(any( + /// Free blocks available to unprivileged user + #[cfg(any( target_os = "ios", target_os = "macos", target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_free(&self) -> libc::c_ulong { - self.0.f_bfree - } - - /// Free blocks available to unprivileged user - #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))] + target_os = "fuchsia", + target_os = "linux", + ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_available(&self) -> u64 { self.0.f_bavail @@ -522,24 +502,9 @@ impl Statfs { } /// Free blocks available to unprivileged user - #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(target_os = "emscripten")] #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_available(&self) -> u64 { - self.0.f_bavail - } - - /// Free blocks available to unprivileged user - #[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_available(&self) -> libc::c_ulong { + pub fn blocks_available(&self) -> u32 { self.0.f_bavail } @@ -549,7 +514,9 @@ impl Statfs { target_os = "macos", target_os = "android", target_os = "freebsd", + target_os = "fuchsia", target_os = "openbsd", + target_os = "linux", ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files(&self) -> u64 { @@ -564,33 +531,20 @@ impl Statfs { } /// Total file nodes in filesystem - #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(target_os = "emscripten")] #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files(&self) -> libc::fsfilcnt_t { + pub fn files(&self) -> u32 { self.0.f_files } - /// Total file nodes in filesystem - #[cfg(not(any( + /// Free file nodes in filesystem + #[cfg(any( target_os = "ios", target_os = "macos", target_os = "android", - target_os = "freebsd", + target_os = "fuchsia", target_os = "openbsd", - target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files(&self) -> libc::c_ulong { - self.0.f_files - } - - /// Free file nodes in filesystem - #[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" + target_os = "linux", ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> u64 { @@ -612,24 +566,9 @@ impl Statfs { } /// Free file nodes in filesystem - #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files_free(&self) -> libc::fsfilcnt_t { - self.0.f_ffree - } - - /// Free file nodes in filesystem - #[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) - )))] + #[cfg(target_os = "emscripten")] #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files_free(&self) -> libc::c_ulong { + pub fn files_free(&self) -> u32 { self.0.f_ffree } From b2c036164744bc06f2f194f4ea7c9b8acc19234c Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 17 Oct 2022 19:00:48 -0600 Subject: [PATCH 197/358] Add a Statfs::flags method It returns the mount flags on the BSDs. On Linux, it returns a slightly different set of flags. --- CHANGELOG.md | 2 ++ src/sys/statfs.rs | 62 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c3a3d1d02..43d122ab10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Add `MntFlags` and `unmount` on all of the BSDs. ([#1849](https://github.com/nix-rust/nix/pull/1849)) +- Added a 'Statfs::flags' method. + ([#1849](https://github.com/nix-rust/nix/pull/1849)) - Added `NSFS_MAGIC` FsType on Linux and Android. ([#1829](https://github.com/nix-rust/nix/pull/1829)) - Added `sched_getcpu` on platforms that support it. diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index acbc75cd1d..9c28bc2120 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -10,6 +10,16 @@ use std::ffi::CStr; use cfg_if::cfg_if; use crate::{NixPath, Result, errno::Errno}; +#[cfg(all(feature = "mount", + any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd") +))] +use crate::mount::MntFlags; +#[cfg(target_os = "linux")] +use crate::sys::statvfs::FsFlags; /// Identifies a mounted file system #[cfg(target_os = "android")] @@ -374,6 +384,29 @@ impl Statfs { self.0.f_bsize } + /// Get the mount flags + #[cfg(all(feature = "mount", + any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd") + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all arches + pub fn flags(&self) -> MntFlags { + MntFlags::from_bits_truncate(self.0.f_flags as i32) + } + + /// Get the mount flags + // The f_flags field exists on Android and Fuchsia too, but without man + // pages I can't tell if it can be cast to FsFlags. + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn flags(&self) -> FsFlags { + FsFlags::from_bits_truncate(self.0.f_flags as libc::c_ulong) + } + /// Maximum length of filenames #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] @@ -580,16 +613,25 @@ impl Statfs { impl Debug for Statfs { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Statfs") - .field("optimal_transfer_size", &self.optimal_transfer_size()) - .field("block_size", &self.block_size()) - .field("blocks", &self.blocks()) - .field("blocks_free", &self.blocks_free()) - .field("blocks_available", &self.blocks_available()) - .field("files", &self.files()) - .field("files_free", &self.files_free()) - .field("filesystem_id", &self.filesystem_id()) - .finish() + let mut ds = f.debug_struct("Statfs"); + ds.field("optimal_transfer_size", &self.optimal_transfer_size()); + ds.field("block_size", &self.block_size()); + ds.field("blocks", &self.blocks()); + ds.field("blocks_free", &self.blocks_free()); + ds.field("blocks_available", &self.blocks_available()); + ds.field("files", &self.files()); + ds.field("files_free", &self.files_free()); + ds.field("filesystem_id", &self.filesystem_id()); + #[cfg(all(feature = "mount", + any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd") + ))] + ds.field("flags", &self.flags()); + ds.finish() + } } From 17833268cb3269d83766bcdb4d9cbe0e25ebd38e Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sun, 6 Nov 2022 11:27:08 -0800 Subject: [PATCH 198/358] Reformat everything Signed-off-by: Alex Saveau --- .cirrus.yml | 2 +- src/dir.rs | 61 +- src/features.rs | 40 +- src/ifaddrs.rs | 7 +- src/kmod.rs | 10 +- src/mount/bsd.rs | 78 ++- src/mount/linux.rs | 57 +- src/mount/mod.rs | 25 +- src/mqueue.rs | 110 ++-- src/net/if_.rs | 3 +- src/poll.rs | 10 +- src/pty.rs | 60 +- src/sched.rs | 31 +- src/sys/aio.rs | 23 +- src/sys/epoll.rs | 36 +- src/sys/event.rs | 162 +++-- src/sys/eventfd.rs | 4 +- src/sys/inotify.rs | 53 +- src/sys/memfd.rs | 4 +- src/sys/mman.rs | 62 +- src/sys/personality.rs | 10 +- src/sys/ptrace/bsd.rs | 46 +- src/sys/ptrace/linux.rs | 180 +++-- src/sys/ptrace/mod.rs | 27 +- src/sys/quota.rs | 115 +++- src/sys/reboot.rs | 10 +- src/sys/resource.rs | 9 +- src/sys/select.rs | 73 ++- src/sys/sendfile.rs | 2 +- src/sys/signalfd.rs | 24 +- src/sys/socket/addr.rs | 1300 ++++++++++++++++++++++--------------- src/sys/socket/sockopt.rs | 572 ++++++++++++---- src/sys/stat.rs | 136 ++-- src/sys/statfs.rs | 215 ++++-- src/sys/statvfs.rs | 9 +- src/sys/termios.rs | 168 +++-- src/sys/timer.rs | 14 +- src/sys/timerfd.rs | 17 +- src/sys/uio.rs | 95 +-- src/sys/utsname.rs | 16 +- src/sys/wait.rs | 13 +- src/time.rs | 42 +- src/ucontext.rs | 16 +- 43 files changed, 2530 insertions(+), 1417 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 30f1b122a2..ab1178dd1a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -315,4 +315,4 @@ task: container: image: rust:latest setup_script: rustup +$TOOLCHAIN component add rustfmt - test_script: $TOOL +$TOOLCHAIN fmt --all -- --check + test_script: $TOOL +$TOOLCHAIN fmt --all -- --check **/*.rs diff --git a/src/dir.rs b/src/dir.rs index e36a8aa650..5ce503644e 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -1,13 +1,13 @@ //! List directory contents -use crate::{Error, NixPath, Result}; use crate::errno::Errno; use crate::fcntl::{self, OFlag}; -use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; -use std::ptr; -use std::ffi; use crate::sys; +use crate::{Error, NixPath, Result}; use cfg_if::cfg_if; +use std::ffi; +use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; +use std::ptr; #[cfg(target_os = "linux")] use libc::{dirent64 as dirent, readdir64_r as readdir_r}; @@ -29,21 +29,26 @@ use libc::{dirent, readdir_r}; /// * returns entries' names as a `CStr` (no allocation or conversion beyond whatever libc /// does). #[derive(Debug, Eq, Hash, PartialEq)] -pub struct Dir( - ptr::NonNull -); +pub struct Dir(ptr::NonNull); impl Dir { /// Opens the given path as with `fcntl::open`. - pub fn open(path: &P, oflag: OFlag, - mode: sys::stat::Mode) -> Result { + pub fn open( + path: &P, + oflag: OFlag, + mode: sys::stat::Mode, + ) -> Result { let fd = fcntl::open(path, oflag, mode)?; Dir::from_fd(fd) } /// Opens the given path as with `fcntl::openat`. - pub fn openat(dirfd: RawFd, path: &P, oflag: OFlag, - mode: sys::stat::Mode) -> Result { + pub fn openat( + dirfd: RawFd, + path: &P, + oflag: OFlag, + mode: sys::stat::Mode, + ) -> Result { let fd = fcntl::openat(dirfd, path, oflag, mode)?; Dir::from_fd(fd) } @@ -57,11 +62,13 @@ impl Dir { /// Converts from a file descriptor, closing it on success or failure. #[doc(alias("fdopendir"))] pub fn from_fd(fd: RawFd) -> Result { - let d = ptr::NonNull::new(unsafe { libc::fdopendir(fd) }).ok_or_else(|| { - let e = Error::last(); - unsafe { libc::close(fd) }; - e - })?; + let d = ptr::NonNull::new(unsafe { libc::fdopendir(fd) }).ok_or_else( + || { + let e = Error::last(); + unsafe { libc::close(fd) }; + e + }, + )?; Ok(Dir(d)) } @@ -103,9 +110,11 @@ fn next(dir: &mut Dir) -> Option> { // Probably fine here too then. let mut ent = std::mem::MaybeUninit::::uninit(); let mut result = ptr::null_mut(); - if let Err(e) = Errno::result( - readdir_r(dir.0.as_ptr(), ent.as_mut_ptr(), &mut result)) - { + if let Err(e) = Errno::result(readdir_r( + dir.0.as_ptr(), + ent.as_mut_ptr(), + &mut result, + )) { return Some(Err(e)); } if result.is_null() { @@ -207,7 +216,7 @@ pub enum Type { impl Entry { /// Returns the inode number (`d_ino`) of the underlying `dirent`. - #[allow(clippy::useless_conversion)] // Not useless on all OSes + #[allow(clippy::useless_conversion)] // Not useless on all OSes // The cast is not unnecessary on all platforms. #[allow(clippy::unnecessary_cast)] pub fn ino(&self) -> u64 { @@ -240,7 +249,11 @@ impl Entry { /// notably, some Linux filesystems don't implement this. The caller should use `stat` or /// `fstat` if this returns `None`. pub fn file_type(&self) -> Option { - #[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "haiku")))] + #[cfg(not(any( + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" + )))] match self.0.d_type { libc::DT_FIFO => Some(Type::Fifo), libc::DT_CHR => Some(Type::CharacterDevice), @@ -253,7 +266,11 @@ impl Entry { } // illumos, Solaris, and Haiku systems do not have the d_type member at all: - #[cfg(any(target_os = "illumos", target_os = "solaris", target_os = "haiku"))] + #[cfg(any( + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" + ))] None } } diff --git a/src/features.rs b/src/features.rs index d2adc1693b..39d17604e1 100644 --- a/src/features.rs +++ b/src/features.rs @@ -3,9 +3,9 @@ pub use self::os::*; #[cfg(any(target_os = "linux", target_os = "android"))] mod os { - use std::os::unix::ffi::OsStrExt; use crate::sys::utsname::uname; use crate::Result; + use std::os::unix::ffi::OsStrExt; // Features: // * atomic cloexec on socket: 2.6.27 @@ -13,10 +13,10 @@ mod os { // * accept4: 2.6.28 static VERS_UNKNOWN: usize = 1; - static VERS_2_6_18: usize = 2; - static VERS_2_6_27: usize = 3; - static VERS_2_6_28: usize = 4; - static VERS_3: usize = 5; + static VERS_2_6_18: usize = 2; + static VERS_2_6_27: usize = 3; + static VERS_2_6_28: usize = 4; + static VERS_3: usize = 5; #[inline] fn digit(dst: &mut usize, b: u8) { @@ -27,7 +27,7 @@ mod os { fn parse_kernel_version() -> Result { let u = uname()?; - let mut curr: usize = 0; + let mut curr: usize = 0; let mut major: usize = 0; let mut minor: usize = 0; let mut patch: usize = 0; @@ -41,13 +41,11 @@ mod os { b'.' | b'-' => { curr += 1; } - b'0'..=b'9' => { - match curr { - 0 => digit(&mut major, b), - 1 => digit(&mut minor, b), - _ => digit(&mut patch, b), - } - } + b'0'..=b'9' => match curr { + 0 => digit(&mut major, b), + 1 => digit(&mut minor, b), + _ => digit(&mut patch, b), + }, _ => break, } } @@ -87,7 +85,9 @@ mod os { /// Check if the OS supports atomic close-on-exec for sockets pub fn socket_atomic_cloexec() -> bool { - kernel_version().map(|version| version >= VERS_2_6_27).unwrap_or(false) + kernel_version() + .map(|version| version >= VERS_2_6_27) + .unwrap_or(false) } #[test] @@ -111,11 +111,13 @@ mod os { } } -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "fuchsia", - target_os = "haiku", - target_os = "solaris"))] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "fuchsia", + target_os = "haiku", + target_os = "solaris" +))] mod os { /// Check if the OS supports atomic close-on-exec for sockets pub const fn socket_atomic_cloexec() -> bool { diff --git a/src/ifaddrs.rs b/src/ifaddrs.rs index f834d30762..210d4d7742 100644 --- a/src/ifaddrs.rs +++ b/src/ifaddrs.rs @@ -9,9 +9,9 @@ use std::iter::Iterator; use std::mem; use std::option::Option; -use crate::{Result, Errno}; -use crate::sys::socket::{SockaddrLike, SockaddrStorage}; use crate::net::if_::*; +use crate::sys::socket::{SockaddrLike, SockaddrStorage}; +use crate::{Errno, Result}; /// Describes a single address for an interface as returned by `getifaddrs`. #[derive(Clone, Debug, Eq, Hash, PartialEq)] @@ -47,7 +47,8 @@ impl InterfaceAddress { fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress { let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) }; let address = unsafe { SockaddrStorage::from_raw(info.ifa_addr, None) }; - let netmask = unsafe { SockaddrStorage::from_raw(info.ifa_netmask, None) }; + let netmask = + unsafe { SockaddrStorage::from_raw(info.ifa_netmask, None) }; let mut addr = InterfaceAddress { interface_name: ifname.to_string_lossy().to_string(), flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32), diff --git a/src/kmod.rs b/src/kmod.rs index c42068c70a..1fa6c170d9 100644 --- a/src/kmod.rs +++ b/src/kmod.rs @@ -79,7 +79,11 @@ libc_bitflags!( /// ``` /// /// See [`man init_module(2)`](https://man7.org/linux/man-pages/man2/init_module.2.html) for more information. -pub fn finit_module(fd: &T, param_values: &CStr, flags: ModuleInitFlags) -> Result<()> { +pub fn finit_module( + fd: &T, + param_values: &CStr, + flags: ModuleInitFlags, +) -> Result<()> { let res = unsafe { libc::syscall( libc::SYS_finit_module, @@ -116,7 +120,9 @@ libc_bitflags!( /// /// See [`man delete_module(2)`](https://man7.org/linux/man-pages/man2/delete_module.2.html) for more information. pub fn delete_module(name: &CStr, flags: DeleteModuleFlags) -> Result<()> { - let res = unsafe { libc::syscall(libc::SYS_delete_module, name.as_ptr(), flags.bits()) }; + let res = unsafe { + libc::syscall(libc::SYS_delete_module, name.as_ptr(), flags.bits()) + }; Errno::result(res).map(drop) } diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs index 1ba8b80902..d124f1f9ab 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd.rs @@ -1,25 +1,17 @@ #[cfg(target_os = "freebsd")] -use crate::{ - Error, -}; -use crate::{ - Errno, - NixPath, - Result, -}; +use crate::Error; +use crate::{Errno, NixPath, Result}; +use libc::c_int; #[cfg(target_os = "freebsd")] use libc::{c_char, c_uint, c_void}; -use libc::c_int; #[cfg(target_os = "freebsd")] use std::{ borrow::Cow, - ffi::{CString, CStr}, + ffi::{CStr, CString}, + fmt, io, marker::PhantomData, - fmt, - io, }; - libc_bitflags!( /// Used with [`Nmount::nmount`]. pub struct MntFlags: c_int { @@ -111,7 +103,6 @@ libc_bitflags!( } ); - /// The Error type of [`Nmount::nmount`]. /// /// It wraps an [`Errno`], but also may contain an additional message returned @@ -120,7 +111,7 @@ libc_bitflags!( #[derive(Debug)] pub struct NmountError { errno: Error, - errmsg: Option + errmsg: Option, } #[cfg(target_os = "freebsd")] @@ -138,7 +129,7 @@ impl NmountError { fn new(error: Error, errmsg: Option<&CStr>) -> Self { Self { errno: error, - errmsg: errmsg.map(CStr::to_string_lossy).map(Cow::into_owned) + errmsg: errmsg.map(CStr::to_string_lossy).map(Cow::into_owned), } } } @@ -199,7 +190,7 @@ pub type NmountResult = std::result::Result<(), NmountError>; /// .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) /// .str_opt_owned("target", target.path().to_str().unwrap()) /// .nmount(MntFlags::empty()).unwrap(); -/// +/// /// unmount(mountpoint.path(), MntFlags::empty()).unwrap(); /// ``` /// @@ -209,7 +200,7 @@ pub type NmountResult = std::result::Result<(), NmountError>; #[cfg(target_os = "freebsd")] #[cfg_attr(docsrs, doc(cfg(all())))] #[derive(Debug, Default)] -pub struct Nmount<'a>{ +pub struct Nmount<'a> { // n.b. notgull: In reality, this is a list that contains // both mutable and immutable pointers. // Be careful using this. @@ -231,7 +222,12 @@ impl<'a> Nmount<'a> { } /// Helper function to push a pointer and its length onto the `iov` array. - fn push_pointer_and_length(&mut self, val: *const u8, len: usize, is_owned: bool) { + fn push_pointer_and_length( + &mut self, + val: *const u8, + len: usize, + is_owned: bool, + ) { self.iov.push(libc::iovec { iov_base: val as *mut _, iov_len: len, @@ -246,7 +242,8 @@ impl<'a> Nmount<'a> { let ptr = s.to_owned().into_raw() as *const u8; self.push_pointer_and_length(ptr, len, true); - }).unwrap(); + }) + .unwrap(); } /// Add an opaque mount option. @@ -280,9 +277,8 @@ impl<'a> Nmount<'a> { &mut self, name: &'a CStr, val: *mut c_void, - len: usize - ) -> &mut Self - { + len: usize, + ) -> &mut Self { self.push_slice(name.to_bytes_with_nul(), false); self.push_pointer_and_length(val.cast(), len, false); self @@ -321,8 +317,10 @@ impl<'a> Nmount<'a> { /// let mut nmount: Nmount<'static> = Nmount::new(); /// nmount.null_opt_owned(read_only); /// ``` - pub fn null_opt_owned(&mut self, name: &P) -> &mut Self - { + pub fn null_opt_owned( + &mut self, + name: &P, + ) -> &mut Self { self.push_nix_path(name); self.push_slice(&[], false); self @@ -340,12 +338,7 @@ impl<'a> Nmount<'a> { /// Nmount::new() /// .str_opt(&fstype, &nullfs); /// ``` - pub fn str_opt( - &mut self, - name: &'a CStr, - val: &'a CStr - ) -> &mut Self - { + pub fn str_opt(&mut self, name: &'a CStr, val: &'a CStr) -> &mut Self { self.push_slice(name.to_bytes_with_nul(), false); self.push_slice(val.to_bytes_with_nul(), false); self @@ -367,8 +360,9 @@ impl<'a> Nmount<'a> { /// .str_opt_owned("fspath", mountpoint.to_str().unwrap()); /// ``` pub fn str_opt_owned(&mut self, name: &P1, val: &P2) -> &mut Self - where P1: ?Sized + NixPath, - P2: ?Sized + NixPath + where + P1: ?Sized + NixPath, + P2: ?Sized + NixPath, { self.push_nix_path(name); self.push_nix_path(val); @@ -398,9 +392,7 @@ impl<'a> Nmount<'a> { let niov = self.iov.len() as c_uint; let iovp = self.iov.as_mut_ptr() as *mut libc::iovec; - let res = unsafe { - libc::nmount(iovp, niov, flags.bits) - }; + let res = unsafe { libc::nmount(iovp, niov, flags.bits) }; match Errno::result(res) { Ok(_) => Ok(()), Err(error) => { @@ -437,7 +429,9 @@ impl<'a> Drop for Nmount<'a> { /// /// Useful flags include /// * `MNT_FORCE` - Unmount even if still in use. -#[cfg_attr(target_os = "freebsd", doc = " +#[cfg_attr( + target_os = "freebsd", + doc = " * `MNT_BYFSID` - `mountpoint` is not a path, but a file system ID encoded as `FSID:val0:val1`, where `val0` and `val1` are the contents of the `fsid_t val[]` array in decimal. @@ -445,12 +439,14 @@ impl<'a> Drop for Nmount<'a> { will be unmounted. See [`statfs`](crate::sys::statfs::statfs) to determine the `fsid`. -")] +" +)] pub fn unmount

(mountpoint: &P, flags: MntFlags) -> Result<()> - where P: ?Sized + NixPath +where + P: ?Sized + NixPath, { - let res = mountpoint.with_nix_path(|cstr| { - unsafe { libc::unmount(cstr.as_ptr(), flags.bits) } + let res = mountpoint.with_nix_path(|cstr| unsafe { + libc::unmount(cstr.as_ptr(), flags.bits) })?; Errno::result(res).map(drop) diff --git a/src/mount/linux.rs b/src/mount/linux.rs index 4c976dcb5a..cf6a60b017 100644 --- a/src/mount/linux.rs +++ b/src/mount/linux.rs @@ -1,7 +1,7 @@ #![allow(missing_docs)] -use libc::{self, c_ulong, c_int}; -use crate::{Result, NixPath}; use crate::errno::Errno; +use crate::{NixPath, Result}; +use libc::{self, c_int, c_ulong}; libc_bitflags!( pub struct MsFlags: c_ulong { @@ -57,36 +57,40 @@ libc_bitflags!( } ); -pub fn mount( - source: Option<&P1>, - target: &P2, - fstype: Option<&P3>, - flags: MsFlags, - data: Option<&P4>) -> Result<()> { - +pub fn mount< + P1: ?Sized + NixPath, + P2: ?Sized + NixPath, + P3: ?Sized + NixPath, + P4: ?Sized + NixPath, +>( + source: Option<&P1>, + target: &P2, + fstype: Option<&P3>, + flags: MsFlags, + data: Option<&P4>, +) -> Result<()> { fn with_opt_nix_path(p: Option<&P>, f: F) -> Result - where P: ?Sized + NixPath, - F: FnOnce(*const libc::c_char) -> T + where + P: ?Sized + NixPath, + F: FnOnce(*const libc::c_char) -> T, { match p { Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())), - None => Ok(f(std::ptr::null())) + None => Ok(f(std::ptr::null())), } } let res = with_opt_nix_path(source, |s| { target.with_nix_path(|t| { with_opt_nix_path(fstype, |ty| { - with_opt_nix_path(data, |d| { - unsafe { - libc::mount( - s, - t.as_ptr(), - ty, - flags.bits, - d as *const libc::c_void - ) - } + with_opt_nix_path(data, |d| unsafe { + libc::mount( + s, + t.as_ptr(), + ty, + flags.bits, + d as *const libc::c_void, + ) }) }) }) @@ -96,16 +100,15 @@ pub fn mount(target: &P) -> Result<()> { - let res = target.with_nix_path(|cstr| { - unsafe { libc::umount(cstr.as_ptr()) } - })?; + let res = + target.with_nix_path(|cstr| unsafe { libc::umount(cstr.as_ptr()) })?; Errno::result(res).map(drop) } pub fn umount2(target: &P, flags: MntFlags) -> Result<()> { - let res = target.with_nix_path(|cstr| { - unsafe { libc::umount2(cstr.as_ptr(), flags.bits) } + let res = target.with_nix_path(|cstr| unsafe { + libc::umount2(cstr.as_ptr(), flags.bits) })?; Errno::result(res).map(drop) diff --git a/src/mount/mod.rs b/src/mount/mod.rs index e89c1a07c3..e98b49c343 100644 --- a/src/mount/mod.rs +++ b/src/mount/mod.rs @@ -6,18 +6,21 @@ mod linux; #[cfg(any(target_os = "android", target_os = "linux"))] pub use self::linux::*; -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] #[cfg_attr(docsrs, doc(cfg(all())))] mod bsd; -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] pub use self::bsd::*; diff --git a/src/mqueue.rs b/src/mqueue.rs index e3c0c43eee..33599bf91d 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -30,15 +30,15 @@ //! ``` //! [Further reading and details on the C API](https://man7.org/linux/man-pages/man7/mq_overview.7.html) -use crate::Result; use crate::errno::Errno; +use crate::Result; +use crate::sys::stat::Mode; use libc::{self, c_char, mqd_t, size_t}; use std::ffi::CStr; -use crate::sys::stat::Mode; use std::mem; -libc_bitflags!{ +libc_bitflags! { /// Used with [`mq_open`]. pub struct MQ_OFlag: libc::c_int { /// Open the message queue for receiving messages. @@ -96,12 +96,12 @@ impl MqAttr { /// - `mq_maxmsg`: Maximum number of messages on the queue. /// - `mq_msgsize`: Maximum message size in bytes. /// - `mq_curmsgs`: Number of messages currently in the queue. - pub fn new(mq_flags: mq_attr_member_t, - mq_maxmsg: mq_attr_member_t, - mq_msgsize: mq_attr_member_t, - mq_curmsgs: mq_attr_member_t) - -> MqAttr - { + pub fn new( + mq_flags: mq_attr_member_t, + mq_maxmsg: mq_attr_member_t, + mq_msgsize: mq_attr_member_t, + mq_curmsgs: mq_attr_member_t, + ) -> MqAttr { let mut attr = mem::MaybeUninit::::uninit(); unsafe { let p = attr.as_mut_ptr(); @@ -109,7 +109,9 @@ impl MqAttr { (*p).mq_maxmsg = mq_maxmsg; (*p).mq_msgsize = mq_msgsize; (*p).mq_curmsgs = mq_curmsgs; - MqAttr { mq_attr: attr.assume_init() } + MqAttr { + mq_attr: attr.assume_init(), + } } } @@ -134,23 +136,25 @@ impl MqAttr { } } - /// Open a message queue /// /// See also [`mq_open(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html) // The mode.bits cast is only lossless on some OSes #[allow(clippy::cast_lossless)] -pub fn mq_open(name: &CStr, - oflag: MQ_OFlag, - mode: Mode, - attr: Option<&MqAttr>) - -> Result { +pub fn mq_open( + name: &CStr, + oflag: MQ_OFlag, + mode: Mode, + attr: Option<&MqAttr>, +) -> Result { let res = match attr { Some(mq_attr) => unsafe { - libc::mq_open(name.as_ptr(), - oflag.bits(), - mode.bits() as libc::c_int, - &mq_attr.mq_attr as *const libc::mq_attr) + libc::mq_open( + name.as_ptr(), + oflag.bits(), + mode.bits() as libc::c_int, + &mq_attr.mq_attr as *const libc::mq_attr, + ) }, None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) }, }; @@ -176,13 +180,19 @@ pub fn mq_close(mqdes: MqdT) -> Result<()> { /// Receive a message from a message queue /// /// See also [`mq_receive(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html) -pub fn mq_receive(mqdes: &MqdT, message: &mut [u8], msg_prio: &mut u32) -> Result { +pub fn mq_receive( + mqdes: &MqdT, + message: &mut [u8], + msg_prio: &mut u32, +) -> Result { let len = message.len() as size_t; let res = unsafe { - libc::mq_receive(mqdes.0, - message.as_mut_ptr() as *mut c_char, - len, - msg_prio as *mut u32) + libc::mq_receive( + mqdes.0, + message.as_mut_ptr() as *mut c_char, + len, + msg_prio as *mut u32, + ) }; Errno::result(res).map(|r| r as usize) } @@ -192,10 +202,12 @@ pub fn mq_receive(mqdes: &MqdT, message: &mut [u8], msg_prio: &mut u32) -> Resul /// See also [`mq_send(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html) pub fn mq_send(mqdes: &MqdT, message: &[u8], msq_prio: u32) -> Result<()> { let res = unsafe { - libc::mq_send(mqdes.0, - message.as_ptr() as *const c_char, - message.len(), - msq_prio) + libc::mq_send( + mqdes.0, + message.as_ptr() as *const c_char, + message.len(), + msq_prio, + ) }; Errno::result(res).map(drop) } @@ -206,7 +218,11 @@ pub fn mq_send(mqdes: &MqdT, message: &[u8], msq_prio: u32) -> Result<()> { pub fn mq_getattr(mqd: &MqdT) -> Result { let mut attr = mem::MaybeUninit::::uninit(); let res = unsafe { libc::mq_getattr(mqd.0, attr.as_mut_ptr()) }; - Errno::result(res).map(|_| unsafe{MqAttr { mq_attr: attr.assume_init() }}) + Errno::result(res).map(|_| unsafe { + MqAttr { + mq_attr: attr.assume_init(), + } + }) } /// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored @@ -217,21 +233,31 @@ pub fn mq_getattr(mqd: &MqdT) -> Result { pub fn mq_setattr(mqd: &MqdT, newattr: &MqAttr) -> Result { let mut attr = mem::MaybeUninit::::uninit(); let res = unsafe { - libc::mq_setattr(mqd.0, &newattr.mq_attr as *const libc::mq_attr, attr.as_mut_ptr()) + libc::mq_setattr( + mqd.0, + &newattr.mq_attr as *const libc::mq_attr, + attr.as_mut_ptr(), + ) }; - Errno::result(res).map(|_| unsafe{ MqAttr { mq_attr: attr.assume_init() }}) + Errno::result(res).map(|_| unsafe { + MqAttr { + mq_attr: attr.assume_init(), + } + }) } /// Convenience function. /// Sets the `O_NONBLOCK` attribute for a given message queue descriptor /// Returns the old attributes -#[allow(clippy::useless_conversion)] // Not useless on all OSes +#[allow(clippy::useless_conversion)] // Not useless on all OSes pub fn mq_set_nonblock(mqd: &MqdT) -> Result { let oldattr = mq_getattr(mqd)?; - let newattr = MqAttr::new(mq_attr_member_t::from(MQ_OFlag::O_NONBLOCK.bits()), - oldattr.mq_attr.mq_maxmsg, - oldattr.mq_attr.mq_msgsize, - oldattr.mq_attr.mq_curmsgs); + let newattr = MqAttr::new( + mq_attr_member_t::from(MQ_OFlag::O_NONBLOCK.bits()), + oldattr.mq_attr.mq_maxmsg, + oldattr.mq_attr.mq_msgsize, + oldattr.mq_attr.mq_curmsgs, + ); mq_setattr(mqd, &newattr) } @@ -240,9 +266,11 @@ pub fn mq_set_nonblock(mqd: &MqdT) -> Result { /// Returns the old attributes pub fn mq_remove_nonblock(mqd: &MqdT) -> Result { let oldattr = mq_getattr(mqd)?; - let newattr = MqAttr::new(0, - oldattr.mq_attr.mq_maxmsg, - oldattr.mq_attr.mq_msgsize, - oldattr.mq_attr.mq_curmsgs); + let newattr = MqAttr::new( + 0, + oldattr.mq_attr.mq_maxmsg, + oldattr.mq_attr.mq_msgsize, + oldattr.mq_attr.mq_curmsgs, + ); mq_setattr(mqd, &newattr) } diff --git a/src/net/if_.rs b/src/net/if_.rs index 045efad9cc..b2423bc673 100644 --- a/src/net/if_.rs +++ b/src/net/if_.rs @@ -8,7 +8,8 @@ use libc::c_uint; /// Resolve an interface into a interface number. pub fn if_nametoindex(name: &P) -> Result { - let if_index = name.with_nix_path(|name| unsafe { libc::if_nametoindex(name.as_ptr()) })?; + let if_index = name + .with_nix_path(|name| unsafe { libc::if_nametoindex(name.as_ptr()) })?; if if_index == 0 { Err(Error::last()) diff --git a/src/poll.rs b/src/poll.rs index 3004d24c37..e1baa814f1 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -1,8 +1,8 @@ //! Wait for events to trigger on specific file descriptors use std::os::unix::io::{AsRawFd, RawFd}; -use crate::Result; use crate::errno::Errno; +use crate::Result; /// This is a wrapper around `libc::pollfd`. /// @@ -134,9 +134,11 @@ libc_bitflags! { /// ready. pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result { let res = unsafe { - libc::poll(fds.as_mut_ptr() as *mut libc::pollfd, - fds.len() as libc::nfds_t, - timeout) + libc::poll( + fds.as_mut_ptr() as *mut libc::pollfd, + fds.len() as libc::nfds_t, + timeout, + ) }; Errno::result(res) diff --git a/src/pty.rs b/src/pty.rs index bb266a65bb..28ae5e924b 100644 --- a/src/pty.rs +++ b/src/pty.rs @@ -8,11 +8,11 @@ use std::io; use std::mem; use std::os::unix::prelude::*; +use crate::errno::Errno; use crate::sys::termios::Termios; #[cfg(feature = "process")] use crate::unistd::{ForkResult, Pid}; -use crate::{Result, fcntl, unistd}; -use crate::errno::Errno; +use crate::{fcntl, unistd, Result}; /// Representation of a master/slave pty pair /// @@ -41,7 +41,6 @@ pub struct ForkptyResult { } } - /// Representation of the Master device in a master/slave pty pair /// /// While this datatype is a thin wrapper around `RawFd`, it enforces that the available PTY @@ -159,9 +158,7 @@ pub fn grantpt(fd: &PtyMaster) -> Result<()> { /// ``` #[inline] pub fn posix_openpt(flags: fcntl::OFlag) -> Result { - let fd = unsafe { - libc::posix_openpt(flags.bits()) - }; + let fd = unsafe { libc::posix_openpt(flags.bits()) }; if fd < 0 { return Err(Errno::last()); @@ -239,7 +236,6 @@ pub fn unlockpt(fd: &PtyMaster) -> Result<()> { Ok(()) } - /// Create a new pseudoterminal, returning the slave and master file descriptors /// in `OpenptyResult` /// (see [`openpty`](https://man7.org/linux/man-pages/man3/openpty.3.html)). @@ -248,7 +244,15 @@ pub fn unlockpt(fd: &PtyMaster) -> Result<()> { /// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's /// terminal settings of the slave will be set to the values in `termios`. #[inline] -pub fn openpty<'a, 'b, T: Into>, U: Into>>(winsize: T, termios: U) -> Result { +pub fn openpty< + 'a, + 'b, + T: Into>, + U: Into>, +>( + winsize: T, + termios: U, +) -> Result { use std::ptr; let mut slave = mem::MaybeUninit::::uninit(); @@ -267,17 +271,15 @@ pub fn openpty<'a, 'b, T: Into>, U: Into ) } } - (None, Some(winsize)) => { - unsafe { - libc::openpty( - master.as_mut_ptr(), - slave.as_mut_ptr(), - ptr::null_mut(), - ptr::null_mut(), - winsize as *const Winsize as *mut _, - ) - } - } + (None, Some(winsize)) => unsafe { + libc::openpty( + master.as_mut_ptr(), + slave.as_mut_ptr(), + ptr::null_mut(), + ptr::null_mut(), + winsize as *const Winsize as *mut _, + ) + }, (Some(termios), None) => { let inner_termios = termios.get_libc_termios(); unsafe { @@ -290,17 +292,15 @@ pub fn openpty<'a, 'b, T: Into>, U: Into ) } } - (None, None) => { - unsafe { - libc::openpty( - master.as_mut_ptr(), - slave.as_mut_ptr(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ) - } - } + (None, None) => unsafe { + libc::openpty( + master.as_mut_ptr(), + slave.as_mut_ptr(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ) + }, } }; diff --git a/src/sched.rs b/src/sched.rs index aa2b90b4d8..d5b1233cf3 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -11,12 +11,12 @@ pub use self::sched_linux_like::*; #[cfg_attr(docsrs, doc(cfg(all())))] mod sched_linux_like { use crate::errno::Errno; + use crate::unistd::Pid; + use crate::Result; use libc::{self, c_int, c_void}; use std::mem; use std::option::Option; use std::os::unix::io::RawFd; - use crate::unistd::Pid; - use crate::Result; // For some functions taking with a parameter of type CloneFlags, // only a subset of these flags have an effect. @@ -112,7 +112,8 @@ mod sched_linux_like { let ptr_aligned = ptr.sub(ptr as usize % 16); libc::clone( mem::transmute( - callback as extern "C" fn(*mut Box isize>) -> i32, + callback + as extern "C" fn(*mut Box isize>) -> i32, ), ptr_aligned as *mut c_void, combined, @@ -142,15 +143,25 @@ mod sched_linux_like { } } -#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux" +))] pub use self::sched_affinity::*; -#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux" +))] mod sched_affinity { use crate::errno::Errno; - use std::mem; use crate::unistd::Pid; use crate::Result; + use std::mem; /// CpuSet represent a bit-mask of CPUs. /// CpuSets are used by sched_setaffinity and @@ -190,7 +201,9 @@ mod sched_affinity { if field >= CpuSet::count() { Err(Errno::EINVAL) } else { - unsafe { libc::CPU_SET(field, &mut self.cpu_set); } + unsafe { + libc::CPU_SET(field, &mut self.cpu_set); + } Ok(()) } } @@ -201,7 +214,9 @@ mod sched_affinity { if field >= CpuSet::count() { Err(Errno::EINVAL) } else { - unsafe { libc::CPU_CLR(field, &mut self.cpu_set);} + unsafe { + libc::CPU_CLR(field, &mut self.cpu_set); + } Ok(()) } } diff --git a/src/sys/aio.rs b/src/sys/aio.rs index 6ff88469b9..e2ce19b79d 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -32,8 +32,7 @@ use std::{ mem, os::unix::io::RawFd, pin::Pin, - ptr, - thread, + ptr, thread, }; use libc::{c_void, off_t}; @@ -107,7 +106,7 @@ unsafe impl Sync for LibcAiocb {} // polymorphism is at the level of `Futures`. #[repr(C)] struct AioCb { - aiocb: LibcAiocb, + aiocb: LibcAiocb, /// Could this `AioCb` potentially have any in-kernel state? // It would be really nice to perform the in-progress check entirely at // compile time. But I can't figure out how, because: @@ -153,7 +152,7 @@ impl AioCb { a.aio_reqprio = prio; a.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); AioCb { - aiocb: LibcAiocb(a), + aiocb: LibcAiocb(a), in_progress: false, } } @@ -432,7 +431,7 @@ macro_rules! aio_methods { #[repr(transparent)] pub struct AioFsync { aiocb: AioCb, - _pin: PhantomPinned, + _pin: PhantomPinned, } impl AioFsync { @@ -546,7 +545,7 @@ impl AsRef for AioFsync { pub struct AioRead<'a> { aiocb: AioCb, _data: PhantomData<&'a [u8]>, - _pin: PhantomPinned, + _pin: PhantomPinned, } impl<'a> AioRead<'a> { @@ -667,7 +666,7 @@ impl<'a> AsRef for AioRead<'a> { pub struct AioReadv<'a> { aiocb: AioCb, _data: PhantomData<&'a [&'a [u8]]>, - _pin: PhantomPinned, + _pin: PhantomPinned, } #[cfg(target_os = "freebsd")] @@ -778,7 +777,7 @@ impl<'a> AsRef for AioReadv<'a> { pub struct AioWrite<'a> { aiocb: AioCb, _data: PhantomData<&'a [u8]>, - _pin: PhantomPinned, + _pin: PhantomPinned, } impl<'a> AioWrite<'a> { @@ -896,7 +895,7 @@ impl<'a> AsRef for AioWrite<'a> { pub struct AioWritev<'a> { aiocb: AioCb, _data: PhantomData<&'a [&'a [u8]]>, - _pin: PhantomPinned, + _pin: PhantomPinned, } #[cfg(target_os = "freebsd")] @@ -1053,8 +1052,7 @@ pub fn aio_suspend( timeout: Option, ) -> Result<()> { let p = list as *const [&dyn AsRef] - as *const [*const libc::aiocb] - as *const *const libc::aiocb; + as *const [*const libc::aiocb] as *const *const libc::aiocb; let timep = match timeout { None => ptr::null::(), Some(x) => x.as_ref() as *const libc::timespec, @@ -1180,8 +1178,7 @@ pub fn lio_listio( sigev_notify: SigevNotify, ) -> Result<()> { let p = list as *mut [Pin<&mut dyn AsMut>] - as *mut [*mut libc::aiocb] - as *mut *mut libc::aiocb; + as *mut [*mut libc::aiocb] as *mut *mut libc::aiocb; let sigev = SigEvent::new(sigev_notify); let sigevp = &mut sigev.sigevent() as *mut libc::sigevent; Errno::result(unsafe { diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 8141ff5cb3..58def2e788 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -1,9 +1,9 @@ -use crate::Result; use crate::errno::Errno; +use crate::Result; use libc::{self, c_int}; +use std::mem; use std::os::unix::io::RawFd; use std::ptr; -use std::mem; libc_bitflags!( pub struct EpollFlags: c_int { @@ -35,7 +35,7 @@ pub enum EpollOp { EpollCtlMod = libc::EPOLL_CTL_MOD, } -libc_bitflags!{ +libc_bitflags! { pub struct EpollCreateFlags: c_int { EPOLL_CLOEXEC; } @@ -49,7 +49,12 @@ pub struct EpollEvent { impl EpollEvent { pub fn new(events: EpollFlags, data: u64) -> Self { - EpollEvent { event: libc::epoll_event { events: events.bits() as u32, u64: data } } + EpollEvent { + event: libc::epoll_event { + events: events.bits() as u32, + u64: data, + }, + } } pub fn empty() -> Self { @@ -80,8 +85,14 @@ pub fn epoll_create1(flags: EpollCreateFlags) -> Result { } #[inline] -pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result<()> - where T: Into> +pub fn epoll_ctl<'a, T>( + epfd: RawFd, + op: EpollOp, + fd: RawFd, + event: T, +) -> Result<()> +where + T: Into>, { let mut event: Option<&mut EpollEvent> = event.into(); if event.is_none() && op != EpollOp::EpollCtlDel { @@ -99,9 +110,18 @@ pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result } #[inline] -pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result { +pub fn epoll_wait( + epfd: RawFd, + events: &mut [EpollEvent], + timeout_ms: isize, +) -> Result { let res = unsafe { - libc::epoll_wait(epfd, events.as_mut_ptr() as *mut libc::epoll_event, events.len() as c_int, timeout_ms as c_int) + libc::epoll_wait( + epfd, + events.as_mut_ptr() as *mut libc::epoll_event, + events.len() as c_int, + timeout_ms as c_int, + ) }; Errno::result(res).map(|r| r as usize) diff --git a/src/sys/event.rs b/src/sys/event.rs index 0d0d23a48f..d8ad628ea2 100644 --- a/src/sys/event.rs +++ b/src/sys/event.rs @@ -3,9 +3,9 @@ use crate::{Errno, Result}; #[cfg(not(target_os = "netbsd"))] -use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t}; +use libc::{c_int, c_long, intptr_t, time_t, timespec, uintptr_t}; #[cfg(target_os = "netbsd")] -use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t}; +use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t}; use std::convert::TryInto; use std::mem; use std::os::unix::io::RawFd; @@ -18,9 +18,13 @@ pub struct KEvent { kevent: libc::kevent, } -#[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", - target_os = "openbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] type type_of_udata = *mut libc::c_void; #[cfg(any(target_os = "netbsd"))] type type_of_udata = intptr_t; @@ -75,13 +79,17 @@ libc_enum! { impl TryFrom } -#[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "macos", - target_os = "openbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] pub type type_of_event_flag = u16; #[cfg(any(target_os = "netbsd"))] pub type type_of_event_flag = u32; -libc_bitflags!{ +libc_bitflags! { pub struct EventFlag: type_of_event_flag { EV_ADD; EV_CLEAR; @@ -205,27 +213,33 @@ pub fn kqueue() -> Result { Errno::result(res) } - // KEvent can't derive Send because on some operating systems, udata is defined // as a void*. However, KEvent's public API always treats udata as an intptr_t, // which is safe to Send. -unsafe impl Send for KEvent { -} +unsafe impl Send for KEvent {} impl KEvent { - #[allow(clippy::needless_update)] // Not needless on all platforms. - pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag, - fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent { - KEvent { kevent: libc::kevent { - ident, - filter: filter as type_of_event_filter, - flags: flags.bits(), - fflags: fflags.bits(), - // data can be either i64 or intptr_t, depending on platform - data: data as _, - udata: udata as type_of_udata, - .. unsafe { mem::zeroed() } - } } + #[allow(clippy::needless_update)] // Not needless on all platforms. + pub fn new( + ident: uintptr_t, + filter: EventFilter, + flags: EventFlag, + fflags: FilterFlag, + data: intptr_t, + udata: intptr_t, + ) -> KEvent { + KEvent { + kevent: libc::kevent { + ident, + filter: filter as type_of_event_filter, + flags: flags.bits(), + fflags: fflags.bits(), + // data can be either i64 or intptr_t, depending on platform + data: data as _, + udata: udata as type_of_udata, + ..unsafe { mem::zeroed() } + }, + } } pub fn ident(&self) -> uintptr_t { @@ -253,34 +267,38 @@ impl KEvent { } } -pub fn kevent(kq: RawFd, - changelist: &[KEvent], - eventlist: &mut [KEvent], - timeout_ms: usize) -> Result { - +pub fn kevent( + kq: RawFd, + changelist: &[KEvent], + eventlist: &mut [KEvent], + timeout_ms: usize, +) -> Result { // Convert ms to timespec let timeout = timespec { tv_sec: (timeout_ms / 1000) as time_t, - tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long + tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long, }; kevent_ts(kq, changelist, eventlist, Some(timeout)) } -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd"))] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd" +))] type type_of_nchanges = c_int; #[cfg(target_os = "netbsd")] type type_of_nchanges = size_t; -pub fn kevent_ts(kq: RawFd, - changelist: &[KEvent], - eventlist: &mut [KEvent], - timeout_opt: Option) -> Result { - +pub fn kevent_ts( + kq: RawFd, + changelist: &[KEvent], + eventlist: &mut [KEvent], + timeout_opt: Option, +) -> Result { let res = unsafe { libc::kevent( kq, @@ -288,40 +306,48 @@ pub fn kevent_ts(kq: RawFd, changelist.len() as type_of_nchanges, eventlist.as_mut_ptr() as *mut libc::kevent, eventlist.len() as type_of_nchanges, - if let Some(ref timeout) = timeout_opt {timeout as *const timespec} else {ptr::null()}) + if let Some(ref timeout) = timeout_opt { + timeout as *const timespec + } else { + ptr::null() + }, + ) }; Errno::result(res).map(|r| r as usize) } #[inline] -pub fn ev_set(ev: &mut KEvent, - ident: usize, - filter: EventFilter, - flags: EventFlag, - fflags: FilterFlag, - udata: intptr_t) { - - ev.kevent.ident = ident as uintptr_t; +pub fn ev_set( + ev: &mut KEvent, + ident: usize, + filter: EventFilter, + flags: EventFlag, + fflags: FilterFlag, + udata: intptr_t, +) { + ev.kevent.ident = ident as uintptr_t; ev.kevent.filter = filter as type_of_event_filter; - ev.kevent.flags = flags.bits(); + ev.kevent.flags = flags.bits(); ev.kevent.fflags = fflags.bits(); - ev.kevent.data = 0; - ev.kevent.udata = udata as type_of_udata; + ev.kevent.data = 0; + ev.kevent.udata = udata as type_of_udata; } #[test] fn test_struct_kevent() { use std::mem; - let udata : intptr_t = 12345; + let udata: intptr_t = 12345; - let actual = KEvent::new(0xdead_beef, - EventFilter::EVFILT_READ, - EventFlag::EV_ONESHOT | EventFlag::EV_ADD, - FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, - 0x1337, - udata); + let actual = KEvent::new( + 0xdead_beef, + EventFilter::EVFILT_READ, + EventFlag::EV_ONESHOT | EventFlag::EV_ADD, + FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, + 0x1337, + udata, + ); assert_eq!(0xdead_beef, actual.ident()); let filter = actual.kevent.filter; assert_eq!(libc::EVFILT_READ, filter); @@ -334,13 +360,15 @@ fn test_struct_kevent() { #[test] fn test_kevent_filter() { - let udata : intptr_t = 12345; + let udata: intptr_t = 12345; - let actual = KEvent::new(0xdead_beef, - EventFilter::EVFILT_READ, - EventFlag::EV_ONESHOT | EventFlag::EV_ADD, - FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, - 0x1337, - udata); + let actual = KEvent::new( + 0xdead_beef, + EventFilter::EVFILT_READ, + EventFlag::EV_ONESHOT | EventFlag::EV_ADD, + FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT, + 0x1337, + udata, + ); assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap()); } diff --git a/src/sys/eventfd.rs b/src/sys/eventfd.rs index c54f952f09..cd906720cd 100644 --- a/src/sys/eventfd.rs +++ b/src/sys/eventfd.rs @@ -1,6 +1,6 @@ -use std::os::unix::io::RawFd; -use crate::Result; use crate::errno::Errno; +use crate::Result; +use std::os::unix::io::RawFd; libc_bitflags! { pub struct EfdFlags: libc::c_int { diff --git a/src/sys/inotify.rs b/src/sys/inotify.rs index b19dbe12dd..84356ec70f 100644 --- a/src/sys/inotify.rs +++ b/src/sys/inotify.rs @@ -23,20 +23,17 @@ //! } //! ``` -use libc::{ - c_char, - c_int, -}; -use std::ffi::{OsString,OsStr,CStr}; -use std::os::unix::ffi::OsStrExt; -use std::mem::{MaybeUninit, size_of}; -use std::os::unix::io::{RawFd,AsRawFd,FromRawFd}; -use std::ptr; +use crate::errno::Errno; use crate::unistd::read; -use crate::Result; use crate::NixPath; -use crate::errno::Errno; +use crate::Result; use cfg_if::cfg_if; +use libc::{c_char, c_int}; +use std::ffi::{CStr, OsStr, OsString}; +use std::mem::{size_of, MaybeUninit}; +use std::os::unix::ffi::OsStrExt; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::ptr; libc_bitflags! { /// Configuration options for [`inotify_add_watch`](fn.inotify_add_watch.html). @@ -106,7 +103,7 @@ libc_bitflags! { /// other interfaces consuming file descriptors, epoll for example. #[derive(Debug, Clone, Copy)] pub struct Inotify { - fd: RawFd + fd: RawFd, } /// This object is returned when you create a new watch on an inotify instance. @@ -114,7 +111,7 @@ pub struct Inotify { /// know which watch triggered which event. #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct WatchDescriptor { - wd: i32 + wd: i32, } /// A single inotify event. @@ -134,7 +131,7 @@ pub struct InotifyEvent { pub cookie: u32, /// Filename. This field exists only if the event was triggered for a file /// inside the watched directory. - pub name: Option + pub name: Option, } impl Inotify { @@ -144,9 +141,7 @@ impl Inotify { /// /// For more information see, [inotify_init(2)](https://man7.org/linux/man-pages/man2/inotify_init.2.html). pub fn init(flags: InitFlags) -> Result { - let res = Errno::result(unsafe { - libc::inotify_init1(flags.bits()) - }); + let res = Errno::result(unsafe { libc::inotify_init1(flags.bits()) }); res.map(|fd| Inotify { fd }) } @@ -156,15 +151,13 @@ impl Inotify { /// Returns a watch descriptor. This is not a File Descriptor! /// /// For more information see, [inotify_add_watch(2)](https://man7.org/linux/man-pages/man2/inotify_add_watch.2.html). - pub fn add_watch(self, - path: &P, - mask: AddWatchFlags) - -> Result - { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits()) - } + pub fn add_watch( + self, + path: &P, + mask: AddWatchFlags, + ) -> Result { + let res = path.with_nix_path(|cstr| unsafe { + libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits()) })?; Errno::result(res).map(|wd| WatchDescriptor { wd }) @@ -210,7 +203,7 @@ impl Inotify { ptr::copy_nonoverlapping( buffer.as_ptr().add(offset), event.as_mut_ptr() as *mut u8, - (BUFSIZ - offset).min(header_size) + (BUFSIZ - offset).min(header_size), ); event.assume_init() }; @@ -219,9 +212,7 @@ impl Inotify { 0 => None, _ => { let ptr = unsafe { - buffer - .as_ptr() - .add(offset + header_size) + buffer.as_ptr().add(offset + header_size) as *const c_char }; let cstr = unsafe { CStr::from_ptr(ptr) }; @@ -234,7 +225,7 @@ impl Inotify { wd: WatchDescriptor { wd: event.wd }, mask: AddWatchFlags::from_bits_truncate(event.mask), cookie: event.cookie, - name + name, }); offset += header_size + event.len as usize; diff --git a/src/sys/memfd.rs b/src/sys/memfd.rs index 9f08dbb2bf..ad9345e89d 100644 --- a/src/sys/memfd.rs +++ b/src/sys/memfd.rs @@ -1,10 +1,10 @@ //! Interfaces for managing memory-backed files. -use std::os::unix::io::RawFd; use cfg_if::cfg_if; +use std::os::unix::io::RawFd; -use crate::Result; use crate::errno::Errno; +use crate::Result; use std::ffi::CStr; libc_bitflags!( diff --git a/src/sys/mman.rs b/src/sys/mman.rs index 700e231c62..869f44c4b7 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -1,16 +1,16 @@ //! Memory management declarations. -use crate::Result; +use crate::errno::Errno; #[cfg(not(target_os = "android"))] use crate::NixPath; -use crate::errno::Errno; +use crate::Result; #[cfg(not(target_os = "android"))] #[cfg(feature = "fs")] use crate::{fcntl::OFlag, sys::stat::Mode}; -use libc::{self, c_int, c_void, size_t, off_t}; +use libc::{self, c_int, c_void, off_t, size_t}; use std::os::unix::io::RawFd; -libc_bitflags!{ +libc_bitflags! { /// Desired memory protection of a memory mapping. pub struct ProtFlags: c_int { /// Pages cannot be accessed. @@ -32,7 +32,7 @@ libc_bitflags!{ } } -libc_bitflags!{ +libc_bitflags! { /// Additional parameters for [`mmap`]. pub struct MapFlags: c_int { /// Compatibility flag. Ignored. @@ -188,7 +188,7 @@ libc_bitflags!{ } #[cfg(any(target_os = "linux", target_os = "netbsd"))] -libc_bitflags!{ +libc_bitflags! { /// Options for [`mremap`]. pub struct MRemapFlags: c_int { /// Permit the kernel to relocate the mapping to a new virtual address, if necessary. @@ -210,7 +210,7 @@ libc_bitflags!{ } } -libc_enum!{ +libc_enum! { /// Usage information for a range of memory to allow for performance optimizations by the kernel. /// /// Used by [`madvise`]. @@ -331,7 +331,7 @@ libc_enum!{ } } -libc_bitflags!{ +libc_bitflags! { /// Configuration flags for [`msync`]. pub struct MsFlags: c_int { /// Schedule an update but return immediately. @@ -352,7 +352,7 @@ libc_bitflags!{ } #[cfg(not(target_os = "haiku"))] -libc_bitflags!{ +libc_bitflags! { /// Flags for [`mlockall`]. pub struct MlockAllFlags: c_int { /// Lock pages that are currently mapped into the address space of the process. @@ -416,7 +416,14 @@ pub fn munlockall() -> Result<()> { /// See the [`mmap(2)`] man page for detailed requirements. /// /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html -pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> { +pub unsafe fn mmap( + addr: *mut c_void, + length: size_t, + prot: ProtFlags, + flags: MapFlags, + fd: RawFd, + offset: off_t, +) -> Result<*mut c_void> { let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset); if ret == libc::MAP_FAILED { @@ -439,10 +446,16 @@ pub unsafe fn mremap( old_size: size_t, new_size: size_t, flags: MRemapFlags, - new_address: Option<* mut c_void>, + new_address: Option<*mut c_void>, ) -> Result<*mut c_void> { #[cfg(target_os = "linux")] - let ret = libc::mremap(addr, old_size, new_size, flags.bits(), new_address.unwrap_or(std::ptr::null_mut())); + let ret = libc::mremap( + addr, + old_size, + new_size, + flags.bits(), + new_address.unwrap_or(std::ptr::null_mut()), + ); #[cfg(target_os = "netbsd")] let ret = libc::mremap( addr, @@ -450,7 +463,7 @@ pub unsafe fn mremap( new_address.unwrap_or(std::ptr::null_mut()), new_size, flags.bits(), - ); + ); if ret == libc::MAP_FAILED { Err(Errno::last()) @@ -479,7 +492,11 @@ pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> { /// [`MmapAdvise::MADV_FREE`]. /// /// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html -pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> Result<()> { +pub unsafe fn madvise( + addr: *mut c_void, + length: size_t, + advise: MmapAdvise, +) -> Result<()> { Errno::result(libc::madvise(addr, length, advise as i32)).map(drop) } @@ -508,7 +525,11 @@ pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> /// slice[0] = 0xFF; /// assert_eq!(slice[0], 0xFF); /// ``` -pub unsafe fn mprotect(addr: *mut c_void, length: size_t, prot: ProtFlags) -> Result<()> { +pub unsafe fn mprotect( + addr: *mut c_void, + length: size_t, + prot: ProtFlags, +) -> Result<()> { Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop) } @@ -520,7 +541,11 @@ pub unsafe fn mprotect(addr: *mut c_void, length: size_t, prot: ProtFlags) -> Re /// page. /// /// [`msync(2)`]: https://man7.org/linux/man-pages/man2/msync.2.html -pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()> { +pub unsafe fn msync( + addr: *mut c_void, + length: size_t, + flags: MsFlags, +) -> Result<()> { Errno::result(libc::msync(addr, length, flags.bits())).map(drop) } @@ -561,9 +586,8 @@ pub fn shm_open

( /// [`shm_unlink(3)`]: https://man7.org/linux/man-pages/man3/shm_unlink.3.html #[cfg(not(target_os = "android"))] pub fn shm_unlink(name: &P) -> Result<()> { - let ret = name.with_nix_path(|cstr| { - unsafe { libc::shm_unlink(cstr.as_ptr()) } - })?; + let ret = + name.with_nix_path(|cstr| unsafe { libc::shm_unlink(cstr.as_ptr()) })?; Errno::result(ret).map(drop) } diff --git a/src/sys/personality.rs b/src/sys/personality.rs index 9e285ae6e0..f295a05fad 100644 --- a/src/sys/personality.rs +++ b/src/sys/personality.rs @@ -1,6 +1,6 @@ //! Process execution domains -use crate::Result; use crate::errno::Errno; +use crate::Result; use libc::{self, c_int, c_ulong}; @@ -62,9 +62,7 @@ libc_bitflags! { /// assert!(!pers.contains(Persona::WHOLE_SECONDS)); /// ``` pub fn get() -> Result { - let res = unsafe { - libc::personality(0xFFFFFFFF) - }; + let res = unsafe { libc::personality(0xFFFFFFFF) }; Errno::result(res).map(Persona::from_bits_truncate) } @@ -89,9 +87,7 @@ pub fn get() -> Result { /// personality::set(pers | Persona::ADDR_NO_RANDOMIZE).unwrap(); /// ``` pub fn set(persona: Persona) -> Result { - let res = unsafe { - libc::personality(persona.bits() as c_ulong) - }; + let res = unsafe { libc::personality(persona.bits() as c_ulong) }; Errno::result(res).map(Persona::from_bits_truncate) } diff --git a/src/sys/ptrace/bsd.rs b/src/sys/ptrace/bsd.rs index c4cc740396..ba267c6577 100644 --- a/src/sys/ptrace/bsd.rs +++ b/src/sys/ptrace/bsd.rs @@ -1,16 +1,16 @@ -use cfg_if::cfg_if; use crate::errno::Errno; -use libc::{self, c_int}; -use std::ptr; use crate::sys::signal::Signal; use crate::unistd::Pid; use crate::Result; +use cfg_if::cfg_if; +use libc::{self, c_int}; +use std::ptr; pub type RequestType = c_int; cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", target_os = "macos", target_os = "openbsd"))] { #[doc(hidden)] @@ -71,7 +71,8 @@ unsafe fn ptrace_other( libc::pid_t::from(pid), addr, data, - )).map(|_| 0) + )) + .map(|_| 0) } /// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)` @@ -79,14 +80,19 @@ unsafe fn ptrace_other( /// Indicates that this process is to be traced by its parent. /// This is the only ptrace request to be issued by the tracee. pub fn traceme() -> Result<()> { - unsafe { ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0).map(drop) } + unsafe { + ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0) + .map(drop) + } } /// Attach to a running process, as with `ptrace(PT_ATTACH, ...)` /// /// Attaches to the process specified by `pid`, making it a tracee of the calling process. pub fn attach(pid: Pid) -> Result<()> { - unsafe { ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) } + unsafe { + ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) + } } /// Detaches the current running process, as with `ptrace(PT_DETACH, ...)` @@ -114,13 +120,14 @@ pub fn cont>>(pid: Pid, sig: T) -> Result<()> { }; unsafe { // Ignore the useless return value - ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data).map(drop) + ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data) + .map(drop) } } /// Issues a kill request as with `ptrace(PT_KILL, ...)` /// -/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);` +/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);` pub fn kill(pid: Pid) -> Result<()> { unsafe { ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(drop) @@ -149,21 +156,22 @@ pub fn kill(pid: Pid) -> Result<()> { /// _ => {}, /// } /// ``` -#[cfg( - any( - any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"), - all(target_os = "openbsd", target_arch = "x86_64"), - all(target_os = "netbsd", - any(target_arch = "x86_64", target_arch = "powerpc") - ) +#[cfg(any( + any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"), + all(target_os = "openbsd", target_arch = "x86_64"), + all( + target_os = "netbsd", + any(target_arch = "x86_64", target_arch = "powerpc") ) -)] +))] pub fn step>>(pid: Pid, sig: T) -> Result<()> { let data = match sig.into() { Some(s) => s as c_int, None => 0, }; - unsafe { ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) } + unsafe { + ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) + } } /// Reads a word from a processes memory at the given address diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs index 1d9b241c1f..9687e05d42 100644 --- a/src/sys/ptrace/linux.rs +++ b/src/sys/ptrace/linux.rs @@ -1,20 +1,24 @@ //! For detailed description of the ptrace requests, consult `man ptrace`. -use cfg_if::cfg_if; -use std::{mem, ptr}; -use crate::Result; use crate::errno::Errno; -use libc::{self, c_void, c_long, siginfo_t}; -use crate::unistd::Pid; use crate::sys::signal::Signal; +use crate::unistd::Pid; +use crate::Result; +use cfg_if::cfg_if; +use libc::{self, c_long, c_void, siginfo_t}; +use std::{mem, ptr}; pub type AddressType = *mut ::libc::c_void; #[cfg(all( target_os = "linux", - any(all(target_arch = "x86_64", - any(target_env = "gnu", target_env = "musl")), - all(target_arch = "x86", target_env = "gnu")) + any( + all( + target_arch = "x86_64", + any(target_env = "gnu", target_env = "musl") + ), + all(target_arch = "x86", target_env = "gnu") + ) ))] use libc::user_regs_struct; @@ -30,7 +34,7 @@ cfg_if! { } } -libc_enum!{ +libc_enum! { #[cfg_attr(not(any(target_env = "musl", target_env = "uclibc", target_os = "android")), repr(u32))] #[cfg_attr(any(target_env = "musl", target_env = "uclibc", target_os = "android"), repr(i32))] /// Ptrace Request enum defining the action to be taken. @@ -120,7 +124,7 @@ libc_enum!{ } } -libc_enum!{ +libc_enum! { #[repr(i32)] /// Using the ptrace options the tracer can configure the tracee to stop /// at certain events. This enum is used to define those events as defined @@ -178,7 +182,12 @@ libc_bitflags! { } } -fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result { +fn ptrace_peek( + request: Request, + pid: Pid, + addr: AddressType, + data: *mut c_void, +) -> Result { let ret = unsafe { Errno::clear(); libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data) @@ -192,9 +201,13 @@ fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) /// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)` #[cfg(all( target_os = "linux", - any(all(target_arch = "x86_64", - any(target_env = "gnu", target_env = "musl")), - all(target_arch = "x86", target_env = "gnu")) + any( + all( + target_arch = "x86_64", + any(target_env = "gnu", target_env = "musl") + ), + all(target_arch = "x86", target_env = "gnu") + ) ))] pub fn getregs(pid: Pid) -> Result { ptrace_get_data::(Request::PTRACE_GETREGS, pid) @@ -203,16 +216,22 @@ pub fn getregs(pid: Pid) -> Result { /// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)` #[cfg(all( target_os = "linux", - any(all(target_arch = "x86_64", - any(target_env = "gnu", target_env = "musl")), - all(target_arch = "x86", target_env = "gnu")) + any( + all( + target_arch = "x86_64", + any(target_env = "gnu", target_env = "musl") + ), + all(target_arch = "x86", target_env = "gnu") + ) ))] pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> { let res = unsafe { - libc::ptrace(Request::PTRACE_SETREGS as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::(), - ®s as *const _ as *const c_void) + libc::ptrace( + Request::PTRACE_SETREGS as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::(), + ®s as *const _ as *const c_void, + ) }; Errno::result(res).map(drop) } @@ -224,26 +243,41 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> { fn ptrace_get_data(request: Request, pid: Pid) -> Result { let mut data = mem::MaybeUninit::uninit(); let res = unsafe { - libc::ptrace(request as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::(), - data.as_mut_ptr() as *const _ as *const c_void) + libc::ptrace( + request as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::(), + data.as_mut_ptr() as *const _ as *const c_void, + ) }; Errno::result(res)?; - Ok(unsafe{ data.assume_init() }) + Ok(unsafe { data.assume_init() }) } -unsafe fn ptrace_other(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result { - Errno::result(libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)).map(|_| 0) +unsafe fn ptrace_other( + request: Request, + pid: Pid, + addr: AddressType, + data: *mut c_void, +) -> Result { + Errno::result(libc::ptrace( + request as RequestType, + libc::pid_t::from(pid), + addr, + data, + )) + .map(|_| 0) } /// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`. pub fn setoptions(pid: Pid, options: Options) -> Result<()> { let res = unsafe { - libc::ptrace(Request::PTRACE_SETOPTIONS as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::(), - options.bits() as *mut c_void) + libc::ptrace( + Request::PTRACE_SETOPTIONS as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::(), + options.bits() as *mut c_void, + ) }; Errno::result(res).map(drop) } @@ -260,12 +294,14 @@ pub fn getsiginfo(pid: Pid) -> Result { /// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)` pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { - let ret = unsafe{ + let ret = unsafe { Errno::clear(); - libc::ptrace(Request::PTRACE_SETSIGINFO as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::(), - sig as *const _ as *const c_void) + libc::ptrace( + Request::PTRACE_SETSIGINFO as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::(), + sig as *const _ as *const c_void, + ) }; match Errno::result(ret) { Ok(_) => Ok(()), @@ -284,7 +320,8 @@ pub fn traceme() -> Result<()> { Pid::from_raw(0), ptr::null_mut(), ptr::null_mut(), - ).map(drop) // ignore the useless return value + ) + .map(drop) // ignore the useless return value } } @@ -298,12 +335,8 @@ pub fn syscall>>(pid: Pid, sig: T) -> Result<()> { None => ptr::null_mut(), }; unsafe { - ptrace_other( - Request::PTRACE_SYSCALL, - pid, - ptr::null_mut(), - data, - ).map(drop) // ignore the useless return value + ptrace_other(Request::PTRACE_SYSCALL, pid, ptr::null_mut(), data) + .map(drop) // ignore the useless return value } } @@ -312,14 +345,19 @@ pub fn syscall>>(pid: Pid, sig: T) -> Result<()> { /// In contrast to the `syscall` function, the syscall stopped at will not be executed. /// Thus the the tracee will only be stopped once per syscall, /// optionally delivering a signal specified by `sig`. -#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))] +#[cfg(all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "x86", target_arch = "x86_64") +))] pub fn sysemu>>(pid: Pid, sig: T) -> Result<()> { let data = match sig.into() { Some(s) => s as i32 as *mut c_void, None => ptr::null_mut(), }; unsafe { - ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data).map(drop) + ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data) + .map(drop) // ignore the useless return value } } @@ -334,7 +372,8 @@ pub fn attach(pid: Pid) -> Result<()> { pid, ptr::null_mut(), ptr::null_mut(), - ).map(drop) // ignore the useless return value + ) + .map(drop) // ignore the useless return value } } @@ -350,7 +389,8 @@ pub fn seize(pid: Pid, options: Options) -> Result<()> { pid, ptr::null_mut(), options.bits() as *mut c_void, - ).map(drop) // ignore the useless return value + ) + .map(drop) // ignore the useless return value } } @@ -364,12 +404,8 @@ pub fn detach>>(pid: Pid, sig: T) -> Result<()> { None => ptr::null_mut(), }; unsafe { - ptrace_other( - Request::PTRACE_DETACH, - pid, - ptr::null_mut(), - data - ).map(drop) + ptrace_other(Request::PTRACE_DETACH, pid, ptr::null_mut(), data) + .map(drop) } } @@ -383,7 +419,8 @@ pub fn cont>>(pid: Pid, sig: T) -> Result<()> { None => ptr::null_mut(), }; unsafe { - ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) // ignore the useless return value + ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) + // ignore the useless return value } } @@ -394,7 +431,13 @@ pub fn cont>>(pid: Pid, sig: T) -> Result<()> { #[cfg_attr(docsrs, doc(cfg(all())))] pub fn interrupt(pid: Pid) -> Result<()> { unsafe { - ptrace_other(Request::PTRACE_INTERRUPT, pid, ptr::null_mut(), ptr::null_mut()).map(drop) + ptrace_other( + Request::PTRACE_INTERRUPT, + pid, + ptr::null_mut(), + ptr::null_mut(), + ) + .map(drop) } } @@ -403,7 +446,13 @@ pub fn interrupt(pid: Pid) -> Result<()> { /// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);` pub fn kill(pid: Pid) -> Result<()> { unsafe { - ptrace_other(Request::PTRACE_KILL, pid, ptr::null_mut(), ptr::null_mut()).map(drop) + ptrace_other( + Request::PTRACE_KILL, + pid, + ptr::null_mut(), + ptr::null_mut(), + ) + .map(drop) } } @@ -436,7 +485,8 @@ pub fn step>>(pid: Pid, sig: T) -> Result<()> { None => ptr::null_mut(), }; unsafe { - ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data).map(drop) + ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data) + .map(drop) } } @@ -446,7 +496,11 @@ pub fn step>>(pid: Pid, sig: T) -> Result<()> { /// Advances the execution by a single step or until the next syscall. /// In case the tracee is stopped at a syscall, the syscall will not be executed. /// Optionally, the signal specified by `sig` is delivered to the tracee upon continuation. -#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))] +#[cfg(all( + target_os = "linux", + target_env = "gnu", + any(target_arch = "x86", target_arch = "x86_64") +))] pub fn sysemu_step>>(pid: Pid, sig: T) -> Result<()> { let data = match sig.into() { Some(s) => s as i32 as *mut c_void, @@ -477,8 +531,8 @@ pub fn read(pid: Pid, addr: AddressType) -> Result { pub unsafe fn write( pid: Pid, addr: AddressType, - data: *mut c_void) -> Result<()> -{ + data: *mut c_void, +) -> Result<()> { ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) } @@ -498,7 +552,7 @@ pub fn read_user(pid: Pid, offset: AddressType) -> Result { pub unsafe fn write_user( pid: Pid, offset: AddressType, - data: *mut c_void) -> Result<()> -{ + data: *mut c_void, +) -> Result<()> { ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop) } diff --git a/src/sys/ptrace/mod.rs b/src/sys/ptrace/mod.rs index 782c30409b..2b121c0b4d 100644 --- a/src/sys/ptrace/mod.rs +++ b/src/sys/ptrace/mod.rs @@ -1,4 +1,4 @@ -///! Provides helpers for making ptrace system calls +///! Provides helpers for making ptrace system calls #[cfg(any(target_os = "android", target_os = "linux"))] mod linux; @@ -6,17 +6,20 @@ mod linux; #[cfg(any(target_os = "android", target_os = "linux"))] pub use self::linux::*; -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] mod bsd; -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] pub use self::bsd::*; diff --git a/src/sys/quota.rs b/src/sys/quota.rs index f3b4c02dee..b3c44ca705 100644 --- a/src/sys/quota.rs +++ b/src/sys/quota.rs @@ -12,11 +12,11 @@ //! dqblk.set_blocks_soft_limit(8000); //! quotactl_set(QuotaType::USRQUOTA, "/dev/sda1", 50, &dqblk, QuotaValidFlags::QIF_BLIMITS).unwrap(); //! ``` +use crate::errno::Errno; +use crate::{NixPath, Result}; +use libc::{self, c_char, c_int}; use std::default::Default; use std::{mem, ptr}; -use libc::{self, c_int, c_char}; -use crate::{Result, NixPath}; -use crate::errno::Errno; struct QuotaCmd(QuotaSubCmd, QuotaType); @@ -28,7 +28,7 @@ impl QuotaCmd { } // linux quota version >= 2 -libc_enum!{ +libc_enum! { #[repr(i32)] enum QuotaSubCmd { Q_SYNC, @@ -39,7 +39,7 @@ libc_enum!{ } } -libc_enum!{ +libc_enum! { /// The scope of the quota. #[repr(i32)] #[non_exhaustive] @@ -51,7 +51,7 @@ libc_enum!{ } } -libc_enum!{ +libc_enum! { /// The type of quota format to use. #[repr(i32)] #[non_exhaustive] @@ -120,7 +120,8 @@ impl Default for Dqblk { impl Dqblk { /// The absolute limit on disk quota blocks allocated. pub fn blocks_hard_limit(&self) -> Option { - let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) { Some(self.0.dqb_bhardlimit) } else { @@ -135,7 +136,8 @@ impl Dqblk { /// Preferred limit on disk quota blocks pub fn blocks_soft_limit(&self) -> Option { - let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) { Some(self.0.dqb_bsoftlimit) } else { @@ -150,7 +152,8 @@ impl Dqblk { /// Current occupied space (bytes). pub fn occupied_space(&self) -> Option { - let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); if valid_fields.contains(QuotaValidFlags::QIF_SPACE) { Some(self.0.dqb_curspace) } else { @@ -160,7 +163,8 @@ impl Dqblk { /// Maximum number of allocated inodes. pub fn inodes_hard_limit(&self) -> Option { - let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) { Some(self.0.dqb_ihardlimit) } else { @@ -175,7 +179,8 @@ impl Dqblk { /// Preferred inode limit pub fn inodes_soft_limit(&self) -> Option { - let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) { Some(self.0.dqb_isoftlimit) } else { @@ -190,7 +195,8 @@ impl Dqblk { /// Current number of allocated inodes. pub fn allocated_inodes(&self) -> Option { - let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); if valid_fields.contains(QuotaValidFlags::QIF_INODES) { Some(self.0.dqb_curinodes) } else { @@ -200,7 +206,8 @@ impl Dqblk { /// Time limit for excessive disk use. pub fn block_time_limit(&self) -> Option { - let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); if valid_fields.contains(QuotaValidFlags::QIF_BTIME) { Some(self.0.dqb_btime) } else { @@ -215,7 +222,8 @@ impl Dqblk { /// Time limit for excessive files. pub fn inode_time_limit(&self) -> Option { - let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); + let valid_fields = + QuotaValidFlags::from_bits_truncate(self.0.dqb_valid); if valid_fields.contains(QuotaValidFlags::QIF_ITIME) { Some(self.0.dqb_itime) } else { @@ -229,11 +237,18 @@ impl Dqblk { } } -fn quotactl(cmd: QuotaCmd, special: Option<&P>, id: c_int, addr: *mut c_char) -> Result<()> { +fn quotactl( + cmd: QuotaCmd, + special: Option<&P>, + id: c_int, + addr: *mut c_char, +) -> Result<()> { unsafe { Errno::clear(); let res = match special { - Some(dev) => dev.with_nix_path(|path| libc::quotactl(cmd.as_int(), path.as_ptr(), id, addr)), + Some(dev) => dev.with_nix_path(|path| { + libc::quotactl(cmd.as_int(), path.as_ptr(), id, addr) + }), None => Ok(libc::quotactl(cmd.as_int(), ptr::null(), id, addr)), }?; @@ -242,36 +257,82 @@ fn quotactl(cmd: QuotaCmd, special: Option<&P>, id: c_int, } /// Turn on disk quotas for a block device. -pub fn quotactl_on(which: QuotaType, special: &P, format: QuotaFmt, quota_file: &P) -> Result<()> { +pub fn quotactl_on( + which: QuotaType, + special: &P, + format: QuotaFmt, + quota_file: &P, +) -> Result<()> { quota_file.with_nix_path(|path| { let mut path_copy = path.to_bytes_with_nul().to_owned(); let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char; - quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), Some(special), format as c_int, p) + quotactl( + QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), + Some(special), + format as c_int, + p, + ) })? } /// Disable disk quotas for a block device. -pub fn quotactl_off(which: QuotaType, special: &P) -> Result<()> { - quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which), Some(special), 0, ptr::null_mut()) +pub fn quotactl_off( + which: QuotaType, + special: &P, +) -> Result<()> { + quotactl( + QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which), + Some(special), + 0, + ptr::null_mut(), + ) } /// Update the on-disk copy of quota usages for a filesystem. /// /// If `special` is `None`, then all file systems with active quotas are sync'd. -pub fn quotactl_sync(which: QuotaType, special: Option<&P>) -> Result<()> { - quotactl(QuotaCmd(QuotaSubCmd::Q_SYNC, which), special, 0, ptr::null_mut()) +pub fn quotactl_sync( + which: QuotaType, + special: Option<&P>, +) -> Result<()> { + quotactl( + QuotaCmd(QuotaSubCmd::Q_SYNC, which), + special, + 0, + ptr::null_mut(), + ) } /// Get disk quota limits and current usage for the given user/group id. -pub fn quotactl_get(which: QuotaType, special: &P, id: c_int) -> Result { +pub fn quotactl_get( + which: QuotaType, + special: &P, + id: c_int, +) -> Result { let mut dqblk = mem::MaybeUninit::uninit(); - quotactl(QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, dqblk.as_mut_ptr() as *mut c_char)?; - Ok(unsafe{ Dqblk(dqblk.assume_init())}) + quotactl( + QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), + Some(special), + id, + dqblk.as_mut_ptr() as *mut c_char, + )?; + Ok(unsafe { Dqblk(dqblk.assume_init()) }) } /// Configure quota values for the specified fields for a given user/group id. -pub fn quotactl_set(which: QuotaType, special: &P, id: c_int, dqblk: &Dqblk, fields: QuotaValidFlags) -> Result<()> { +pub fn quotactl_set( + which: QuotaType, + special: &P, + id: c_int, + dqblk: &Dqblk, + fields: QuotaValidFlags, +) -> Result<()> { let mut dqblk_copy = *dqblk; dqblk_copy.0.dqb_valid = fields.bits(); - quotactl(QuotaCmd(QuotaSubCmd::Q_SETQUOTA, which), Some(special), id, &mut dqblk_copy as *mut _ as *mut c_char) + quotactl( + QuotaCmd(QuotaSubCmd::Q_SETQUOTA, which), + Some(special), + id, + &mut dqblk_copy as *mut _ as *mut c_char, + ) } diff --git a/src/sys/reboot.rs b/src/sys/reboot.rs index 2a8009e4f8..02d98162bd 100644 --- a/src/sys/reboot.rs +++ b/src/sys/reboot.rs @@ -1,7 +1,7 @@ //! Reboot/shutdown or enable/disable Ctrl-Alt-Delete. -use crate::Result; use crate::errno::Errno; +use crate::Result; use std::convert::Infallible; use std::mem::drop; @@ -30,9 +30,7 @@ libc_enum! { /// Reboots or shuts down the system. pub fn reboot(how: RebootMode) -> Result { - unsafe { - libc::reboot(how as libc::c_int) - }; + unsafe { libc::reboot(how as libc::c_int) }; Err(Errno::last()) } @@ -45,8 +43,6 @@ pub fn set_cad_enabled(enable: bool) -> Result<()> { } else { libc::RB_DISABLE_CAD }; - let res = unsafe { - libc::reboot(cmd) - }; + let res = unsafe { libc::reboot(cmd) }; Errno::result(res).map(drop) } diff --git a/src/sys/resource.rs b/src/sys/resource.rs index 788444d876..8927737763 100644 --- a/src/sys/resource.rs +++ b/src/sys/resource.rs @@ -245,7 +245,11 @@ pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> { /// [`Resource`]: enum.Resource.html /// /// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`. -pub fn setrlimit(resource: Resource, soft_limit: rlim_t, hard_limit: rlim_t) -> Result<()> { +pub fn setrlimit( + resource: Resource, + soft_limit: rlim_t, + hard_limit: rlim_t, +) -> Result<()> { let new_rlim = rlimit { rlim_cur: soft_limit, rlim_max: hard_limit, @@ -427,7 +431,8 @@ mod test { // thing away. Replace the assert with test::black_box once stabilized. assert_eq!(numbers[100..200].iter().sum::(), 30_100); - let usage = getrusage(UsageWho::RUSAGE_SELF).expect("Failed to call getrusage for SELF"); + let usage = getrusage(UsageWho::RUSAGE_SELF) + .expect("Failed to call getrusage for SELF"); let rusage = usage.as_ref(); let user = usage.user_time(); diff --git a/src/sys/select.rs b/src/sys/select.rs index ab4f68f537..7a94cff87e 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -1,14 +1,14 @@ //! Portably monitor a group of file descriptors for readiness. +use crate::errno::Errno; +use crate::sys::time::{TimeSpec, TimeVal}; +use crate::Result; +use libc::{self, c_int}; use std::convert::TryFrom; use std::iter::FusedIterator; use std::mem; use std::ops::Range; use std::os::unix::io::RawFd; use std::ptr::{null, null_mut}; -use libc::{self, c_int}; -use crate::Result; -use crate::errno::Errno; -use crate::sys::time::{TimeSpec, TimeVal}; pub use libc::FD_SETSIZE; @@ -173,11 +173,13 @@ impl<'a> FusedIterator for Fds<'a> {} /// [select(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html) /// /// [`FdSet::highest`]: struct.FdSet.html#method.highest -pub fn select<'a, N, R, W, E, T>(nfds: N, +pub fn select<'a, N, R, W, E, T>( + nfds: N, readfds: R, writefds: W, errorfds: E, - timeout: T) -> Result + timeout: T, +) -> Result where N: Into>, R: Into>, @@ -191,23 +193,31 @@ where let timeout = timeout.into(); let nfds = nfds.into().unwrap_or_else(|| { - readfds.iter_mut() + readfds + .iter_mut() .chain(writefds.iter_mut()) .chain(errorfds.iter_mut()) .map(|set| set.highest().unwrap_or(-1)) .max() - .unwrap_or(-1) + 1 + .unwrap_or(-1) + + 1 }); - let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); - let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); - let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); - let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval) + let readfds = readfds + .map(|set| set as *mut _ as *mut libc::fd_set) + .unwrap_or(null_mut()); + let writefds = writefds + .map(|set| set as *mut _ as *mut libc::fd_set) + .unwrap_or(null_mut()); + let errorfds = errorfds + .map(|set| set as *mut _ as *mut libc::fd_set) + .unwrap_or(null_mut()); + let timeout = timeout + .map(|tv| tv as *mut _ as *mut libc::timeval) .unwrap_or(null_mut()); - let res = unsafe { - libc::select(nfds, readfds, writefds, errorfds, timeout) - }; + let res = + unsafe { libc::select(nfds, readfds, writefds, errorfds, timeout) }; Errno::result(res) } @@ -292,9 +302,9 @@ where #[cfg(test)] mod tests { use super::*; - use std::os::unix::io::RawFd; use crate::sys::time::{TimeVal, TimeValLike}; - use crate::unistd::{write, pipe}; + use crate::unistd::{pipe, write}; + use std::os::unix::io::RawFd; #[test] fn fdset_insert() { @@ -383,11 +393,10 @@ mod tests { fd_set.insert(r2); let mut timeout = TimeVal::seconds(10); - assert_eq!(1, select(None, - &mut fd_set, - None, - None, - &mut timeout).unwrap()); + assert_eq!( + 1, + select(None, &mut fd_set, None, None, &mut timeout).unwrap() + ); assert!(fd_set.contains(r1)); assert!(!fd_set.contains(r2)); } @@ -403,11 +412,17 @@ mod tests { fd_set.insert(r2); let mut timeout = TimeVal::seconds(10); - assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1), + assert_eq!( + 1, + select( + Some(fd_set.highest().unwrap() + 1), &mut fd_set, None, None, - &mut timeout).unwrap()); + &mut timeout + ) + .unwrap() + ); assert!(fd_set.contains(r1)); assert!(!fd_set.contains(r2)); } @@ -423,11 +438,17 @@ mod tests { fd_set.insert(r2); let mut timeout = TimeVal::seconds(10); - assert_eq!(1, select(::std::cmp::max(r1, r2) + 1, + assert_eq!( + 1, + select( + ::std::cmp::max(r1, r2) + 1, &mut fd_set, None, None, - &mut timeout).unwrap()); + &mut timeout + ) + .unwrap() + ); assert!(fd_set.contains(r1)); assert!(!fd_set.contains(r2)); } diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs index 2ebcdf4889..fb293a4e74 100644 --- a/src/sys/sendfile.rs +++ b/src/sys/sendfile.rs @@ -6,8 +6,8 @@ use std::ptr; use libc::{self, off_t}; -use crate::Result; use crate::errno::Errno; +use crate::Result; /// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`. /// diff --git a/src/sys/signalfd.rs b/src/sys/signalfd.rs index 166bb9d246..095e590850 100644 --- a/src/sys/signalfd.rs +++ b/src/sys/signalfd.rs @@ -15,17 +15,16 @@ //! //! Please note that signal discarding is not specific to `signalfd`, but also happens with regular //! signal handlers. -use crate::unistd; -use crate::Result; use crate::errno::Errno; pub use crate::sys::signal::{self, SigSet}; +use crate::unistd; +use crate::Result; pub use libc::signalfd_siginfo as siginfo; -use std::os::unix::io::{RawFd, AsRawFd}; use std::mem; +use std::os::unix::io::{AsRawFd, RawFd}; - -libc_bitflags!{ +libc_bitflags! { pub struct SfdFlags: libc::c_int { SFD_NONBLOCK; SFD_CLOEXEC; @@ -49,7 +48,11 @@ pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::(); /// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html) pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result { unsafe { - Errno::result(libc::signalfd(fd as libc::c_int, mask.as_ref(), flags.bits())) + Errno::result(libc::signalfd( + fd as libc::c_int, + mask.as_ref(), + flags.bits(), + )) } } @@ -103,12 +106,13 @@ impl SignalFd { let size = mem::size_of_val(&buffer); let res = Errno::result(unsafe { libc::read(self.0, buffer.as_mut_ptr() as *mut libc::c_void, size) - }).map(|r| r as usize); + }) + .map(|r| r as usize); match res { Ok(x) if x == size => Ok(Some(unsafe { buffer.assume_init() })), Ok(_) => unreachable!("partial read on signalfd"), Err(Errno::EAGAIN) => Ok(None), - Err(error) => Err(error) + Err(error) => Err(error), } } } @@ -139,7 +143,6 @@ impl Iterator for SignalFd { } } - #[cfg(test)] mod tests { use super::*; @@ -163,7 +166,8 @@ mod tests { #[test] fn read_empty_signalfd() { let mask = SigSet::empty(); - let mut fd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); + let mut fd = + SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap(); let res = fd.read_signal(); assert!(res.unwrap().is_none()); diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 07d68e1fd0..4a16eea94e 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1,47 +1,54 @@ +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "haiku", + target_os = "fuchsia" +))] +#[cfg(feature = "net")] +pub use self::datalink::LinkAddr; +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use self::vsock::VsockAddr; use super::sa_family_t; -use cfg_if::cfg_if; -use crate::{Result, NixPath}; use crate::errno::Errno; +#[cfg(any(target_os = "android", target_os = "linux"))] +use crate::sys::socket::addr::alg::AlgAddr; +#[cfg(any(target_os = "android", target_os = "linux"))] +use crate::sys::socket::addr::netlink::NetlinkAddr; +#[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") +))] +use crate::sys::socket::addr::sys_control::SysControlAddr; +use crate::{NixPath, Result}; +use cfg_if::cfg_if; use memoffset::offset_of; -use std::{fmt, mem, net, ptr, slice}; use std::convert::TryInto; use std::ffi::OsStr; use std::hash::{Hash, Hasher}; -use std::path::Path; use std::os::unix::ffi::OsStrExt; -#[cfg(any(target_os = "android", target_os = "linux"))] -use crate::sys::socket::addr::netlink::NetlinkAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] -use crate::sys::socket::addr::alg::AlgAddr; #[cfg(any(target_os = "ios", target_os = "macos"))] use std::os::unix::io::RawFd; -#[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] -use crate::sys::socket::addr::sys_control::SysControlAddr; -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "haiku", - target_os = "fuchsia"))] -#[cfg(feature = "net")] -pub use self::datalink::LinkAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] -pub use self::vsock::VsockAddr; +use std::path::Path; +use std::{fmt, mem, net, ptr, slice}; /// Convert a std::net::Ipv4Addr into the libc form. #[cfg(feature = "net")] pub(crate) fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { let octets = addr.octets(); libc::in_addr { - s_addr: u32::to_be(((octets[0] as u32) << 24) | - ((octets[1] as u32) << 16) | - ((octets[2] as u32) << 8) | - (octets[3] as u32)) + s_addr: u32::to_be( + ((octets[0] as u32) << 24) + | ((octets[1] as u32) << 16) + | ((octets[2] as u32) << 8) + | (octets[3] as u32), + ), } } @@ -49,7 +56,7 @@ pub(crate) fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { #[cfg(feature = "net")] pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr { libc::in6_addr { - s6_addr: addr.octets() + s6_addr: addr.octets(), } } @@ -75,11 +82,13 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] Netlink = libc::AF_NETLINK, /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html)) - #[cfg(any(target_os = "android", - target_os = "linux", - target_os = "illumos", - target_os = "fuchsia", - target_os = "solaris"))] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "illumos", + target_os = "fuchsia", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Packet = libc::AF_PACKET, /// KEXT Controls and Notifications @@ -136,7 +145,7 @@ pub enum AddressFamily { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Key = libc::AF_KEY, - #[allow(missing_docs)] // Not documented anywhere that I can find + #[allow(missing_docs)] // Not documented anywhere that I can find #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Ash = libc::AF_ASH, @@ -172,7 +181,7 @@ pub enum AddressFamily { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Llc = libc::AF_LLC, - /// InfiniBand native addressing + /// InfiniBand native addressing #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] #[cfg_attr(docsrs, doc(cfg(all())))] Ib = libc::AF_IB, @@ -189,10 +198,12 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] Tipc = libc::AF_TIPC, /// Bluetooth low-level socket protocol - #[cfg(not(any(target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "solaris")))] + #[cfg(not(any( + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "solaris" + )))] #[cfg_attr(docsrs, doc(cfg(all())))] Bluetooth = libc::AF_BLUETOOTH, /// IUCV (inter-user communication vehicle) z/VM protocol for @@ -205,7 +216,11 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] RxRpc = libc::AF_RXRPC, /// New "modular ISDN" driver interface protocol - #[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "haiku")))] + #[cfg(not(any( + target_os = "illumos", + target_os = "solaris", + target_os = "haiku" + )))] #[cfg_attr(docsrs, doc(cfg(all())))] Isdn = libc::AF_ISDN, /// Nokia cellular modem IPC/RPC interface @@ -234,128 +249,156 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] Vsock = libc::AF_VSOCK, /// ARPANet IMP addresses - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] ImpLink = libc::AF_IMPLINK, /// PUP protocols, e.g. BSP - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Pup = libc::AF_PUP, /// MIT CHAOS protocols - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Chaos = libc::AF_CHAOS, /// Novell and Xerox protocol - #[cfg(any(target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Ns = libc::AF_NS, - #[allow(missing_docs)] // Not documented anywhere that I can find - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[allow(missing_docs)] // Not documented anywhere that I can find + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Iso = libc::AF_ISO, /// Bell Labs virtual circuit switch ? - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Datakit = libc::AF_DATAKIT, /// CCITT protocols, X.25 etc - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Ccitt = libc::AF_CCITT, /// DEC Direct data link interface - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Dli = libc::AF_DLI, - #[allow(missing_docs)] // Not documented anywhere that I can find - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[allow(missing_docs)] // Not documented anywhere that I can find + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Lat = libc::AF_LAT, /// NSC Hyperchannel - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Hylink = libc::AF_HYLINK, /// Link layer interface - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Link = libc::AF_LINK, /// connection-oriented IP, aka ST II - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Coip = libc::AF_COIP, /// Computer Network Technology - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Cnt = libc::AF_CNT, /// Native ATM access - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] Natm = libc::AF_NATM, /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html)) @@ -381,17 +424,19 @@ impl AddressFamily { libc::AF_SYSTEM => Some(AddressFamily::System), #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_PACKET => Some(AddressFamily::Packet), - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd" + ))] libc::AF_LINK => Some(AddressFamily::Link), #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_VSOCK => Some(AddressFamily::Vsock), - _ => None + _ => None, } } } @@ -707,12 +752,13 @@ pub struct UnixAddr { /// The length of the valid part of `sun`, including the sun_family field /// but excluding any trailing nul. // On the BSDs, this field is built into sun - #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" ))] - sun_len: u8 + sun_len: u8, } // linux man page unix(7) says there are 3 kinds of unix socket: @@ -732,17 +778,21 @@ impl<'a> UnixAddrKind<'a> { /// Safety: sun & sun_len must be valid unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self { assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path)); - let path_len = sun_len as usize - offset_of!(libc::sockaddr_un, sun_path); + let path_len = + sun_len as usize - offset_of!(libc::sockaddr_un, sun_path); if path_len == 0 { return Self::Unnamed; } #[cfg(any(target_os = "android", target_os = "linux"))] if sun.sun_path[0] == 0 { - let name = - slice::from_raw_parts(sun.sun_path.as_ptr().add(1) as *const u8, path_len - 1); + let name = slice::from_raw_parts( + sun.sun_path.as_ptr().add(1) as *const u8, + path_len - 1, + ); return Self::Abstract(name); } - let pathname = slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len); + let pathname = + slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len); if pathname.last() == Some(&0) { // A trailing NUL is not considered part of the path, and it does // not need to be included in the addrlen passed to functions like @@ -751,7 +801,9 @@ impl<'a> UnixAddrKind<'a> { // getsockname() (the BSDs do not do that). So we need to filter // out any trailing NUL here, so sockaddrs can round-trip through // the kernel and still compare equal. - Self::Pathname(Path::new(OsStr::from_bytes(&pathname[0..pathname.len() - 1]))) + Self::Pathname(Path::new(OsStr::from_bytes( + &pathname[0..pathname.len() - 1], + ))) } else { Self::Pathname(Path::new(OsStr::from_bytes(pathname))) } @@ -761,38 +813,41 @@ impl<'a> UnixAddrKind<'a> { impl UnixAddr { /// Create a new sockaddr_un representing a filesystem path. pub fn new(path: &P) -> Result { - path.with_nix_path(|cstr| { - unsafe { - let mut ret = libc::sockaddr_un { - sun_family: AddressFamily::Unix as sa_family_t, - .. mem::zeroed() - }; - - let bytes = cstr.to_bytes(); + path.with_nix_path(|cstr| unsafe { + let mut ret = libc::sockaddr_un { + sun_family: AddressFamily::Unix as sa_family_t, + ..mem::zeroed() + }; - if bytes.len() >= ret.sun_path.len() { - return Err(Errno::ENAMETOOLONG); - } + let bytes = cstr.to_bytes(); - let sun_len = (bytes.len() + - offset_of!(libc::sockaddr_un, sun_path)).try_into() - .unwrap(); + if bytes.len() >= ret.sun_path.len() { + return Err(Errno::ENAMETOOLONG); + } - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - { - ret.sun_len = sun_len; - } - ptr::copy_nonoverlapping(bytes.as_ptr(), - ret.sun_path.as_mut_ptr() as *mut u8, - bytes.len()); + let sun_len = (bytes.len() + + offset_of!(libc::sockaddr_un, sun_path)) + .try_into() + .unwrap(); - Ok(UnixAddr::from_raw_parts(ret, sun_len)) + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + { + ret.sun_len = sun_len; } + ptr::copy_nonoverlapping( + bytes.as_ptr(), + ret.sun_path.as_mut_ptr() as *mut u8, + bytes.len(), + ); + + Ok(UnixAddr::from_raw_parts(ret, sun_len)) })? } @@ -808,22 +863,24 @@ impl UnixAddr { unsafe { let mut ret = libc::sockaddr_un { sun_family: AddressFamily::Unix as sa_family_t, - .. mem::zeroed() + ..mem::zeroed() }; if path.len() >= ret.sun_path.len() { return Err(Errno::ENAMETOOLONG); } - let sun_len = (path.len() + - 1 + - offset_of!(libc::sockaddr_un, sun_path)).try_into() - .unwrap(); + let sun_len = + (path.len() + 1 + offset_of!(libc::sockaddr_un, sun_path)) + .try_into() + .unwrap(); // Abstract addresses are represented by sun_path[0] == // b'\0', so copy starting one byte in. - ptr::copy_nonoverlapping(path.as_ptr(), - ret.sun_path.as_mut_ptr().offset(1) as *mut u8, - path.len()); + ptr::copy_nonoverlapping( + path.as_ptr(), + ret.sun_path.as_mut_ptr().offset(1) as *mut u8, + path.len(), + ); Ok(UnixAddr::from_raw_parts(ret, sun_len)) } @@ -840,8 +897,11 @@ impl UnixAddr { /// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path) /// - if this is a unix addr with a pathname, sun.sun_path is a /// fs path, not necessarily nul-terminated. - pub(crate) unsafe fn from_raw_parts(sun: libc::sockaddr_un, sun_len: u8) -> UnixAddr { - cfg_if!{ + pub(crate) unsafe fn from_raw_parts( + sun: libc::sockaddr_un, + sun_len: u8, + ) -> UnixAddr { + cfg_if! { if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "illumos", @@ -898,8 +958,8 @@ impl UnixAddr { &mut self.sun } - fn sun_len(&self)-> u8 { - cfg_if!{ + fn sun_len(&self) -> u8 { + cfg_if! { if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "illumos", @@ -916,21 +976,26 @@ impl UnixAddr { impl private::SockaddrLikePriv for UnixAddr {} impl SockaddrLike for UnixAddr { - #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux" + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" ))] fn len(&self) -> libc::socklen_t { self.sun_len.into() } - unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) - -> Option where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option, + ) -> Option + where + Self: Sized, { if let Some(l) = len { - if (l as usize) < offset_of!(libc::sockaddr_un, sun_path) || - l > u8::MAX as libc::socklen_t + if (l as usize) < offset_of!(libc::sockaddr_un, sun_path) + || l > u8::MAX as libc::socklen_t { return None; } @@ -940,7 +1005,7 @@ impl SockaddrLike for UnixAddr { } let mut su: libc::sockaddr_un = mem::zeroed(); let sup = &mut su as *mut libc::sockaddr_un as *mut u8; - cfg_if!{ + cfg_if! { if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "illumos", @@ -957,7 +1022,10 @@ impl SockaddrLike for UnixAddr { Some(Self::from_raw_parts(su, su_len as u8)) } - fn size() -> libc::socklen_t where Self: Sized { + fn size() -> libc::socklen_t + where + Self: Sized, + { mem::size_of::() as libc::socklen_t } } @@ -1037,8 +1105,12 @@ pub trait SockaddrLike: private::SockaddrLikePriv { /// /// `addr` must be valid for the specific type of sockaddr. `len`, if /// present, must not exceed the length of valid data in `addr`. - unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) - -> Option where Self: Sized; + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option, + ) -> Option + where + Self: Sized; /// Return the address family of this socket /// @@ -1058,11 +1130,9 @@ pub trait SockaddrLike: private::SockaddrLikePriv { fn family(&self) -> Option { // Safe since all implementors have a sa_family field at the same // address, and they're all repr(C) - AddressFamily::from_i32( - unsafe { - (*(self as *const Self as *const libc::sockaddr)).sa_family as i32 - } - ) + AddressFamily::from_i32(unsafe { + (*(self as *const Self as *const libc::sockaddr)).sa_family as i32 + }) } cfg_if! { @@ -1101,7 +1171,10 @@ pub trait SockaddrLike: private::SockaddrLikePriv { } /// Return the available space in the structure - fn size() -> libc::socklen_t where Self: Sized { + fn size() -> libc::socklen_t + where + Self: Sized, + { mem::size_of::() as libc::socklen_t } } @@ -1121,8 +1194,12 @@ impl SockaddrLike for () { ptr::null() } - unsafe fn from_raw(_: *const libc::sockaddr, _: Option) - -> Option where Self: Sized + unsafe fn from_raw( + _: *const libc::sockaddr, + _: Option, + ) -> Option + where + Self: Sized, { None } @@ -1156,20 +1233,22 @@ impl SockaddrIn { /// Creates a new socket address from IPv4 octets and a port number. pub fn new(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self { Self(libc::sockaddr_in { - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "haiku", + target_os = "openbsd" + ))] sin_len: Self::size() as u8, sin_family: AddressFamily::Inet as sa_family_t, sin_port: u16::to_be(port), sin_addr: libc::in_addr { - s_addr: u32::from_ne_bytes([a, b, c, d]) + s_addr: u32::from_ne_bytes([a, b, c, d]), }, - sin_zero: unsafe{mem::zeroed()} + sin_zero: unsafe { mem::zeroed() }, }) } @@ -1184,8 +1263,12 @@ impl SockaddrIn { impl private::SockaddrLikePriv for SockaddrIn {} #[cfg(feature = "net")] impl SockaddrLike for SockaddrIn { - unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) - -> Option where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option, + ) -> Option + where + Self: Sized, { if let Some(l) = len { if l != mem::size_of::() as libc::socklen_t { @@ -1211,28 +1294,37 @@ impl fmt::Display for SockaddrIn { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let ne = u32::from_be(self.0.sin_addr.s_addr); let port = u16::from_be(self.0.sin_port); - write!(f, "{}.{}.{}.{}:{}", - ne >> 24, - (ne >> 16) & 0xFF, - (ne >> 8) & 0xFF, - ne & 0xFF, - port) + write!( + f, + "{}.{}.{}.{}:{}", + ne >> 24, + (ne >> 16) & 0xFF, + (ne >> 8) & 0xFF, + ne & 0xFF, + port + ) } } #[cfg(feature = "net")] impl From for SockaddrIn { fn from(addr: net::SocketAddrV4) -> Self { - Self(libc::sockaddr_in{ - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "haiku", target_os = "hermit", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] + Self(libc::sockaddr_in { + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "hermit", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] sin_len: mem::size_of::() as u8, sin_family: AddressFamily::Inet as sa_family_t, - sin_port: addr.port().to_be(), // network byte order + sin_port: addr.port().to_be(), // network byte order sin_addr: ipv4addr_to_libc(*addr.ip()), - .. unsafe { mem::zeroed() } + ..unsafe { mem::zeroed() } }) } } @@ -1242,7 +1334,7 @@ impl From for net::SocketAddrV4 { fn from(addr: SockaddrIn) -> Self { net::SocketAddrV4::new( net::Ipv4Addr::from(addr.0.sin_addr.s_addr.to_ne_bytes()), - u16::from_be(addr.0.sin_port) + u16::from_be(addr.0.sin_port), ) } } @@ -1290,8 +1382,12 @@ impl SockaddrIn6 { impl private::SockaddrLikePriv for SockaddrIn6 {} #[cfg(feature = "net")] impl SockaddrLike for SockaddrIn6 { - unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) - -> Option where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option, + ) -> Option + where + Self: Sized, { if let Some(l) = len { if l != mem::size_of::() as libc::socklen_t { @@ -1317,8 +1413,12 @@ impl fmt::Display for SockaddrIn6 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // These things are really hard to display properly. Easier to let std // do it. - let std = net::SocketAddrV6::new(self.ip(), self.port(), - self.flowinfo(), self.scope_id()); + let std = net::SocketAddrV6::new( + self.ip(), + self.port(), + self.flowinfo(), + self.scope_id(), + ); std.fmt(f) } } @@ -1326,19 +1426,25 @@ impl fmt::Display for SockaddrIn6 { #[cfg(feature = "net")] impl From for SockaddrIn6 { fn from(addr: net::SocketAddrV6) -> Self { - #[allow(clippy::needless_update)] // It isn't needless on Illumos - Self(libc::sockaddr_in6{ - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "haiku", target_os = "hermit", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] + #[allow(clippy::needless_update)] // It isn't needless on Illumos + Self(libc::sockaddr_in6 { + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "hermit", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] sin6_len: mem::size_of::() as u8, sin6_family: AddressFamily::Inet6 as sa_family_t, - sin6_port: addr.port().to_be(), // network byte order + sin6_port: addr.port().to_be(), // network byte order sin6_addr: ipv6addr_to_libc(addr.ip()), - sin6_flowinfo: addr.flowinfo(), // host byte order - sin6_scope_id: addr.scope_id(), // host byte order - .. unsafe { mem::zeroed() } + sin6_flowinfo: addr.flowinfo(), // host byte order + sin6_scope_id: addr.scope_id(), // host byte order + ..unsafe { mem::zeroed() } }) } } @@ -1350,7 +1456,7 @@ impl From for net::SocketAddrV6 { net::Ipv6Addr::from(addr.0.sin6_addr.s6_addr), u16::from_be(addr.0.sin6_port), u32::from_be(addr.0.sin6_flowinfo), - u32::from_be(addr.0.sin6_scope_id) + u32::from_be(addr.0.sin6_scope_id), ) } } @@ -1364,7 +1470,6 @@ impl std::str::FromStr for SockaddrIn6 { } } - /// A container for any sockaddr type /// /// Just like C's `sockaddr_storage`, this type is large enough to hold any type @@ -1394,7 +1499,10 @@ pub union SockaddrStorage { dl: LinkAddr, #[cfg(any(target_os = "android", target_os = "linux"))] nl: NetlinkAddr, - #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] sctl: SysControlAddr, #[cfg(feature = "net")] @@ -1405,26 +1513,31 @@ pub union SockaddrStorage { su: UnixAddr, #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] - vsock: VsockAddr + vsock: VsockAddr, } impl private::SockaddrLikePriv for SockaddrStorage {} impl SockaddrLike for SockaddrStorage { - unsafe fn from_raw(addr: *const libc::sockaddr, l: Option) - -> Option where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + l: Option, + ) -> Option + where + Self: Sized, { if addr.is_null() { return None; } if let Some(len) = l { let ulen = len as usize; - if ulen < offset_of!(libc::sockaddr, sa_data) || - ulen > mem::size_of::() { + if ulen < offset_of!(libc::sockaddr, sa_data) + || ulen > mem::size_of::() + { None - } else{ + } else { let mut ss: libc::sockaddr_storage = mem::zeroed(); let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8; ptr::copy(addr as *const u8, ssp, len as usize); - Some(Self{ss}) + Some(Self { ss }) } } else { // If length is not available and addr is of a fixed-length type, @@ -1432,43 +1545,56 @@ impl SockaddrLike for SockaddrStorage { // available, then there's nothing we can do. match (*addr).sa_family as i32 { #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_ALG => AlgAddr::from_raw(addr, l) - .map(|alg| Self { alg}), + libc::AF_ALG => { + AlgAddr::from_raw(addr, l).map(|alg| Self { alg }) + } #[cfg(feature = "net")] - libc::AF_INET => SockaddrIn::from_raw(addr, l) - .map(|sin| Self{ sin}), + libc::AF_INET => { + SockaddrIn::from_raw(addr, l).map(|sin| Self { sin }) + } #[cfg(feature = "net")] - libc::AF_INET6 => SockaddrIn6::from_raw(addr, l) - .map(|sin6| Self{ sin6}), - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd"))] + libc::AF_INET6 => { + SockaddrIn6::from_raw(addr, l).map(|sin6| Self { sin6 }) + } + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "haiku", + target_os = "openbsd" + ))] #[cfg(feature = "net")] - libc::AF_LINK => LinkAddr::from_raw(addr, l) - .map(|dl| Self{ dl}), + libc::AF_LINK => { + LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) + } #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => NetlinkAddr::from_raw(addr, l) - .map(|nl| Self{ nl }), - #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "linux" + libc::AF_NETLINK => { + NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl }) + } + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" ))] #[cfg(feature = "net")] - libc::AF_PACKET => LinkAddr::from_raw(addr, l) - .map(|dl| Self{ dl}), - #[cfg(all(feature = "ioctl", - any(target_os = "ios", target_os = "macos")))] - libc::AF_SYSTEM => SysControlAddr::from_raw(addr, l) - .map(|sctl| Self {sctl}), + libc::AF_PACKET => { + LinkAddr::from_raw(addr, l).map(|dl| Self { dl }) + } + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] + libc::AF_SYSTEM => { + SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl }) + } #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_VSOCK => VsockAddr::from_raw(addr, l) - .map(|vsock| Self{vsock}), - _ => None + libc::AF_VSOCK => { + VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock }) + } + _ => None, } } } @@ -1481,15 +1607,14 @@ macro_rules! accessors { $sockty:ty, $family:expr, $libc_ty:ty, - $field:ident) => - { + $field:ident) => { /// Safely and falliably downcast to an immutable reference pub fn $fname(&self) -> Option<&$sockty> { - if self.family() == Some($family) && - self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t + if self.family() == Some($family) + && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t { // Safe because family and len are validated - Some(unsafe{&self.$field}) + Some(unsafe { &self.$field }) } else { None } @@ -1497,66 +1622,70 @@ macro_rules! accessors { /// Safely and falliably downcast to a mutable reference pub fn $fname_mut(&mut self) -> Option<&mut $sockty> { - if self.family() == Some($family) && - self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t + if self.family() == Some($family) + && self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t { // Safe because family and len are validated - Some(unsafe{&mut self.$field}) + Some(unsafe { &mut self.$field }) } else { None } } - } + }; } impl SockaddrStorage { #[cfg(any(target_os = "android", target_os = "linux"))] - accessors!{as_alg_addr, as_alg_addr_mut, AlgAddr, - AddressFamily::Alg, libc::sockaddr_alg, alg} + accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr, + AddressFamily::Alg, libc::sockaddr_alg, alg} - #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "linux"))] + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] #[cfg(feature = "net")] - accessors!{ - as_link_addr, as_link_addr_mut, LinkAddr, - AddressFamily::Packet, libc::sockaddr_ll, dl} - - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd"))] + accessors! { + as_link_addr, as_link_addr_mut, LinkAddr, + AddressFamily::Packet, libc::sockaddr_ll, dl} + + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg(feature = "net")] - accessors!{ - as_link_addr, as_link_addr_mut, LinkAddr, - AddressFamily::Link, libc::sockaddr_dl, dl} + accessors! { + as_link_addr, as_link_addr_mut, LinkAddr, + AddressFamily::Link, libc::sockaddr_dl, dl} #[cfg(feature = "net")] - accessors!{ - as_sockaddr_in, as_sockaddr_in_mut, SockaddrIn, - AddressFamily::Inet, libc::sockaddr_in, sin} + accessors! { + as_sockaddr_in, as_sockaddr_in_mut, SockaddrIn, + AddressFamily::Inet, libc::sockaddr_in, sin} #[cfg(feature = "net")] - accessors!{ - as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6, - AddressFamily::Inet6, libc::sockaddr_in6, sin6} + accessors! { + as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6, + AddressFamily::Inet6, libc::sockaddr_in6, sin6} #[cfg(any(target_os = "android", target_os = "linux"))] - accessors!{as_netlink_addr, as_netlink_addr_mut, NetlinkAddr, - AddressFamily::Netlink, libc::sockaddr_nl, nl} + accessors! {as_netlink_addr, as_netlink_addr_mut, NetlinkAddr, + AddressFamily::Netlink, libc::sockaddr_nl, nl} #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] - accessors!{as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr, - AddressFamily::System, libc::sockaddr_ctl, sctl} + accessors! {as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr, + AddressFamily::System, libc::sockaddr_ctl, sctl} #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] - accessors!{as_vsock_addr, as_vsock_addr_mut, VsockAddr, - AddressFamily::Vsock, libc::sockaddr_vm, vsock} + accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr, + AddressFamily::Vsock, libc::sockaddr_vm, vsock} } impl fmt::Debug for SockaddrStorage { @@ -1564,7 +1693,7 @@ impl fmt::Debug for SockaddrStorage { f.debug_struct("SockaddrStorage") // Safe because sockaddr_storage has the least specific // field types - .field("ss", unsafe{&self.ss}) + .field("ss", unsafe { &self.ss }) .finish() } } @@ -1579,20 +1708,23 @@ impl fmt::Display for SockaddrStorage { libc::AF_INET => self.sin.fmt(f), #[cfg(feature = "net")] libc::AF_INET6 => self.sin6.fmt(f), - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg(feature = "net")] libc::AF_LINK => self.dl.fmt(f), #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_NETLINK => self.nl.fmt(f), - #[cfg(any(target_os = "android", - target_os = "linux", - target_os = "fuchsia" + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "fuchsia" ))] #[cfg(feature = "net")] libc::AF_PACKET => self.dl.fmt(f), @@ -1602,7 +1734,7 @@ impl fmt::Display for SockaddrStorage { libc::AF_UNIX => self.su.fmt(f), #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_VSOCK => self.vsock.fmt(f), - _ => "

".fmt(f) + _ => "
".fmt(f), } } } @@ -1650,20 +1782,23 @@ impl Hash for SockaddrStorage { libc::AF_INET => self.sin.hash(s), #[cfg(feature = "net")] libc::AF_INET6 => self.sin6.hash(s), - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg(feature = "net")] libc::AF_LINK => self.dl.hash(s), #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_NETLINK => self.nl.hash(s), - #[cfg(any(target_os = "android", - target_os = "linux", - target_os = "fuchsia" + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "fuchsia" ))] #[cfg(feature = "net")] libc::AF_PACKET => self.dl.hash(s), @@ -1673,7 +1808,7 @@ impl Hash for SockaddrStorage { libc::AF_UNIX => self.su.hash(s), #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_VSOCK => self.vsock.hash(s), - _ => self.ss.hash(s) + _ => self.ss.hash(s), } } } @@ -1689,20 +1824,23 @@ impl PartialEq for SockaddrStorage { (libc::AF_INET, libc::AF_INET) => self.sin == other.sin, #[cfg(feature = "net")] (libc::AF_INET6, libc::AF_INET6) => self.sin6 == other.sin6, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg(feature = "net")] (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl, #[cfg(any(target_os = "android", target_os = "linux"))] (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl, - #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "linux" + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" ))] #[cfg(feature = "net")] (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl, @@ -1740,7 +1878,7 @@ mod private { since = "0.24.0", note = "use SockaddrLike or SockaddrStorage instead" )] -#[allow(missing_docs)] // Since they're all deprecated anyway +#[allow(missing_docs)] // Since they're all deprecated anyway #[allow(deprecated)] #[non_exhaustive] pub enum SockAddr { @@ -1754,19 +1892,24 @@ pub enum SockAddr { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Alg(AlgAddr), - #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] SysControl(SysControlAddr), /// Datalink address (MAC) - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg(feature = "net")] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] Link(LinkAddr), @@ -1775,7 +1918,7 @@ pub enum SockAddr { Vsock(VsockAddr), } -#[allow(missing_docs)] // Since they're all deprecated anyway +#[allow(missing_docs)] // Since they're all deprecated anyway #[allow(deprecated)] impl SockAddr { feature! { @@ -1826,19 +1969,23 @@ impl SockAddr { SockAddr::Netlink(..) => AddressFamily::Netlink, #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Alg(..) => AddressFamily::Alg, - #[cfg(all(feature = "ioctl", - any(target_os = "ios", target_os = "macos")))] + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] SockAddr::SysControl(..) => AddressFamily::System, #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg(feature = "net")] SockAddr::Link(..) => AddressFamily::Packet, - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd" + ))] #[cfg(feature = "net")] SockAddr::Link(..) => AddressFamily::Link, #[cfg(any(target_os = "android", target_os = "linux"))] @@ -1862,7 +2009,9 @@ impl SockAddr { /// ensure that the pointer is valid. #[cfg(not(target_os = "fuchsia"))] #[cfg(feature = "net")] - pub(crate) unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option { + pub(crate) unsafe fn from_libc_sockaddr( + addr: *const libc::sockaddr, + ) -> Option { if addr.is_null() { None } else { @@ -1870,40 +2019,51 @@ impl SockAddr { Some(AddressFamily::Unix) => None, #[cfg(feature = "net")] Some(AddressFamily::Inet) => Some(SockAddr::Inet( - InetAddr::V4(ptr::read_unaligned(addr as *const _)))), + InetAddr::V4(ptr::read_unaligned(addr as *const _)), + )), #[cfg(feature = "net")] Some(AddressFamily::Inet6) => Some(SockAddr::Inet( - InetAddr::V6(ptr::read_unaligned(addr as *const _)))), + InetAddr::V6(ptr::read_unaligned(addr as *const _)), + )), #[cfg(any(target_os = "android", target_os = "linux"))] Some(AddressFamily::Netlink) => Some(SockAddr::Netlink( - NetlinkAddr(ptr::read_unaligned(addr as *const _)))), - #[cfg(all(feature = "ioctl", - any(target_os = "ios", target_os = "macos")))] + NetlinkAddr(ptr::read_unaligned(addr as *const _)), + )), + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] Some(AddressFamily::System) => Some(SockAddr::SysControl( - SysControlAddr(ptr::read_unaligned(addr as *const _)))), + SysControlAddr(ptr::read_unaligned(addr as *const _)), + )), #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg(feature = "net")] - Some(AddressFamily::Packet) => Some(SockAddr::Link( - LinkAddr(ptr::read_unaligned(addr as *const _)))), - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] + Some(AddressFamily::Packet) => Some(SockAddr::Link(LinkAddr( + ptr::read_unaligned(addr as *const _), + ))), + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd" + ))] #[cfg(feature = "net")] Some(AddressFamily::Link) => { - let ether_addr = LinkAddr(ptr::read_unaligned(addr as *const _)); + let ether_addr = + LinkAddr(ptr::read_unaligned(addr as *const _)); if ether_addr.is_empty() { None } else { Some(SockAddr::Link(ether_addr)) } - }, + } #[cfg(any(target_os = "android", target_os = "linux"))] - Some(AddressFamily::Vsock) => Some(SockAddr::Vsock( - VsockAddr(ptr::read_unaligned(addr as *const _)))), + Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(VsockAddr( + ptr::read_unaligned(addr as *const _), + ))), // Other address families are currently not supported and simply yield a None // entry instead of a proper conversion to a `SockAddr`. Some(_) | None => None, @@ -1924,24 +2084,27 @@ impl SockAddr { SockAddr::Inet(InetAddr::V4(ref addr)) => ( // This cast is always allowed in C unsafe { - &*(addr as *const libc::sockaddr_in as *const libc::sockaddr) + &*(addr as *const libc::sockaddr_in + as *const libc::sockaddr) }, - mem::size_of_val(addr) as libc::socklen_t + mem::size_of_val(addr) as libc::socklen_t, ), #[cfg(feature = "net")] SockAddr::Inet(InetAddr::V6(ref addr)) => ( // This cast is always allowed in C unsafe { - &*(addr as *const libc::sockaddr_in6 as *const libc::sockaddr) + &*(addr as *const libc::sockaddr_in6 + as *const libc::sockaddr) }, - mem::size_of_val(addr) as libc::socklen_t + mem::size_of_val(addr) as libc::socklen_t, ), SockAddr::Unix(ref unix_addr) => ( // This cast is always allowed in C unsafe { - &*(&unix_addr.sun as *const libc::sockaddr_un as *const libc::sockaddr) + &*(&unix_addr.sun as *const libc::sockaddr_un + as *const libc::sockaddr) }, - unix_addr.sun_len() as libc::socklen_t + unix_addr.sun_len() as libc::socklen_t, ), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Netlink(NetlinkAddr(ref sa)) => ( @@ -1949,7 +2112,7 @@ impl SockAddr { unsafe { &*(sa as *const libc::sockaddr_nl as *const libc::sockaddr) }, - mem::size_of_val(sa) as libc::socklen_t + mem::size_of_val(sa) as libc::socklen_t, ), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Alg(AlgAddr(ref sa)) => ( @@ -1957,41 +2120,46 @@ impl SockAddr { unsafe { &*(sa as *const libc::sockaddr_alg as *const libc::sockaddr) }, - mem::size_of_val(sa) as libc::socklen_t + mem::size_of_val(sa) as libc::socklen_t, ), - #[cfg(all(feature = "ioctl", - any(target_os = "ios", target_os = "macos")))] + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] SockAddr::SysControl(SysControlAddr(ref sa)) => ( // This cast is always allowed in C unsafe { &*(sa as *const libc::sockaddr_ctl as *const libc::sockaddr) }, - mem::size_of_val(sa) as libc::socklen_t - + mem::size_of_val(sa) as libc::socklen_t, ), #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg(feature = "net")] SockAddr::Link(LinkAddr(ref addr)) => ( // This cast is always allowed in C unsafe { - &*(addr as *const libc::sockaddr_ll as *const libc::sockaddr) + &*(addr as *const libc::sockaddr_ll + as *const libc::sockaddr) }, - mem::size_of_val(addr) as libc::socklen_t + mem::size_of_val(addr) as libc::socklen_t, ), - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg(feature = "net")] SockAddr::Link(LinkAddr(ref addr)) => ( // This cast is always allowed in C unsafe { - &*(addr as *const libc::sockaddr_dl as *const libc::sockaddr) + &*(addr as *const libc::sockaddr_dl + as *const libc::sockaddr) }, - mem::size_of_val(addr) as libc::socklen_t + mem::size_of_val(addr) as libc::socklen_t, ), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Vsock(VsockAddr(ref sa)) => ( @@ -1999,7 +2167,7 @@ impl SockAddr { unsafe { &*(sa as *const libc::sockaddr_vm as *const libc::sockaddr) }, - mem::size_of_val(sa) as libc::socklen_t + mem::size_of_val(sa) as libc::socklen_t, ), } } @@ -2016,18 +2184,22 @@ impl fmt::Display for SockAddr { SockAddr::Netlink(ref nl) => nl.fmt(f), #[cfg(any(target_os = "android", target_os = "linux"))] SockAddr::Alg(ref nl) => nl.fmt(f), - #[cfg(all(feature = "ioctl", - any(target_os = "ios", target_os = "macos")))] + #[cfg(all( + feature = "ioctl", + any(target_os = "ios", target_os = "macos") + ))] SockAddr::SysControl(ref sc) => sc.fmt(f), - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd" + ))] #[cfg(feature = "net")] SockAddr::Link(ref ether_addr) => ether_addr.fmt(f), #[cfg(any(target_os = "android", target_os = "linux"))] @@ -2044,9 +2216,10 @@ impl private::SockaddrLikePriv for SockAddr {} #[cfg(feature = "net")] #[allow(deprecated)] impl SockaddrLike for SockAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, _len: Option) - -> Option - { + unsafe fn from_raw( + addr: *const libc::sockaddr, + _len: Option, + ) -> Option { Self::from_libc_sockaddr(addr) } } @@ -2054,10 +2227,10 @@ impl SockaddrLike for SockAddr { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub mod netlink { + use super::*; use crate::sys::socket::addr::AddressFamily; use libc::{sa_family_t, sockaddr_nl}; use std::{fmt, mem}; - use super::*; /// Address for the Linux kernel user interface device. /// @@ -2093,8 +2266,12 @@ pub mod netlink { impl private::SockaddrLikePriv for NetlinkAddr {} impl SockaddrLike for NetlinkAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) - -> Option where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option, + ) -> Option + where + Self: Sized, { if let Some(l) = len { if l != mem::size_of::() as libc::socklen_t { @@ -2124,11 +2301,11 @@ pub mod netlink { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub mod alg { - use libc::{AF_ALG, sockaddr_alg, c_char}; - use std::{fmt, mem, str}; - use std::hash::{Hash, Hasher}; - use std::ffi::CStr; use super::*; + use libc::{c_char, sockaddr_alg, AF_ALG}; + use std::ffi::CStr; + use std::hash::{Hash, Hasher}; + use std::{fmt, mem, str}; /// Socket address for the Linux kernel crypto API #[derive(Copy, Clone)] @@ -2137,11 +2314,16 @@ pub mod alg { impl private::SockaddrLikePriv for AlgAddr {} impl SockaddrLike for AlgAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, l: Option) - -> Option where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + l: Option, + ) -> Option + where + Self: Sized, { if let Some(l) = l { - if l != mem::size_of::() as libc::socklen_t { + if l != mem::size_of::() as libc::socklen_t + { return None; } } @@ -2162,8 +2344,19 @@ pub mod alg { impl PartialEq for AlgAddr { fn eq(&self, other: &Self) -> bool { let (inner, other) = (self.0, other.0); - (inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]) == - (other.salg_family, &other.salg_type[..], other.salg_feat, other.salg_mask, &other.salg_name[..]) + ( + inner.salg_family, + &inner.salg_type[..], + inner.salg_feat, + inner.salg_mask, + &inner.salg_name[..], + ) == ( + other.salg_family, + &other.salg_type[..], + other.salg_feat, + other.salg_mask, + &other.salg_name[..], + ) } } @@ -2172,7 +2365,14 @@ pub mod alg { impl Hash for AlgAddr { fn hash(&self, s: &mut H) { let inner = self.0; - (inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]).hash(s); + ( + inner.salg_family, + &inner.salg_type[..], + inner.salg_feat, + inner.salg_mask, + &inner.salg_name[..], + ) + .hash(s); } } @@ -2181,29 +2381,37 @@ pub mod alg { pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr { let mut addr: sockaddr_alg = unsafe { mem::zeroed() }; addr.salg_family = AF_ALG as u16; - addr.salg_type[..alg_type.len()].copy_from_slice(alg_type.to_string().as_bytes()); - addr.salg_name[..alg_name.len()].copy_from_slice(alg_name.to_string().as_bytes()); + addr.salg_type[..alg_type.len()] + .copy_from_slice(alg_type.to_string().as_bytes()); + addr.salg_name[..alg_name.len()] + .copy_from_slice(alg_name.to_string().as_bytes()); AlgAddr(addr) } - /// Return the socket's cipher type, for example `hash` or `aead`. pub fn alg_type(&self) -> &CStr { - unsafe { CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) } + unsafe { + CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) + } } /// Return the socket's cipher name, for example `sha1`. pub fn alg_name(&self) -> &CStr { - unsafe { CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) } + unsafe { + CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) + } } } impl fmt::Display for AlgAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "type: {} alg: {}", - self.alg_name().to_string_lossy(), - self.alg_type().to_string_lossy()) + write!( + f, + "type: {} alg: {}", + self.alg_name().to_string_lossy(), + self.alg_type().to_string_lossy() + ) } } @@ -2323,7 +2531,6 @@ pub mod sys_control { } } - #[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))] #[cfg_attr(docsrs, doc(cfg(all())))] mod datalink { @@ -2418,14 +2625,16 @@ mod datalink { } } -#[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "haiku", - target_os = "openbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "haiku", + target_os = "openbsd" +))] #[cfg_attr(docsrs, doc(cfg(all())))] mod datalink { feature! { @@ -2543,11 +2752,11 @@ mod datalink { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub mod vsock { + use super::*; use crate::sys::socket::addr::AddressFamily; use libc::{sa_family_t, sockaddr_vm}; - use std::{fmt, mem}; use std::hash::{Hash, Hasher}; - use super::*; + use std::{fmt, mem}; /// Socket address for VMWare VSockets protocol /// @@ -2560,8 +2769,12 @@ pub mod vsock { impl private::SockaddrLikePriv for VsockAddr {} impl SockaddrLike for VsockAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, len: Option) - -> Option where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option, + ) -> Option + where + Self: Sized, { if let Some(l) = len { if l != mem::size_of::() as libc::socklen_t { @@ -2584,8 +2797,8 @@ pub mod vsock { impl PartialEq for VsockAddr { fn eq(&self, other: &Self) -> bool { let (inner, other) = (self.0, other.0); - (inner.svm_family, inner.svm_cid, inner.svm_port) == - (other.svm_family, other.svm_cid, other.svm_port) + (inner.svm_family, inner.svm_cid, inner.svm_port) + == (other.svm_family, other.svm_cid, other.svm_port) } } @@ -2655,33 +2868,39 @@ mod tests { fn test_ipv6addr_to_libc() { let s = std::net::Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8); let l = ipv6addr_to_libc(&s); - assert_eq!(l.s6_addr, [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8]); + assert_eq!( + l.s6_addr, + [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8] + ); } } mod link { #![allow(clippy::cast_ptr_alignment)] - use super::*; - #[cfg(any(target_os = "ios", - target_os = "macos", - target_os = "illumos" - ))] + #[cfg(any( + target_os = "ios", + target_os = "macos", + target_os = "illumos" + ))] use super::super::super::socklen_t; + use super::*; /// Don't panic when trying to display an empty datalink address - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[test] fn test_datalink_display() { use super::super::LinkAddr; use std::mem; - let la = LinkAddr(libc::sockaddr_dl{ + let la = LinkAddr(libc::sockaddr_dl { sdl_len: 56, sdl_family: 18, sdl_index: 5, @@ -2689,67 +2908,75 @@ mod tests { sdl_nlen: 3, sdl_alen: 0, sdl_slen: 0, - .. unsafe{mem::zeroed()} + ..unsafe { mem::zeroed() } }); format!("{}", la); } #[cfg(all( - any(target_os = "android", - target_os = "fuchsia", - target_os = "linux"), - target_endian = "little" + any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ), + target_endian = "little" ))] #[test] fn linux_loopback() { #[repr(align(2))] struct Raw([u8; 20]); - let bytes = Raw([17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0]); + let bytes = Raw([ + 17u8, 0, 0, 0, 1, 0, 0, 0, 4, 3, 0, 6, 1, 2, 3, 4, 5, 6, 0, 0, + ]); let sa = bytes.0.as_ptr() as *const libc::sockaddr; let len = None; - let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); + let sock_addr = + unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); assert_eq!(sock_addr.family(), Some(AddressFamily::Packet)); match sock_addr.as_link_addr() { Some(dl) => assert_eq!(dl.addr(), Some([1, 2, 3, 4, 5, 6])), - None => panic!("Can't unwrap sockaddr storage") + None => panic!("Can't unwrap sockaddr storage"), } } - #[cfg(any(target_os = "ios", - target_os = "macos" - ))] + #[cfg(any(target_os = "ios", target_os = "macos"))] #[test] fn macos_loopback() { - let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; + let bytes = + [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; let sa = bytes.as_ptr() as *const libc::sockaddr; let len = Some(bytes.len() as socklen_t); - let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); + let sock_addr = + unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); match sock_addr.as_link_addr() { Some(dl) => { assert!(dl.addr().is_none()); - }, - None => panic!("Can't unwrap sockaddr storage") + } + None => panic!("Can't unwrap sockaddr storage"), } } - #[cfg(any(target_os = "ios", - target_os = "macos" - ))] + #[cfg(any(target_os = "ios", target_os = "macos"))] #[test] fn macos_tap() { - let bytes = [20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, 76, -80]; + let bytes = [ + 20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, + 76, -80, + ]; let ptr = bytes.as_ptr(); let sa = ptr as *const libc::sockaddr; let len = Some(bytes.len() as socklen_t); - let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len).unwrap() }; + let sock_addr = + unsafe { SockaddrStorage::from_raw(sa, len).unwrap() }; assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); match sock_addr.as_link_addr() { - Some(dl) => assert_eq!(dl.addr(), - Some([24u8, 101, 144, 221, 76, 176])), - None => panic!("Can't unwrap sockaddr storage") + Some(dl) => { + assert_eq!(dl.addr(), Some([24u8, 101, 144, 221, 76, 176])) + } + None => panic!("Can't unwrap sockaddr storage"), } } @@ -2768,27 +2995,32 @@ mod tests { assert_eq!(sock_addr.family().unwrap(), AddressFamily::Link); - assert_eq!(sock_addr.as_link_addr().unwrap().addr(), - Some([24u8, 101, 144, 221, 76, 176])); + assert_eq!( + sock_addr.as_link_addr().unwrap().addr(), + Some([24u8, 101, 144, 221, 76, 176]) + ); } #[test] fn size() { - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd", - target_os = "haiku"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "illumos", + target_os = "openbsd", + target_os = "haiku" + ))] let l = mem::size_of::(); #[cfg(any( - target_os = "android", - target_os = "fuchsia", - target_os = "linux"))] + target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] let l = mem::size_of::(); - assert_eq!( LinkAddr::size() as usize, l); + assert_eq!(LinkAddr::size() as usize, l); } } @@ -2805,8 +3037,10 @@ mod tests { #[test] fn size() { - assert_eq!(mem::size_of::(), - SockaddrIn::size() as usize); + assert_eq!( + mem::size_of::(), + SockaddrIn::size() as usize + ); } } @@ -2823,8 +3057,10 @@ mod tests { #[test] fn size() { - assert_eq!(mem::size_of::(), - SockaddrIn6::size() as usize); + assert_eq!( + mem::size_of::(), + SockaddrIn6::size() as usize + ); } } @@ -2837,15 +3073,21 @@ mod tests { let name = String::from("nix\0abstract\0test"); let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); - let sun_path1 = unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] }; - let sun_path2 = [0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116]; + let sun_path1 = + unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] }; + let sun_path2 = [ + 0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, + 116, 101, 115, 116, + ]; assert_eq!(sun_path1, sun_path2); } #[test] fn size() { - assert_eq!(mem::size_of::(), - UnixAddr::size() as usize); + assert_eq!( + mem::size_of::(), + UnixAddr::size() as usize + ); } } } diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 90111ec54d..e9f26333a3 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -1,18 +1,15 @@ //! Socket options as used by `setsockopt` and `getsockopt`. -use cfg_if::cfg_if; use super::{GetSockOpt, SetSockOpt}; -use crate::Result; use crate::errno::Errno; use crate::sys::time::TimeVal; +use crate::Result; +use cfg_if::cfg_if; use libc::{self, c_int, c_void, socklen_t}; -use std::mem::{ - self, - MaybeUninit -}; -use std::os::unix::io::RawFd; use std::ffi::{OsStr, OsString}; +use std::mem::{self, MaybeUninit}; #[cfg(target_family = "unix")] use std::os::unix::ffi::OsStrExt; +use std::os::unix::io::RawFd; // Constants // TCP_CA_NAME_MAX isn't defined in user space include files @@ -51,14 +48,18 @@ macro_rules! setsockopt_impl { unsafe { let setter: $setter = Set::new(val); - let res = libc::setsockopt(fd, $level, $flag, - setter.ffi_ptr(), - setter.ffi_len()); + let res = libc::setsockopt( + fd, + $level, + $flag, + setter.ffi_ptr(), + setter.ffi_len(), + ); Errno::result(res).map(drop) } } } - } + }; } /// Helper for implementing `GetSockOpt` for a given socket option. See @@ -92,16 +93,20 @@ macro_rules! getsockopt_impl { unsafe { let mut getter: $getter = Get::uninit(); - let res = libc::getsockopt(fd, $level, $flag, - getter.ffi_ptr(), - getter.ffi_len()); + let res = libc::getsockopt( + fd, + $level, + $flag, + getter.ffi_ptr(), + getter.ffi_len(), + ); Errno::result(res)?; Ok(getter.assume_init()) } } } - } + }; } /// Helper to generate the sockopt accessors. See @@ -248,13 +253,22 @@ macro_rules! sockopt_impl { sockopt_impl!( /// Enables local address reuse - ReuseAddr, Both, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool + ReuseAddr, + Both, + libc::SOL_SOCKET, + libc::SO_REUSEADDR, + bool ); #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] sockopt_impl!( /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an /// identical socket address. - ReusePort, Both, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool); + ReusePort, + Both, + libc::SOL_SOCKET, + libc::SO_REUSEPORT, + bool +); #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -265,24 +279,42 @@ sockopt_impl!( /// send a stream of mouse events which receive no replies, this /// packetization may cause significant delays. The boolean option /// TCP_NODELAY defeats this algorithm. - TcpNoDelay, Both, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool); + TcpNoDelay, + Both, + libc::IPPROTO_TCP, + libc::TCP_NODELAY, + bool +); sockopt_impl!( /// When enabled, a close(2) or shutdown(2) will not return until all /// queued messages for the socket have been successfully sent or the /// linger timeout has been reached. - Linger, Both, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger); + Linger, + Both, + libc::SOL_SOCKET, + libc::SO_LINGER, + libc::linger +); #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Join a multicast group - IpAddMembership, SetOnly, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, - super::IpMembershipRequest); + IpAddMembership, + SetOnly, + libc::IPPROTO_IP, + libc::IP_ADD_MEMBERSHIP, + super::IpMembershipRequest +); #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Leave a multicast group. - IpDropMembership, SetOnly, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, - super::IpMembershipRequest); + IpDropMembership, + SetOnly, + libc::IPPROTO_IP, + libc::IP_DROP_MEMBERSHIP, + super::IpMembershipRequest +); cfg_if! { if #[cfg(any(target_os = "android", target_os = "linux"))] { #[cfg(feature = "net")] @@ -322,74 +354,145 @@ sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Set or read the time-to-live value of outgoing multicast packets for /// this socket. - IpMulticastTtl, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8); + IpMulticastTtl, + Both, + libc::IPPROTO_IP, + libc::IP_MULTICAST_TTL, + u8 +); #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Set or read a boolean integer argument that determines whether sent /// multicast packets should be looped back to the local sockets. - IpMulticastLoop, Both, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool); + IpMulticastLoop, + Both, + libc::IPPROTO_IP, + libc::IP_MULTICAST_LOOP, + bool +); #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// If enabled, this boolean option allows binding to an IP address that /// is nonlocal or does not (yet) exist. - IpFreebind, Both, libc::IPPROTO_IP, libc::IP_FREEBIND, bool); + IpFreebind, + Both, + libc::IPPROTO_IP, + libc::IP_FREEBIND, + bool +); sockopt_impl!( /// Specify the receiving timeout until reporting an error. - ReceiveTimeout, Both, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal); + ReceiveTimeout, + Both, + libc::SOL_SOCKET, + libc::SO_RCVTIMEO, + TimeVal +); sockopt_impl!( /// Specify the sending timeout until reporting an error. - SendTimeout, Both, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal); + SendTimeout, + Both, + libc::SOL_SOCKET, + libc::SO_SNDTIMEO, + TimeVal +); sockopt_impl!( /// Set or get the broadcast flag. - Broadcast, Both, libc::SOL_SOCKET, libc::SO_BROADCAST, bool); + Broadcast, + Both, + libc::SOL_SOCKET, + libc::SO_BROADCAST, + bool +); sockopt_impl!( /// If this option is enabled, out-of-band data is directly placed into /// the receive data stream. - OobInline, Both, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool); + OobInline, + Both, + libc::SOL_SOCKET, + libc::SO_OOBINLINE, + bool +); sockopt_impl!( /// Get and clear the pending socket error. - SocketError, GetOnly, libc::SOL_SOCKET, libc::SO_ERROR, i32); + SocketError, + GetOnly, + libc::SOL_SOCKET, + libc::SO_ERROR, + i32 +); sockopt_impl!( /// Set or get the don't route flag. - DontRoute, Both, libc::SOL_SOCKET, libc::SO_DONTROUTE, bool); + DontRoute, + Both, + libc::SOL_SOCKET, + libc::SO_DONTROUTE, + bool +); sockopt_impl!( /// Enable sending of keep-alive messages on connection-oriented sockets. - KeepAlive, Both, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool); + KeepAlive, + Both, + libc::SOL_SOCKET, + libc::SO_KEEPALIVE, + bool +); #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "ios" + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "ios" ))] sockopt_impl!( /// Get the credentials of the peer process of a connected unix domain /// socket. - LocalPeerCred, GetOnly, 0, libc::LOCAL_PEERCRED, super::XuCred); + LocalPeerCred, + GetOnly, + 0, + libc::LOCAL_PEERCRED, + super::XuCred +); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!( /// Return the credentials of the foreign process connected to this socket. - PeerCredentials, GetOnly, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials); -#[cfg(any(target_os = "ios", - target_os = "macos"))] + PeerCredentials, + GetOnly, + libc::SOL_SOCKET, + libc::SO_PEERCRED, + super::UnixCredentials +); +#[cfg(any(target_os = "ios", target_os = "macos"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Specify the amount of time, in seconds, that the connection must be idle /// before keepalive probes (if enabled) are sent. - TcpKeepAlive, Both, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32); -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux"))] + TcpKeepAlive, + Both, + libc::IPPROTO_TCP, + libc::TCP_KEEPALIVE, + u32 +); +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux" +))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The time (in seconds) the connection needs to remain idle before TCP /// starts sending keepalive probes - TcpKeepIdle, Both, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32); + TcpKeepIdle, + Both, + libc::IPPROTO_TCP, + libc::TCP_KEEPIDLE, + u32 +); cfg_if! { if #[cfg(any(target_os = "android", target_os = "linux"))] { sockopt_impl!( @@ -407,20 +510,33 @@ sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The maximum number of keepalive probes TCP should send before /// dropping the connection. - TcpKeepCount, Both, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32); -#[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "linux"))] + TcpKeepCount, + Both, + libc::IPPROTO_TCP, + libc::TCP_KEEPCNT, + u32 +); +#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] sockopt_impl!( #[allow(missing_docs)] // Not documented by Linux! - TcpRepair, Both, libc::IPPROTO_TCP, libc::TCP_REPAIR, u32); + TcpRepair, + Both, + libc::IPPROTO_TCP, + libc::TCP_REPAIR, + u32 +); #[cfg(not(any(target_os = "openbsd", target_os = "haiku")))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The time (in seconds) between individual keepalive probes. - TcpKeepInterval, Both, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32); + TcpKeepInterval, + Both, + libc::IPPROTO_TCP, + libc::TCP_KEEPINTVL, + u32 +); #[cfg(any(target_os = "fuchsia", target_os = "linux"))] #[cfg(feature = "net")] sockopt_impl!( @@ -428,98 +544,193 @@ sockopt_impl!( /// Specifies the maximum amount of time in milliseconds that transmitted /// data may remain unacknowledged before TCP will forcibly close the /// corresponding connection - TcpUserTimeout, Both, libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT, u32); + TcpUserTimeout, + Both, + libc::IPPROTO_TCP, + libc::TCP_USER_TIMEOUT, + u32 +); sockopt_impl!( /// Sets or gets the maximum socket receive buffer in bytes. - RcvBuf, Both, libc::SOL_SOCKET, libc::SO_RCVBUF, usize); + RcvBuf, + Both, + libc::SOL_SOCKET, + libc::SO_RCVBUF, + usize +); sockopt_impl!( /// Sets or gets the maximum socket send buffer in bytes. - SndBuf, Both, libc::SOL_SOCKET, libc::SO_SNDBUF, usize); + SndBuf, + Both, + libc::SOL_SOCKET, + libc::SO_SNDBUF, + usize +); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!( /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can /// perform the same task as `SO_RCVBUF`, but the `rmem_max limit` can be /// overridden. - RcvBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize); + RcvBufForce, + SetOnly, + libc::SOL_SOCKET, + libc::SO_RCVBUFFORCE, + usize +); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!( /// Using this socket option, a privileged (`CAP_NET_ADMIN`) process can /// perform the same task as `SO_SNDBUF`, but the `wmem_max` limit can be /// overridden. - SndBufForce, SetOnly, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize); + SndBufForce, + SetOnly, + libc::SOL_SOCKET, + libc::SO_SNDBUFFORCE, + usize +); sockopt_impl!( /// Gets the socket type as an integer. - SockType, GetOnly, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType); + SockType, + GetOnly, + libc::SOL_SOCKET, + libc::SO_TYPE, + super::SockType +); sockopt_impl!( /// Returns a value indicating whether or not this socket has been marked to /// accept connections with `listen(2)`. - AcceptConn, GetOnly, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool); + AcceptConn, + GetOnly, + libc::SOL_SOCKET, + libc::SO_ACCEPTCONN, + bool +); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!( /// Bind this socket to a particular device like “eth0”. - BindToDevice, Both, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>); + BindToDevice, + Both, + libc::SOL_SOCKET, + libc::SO_BINDTODEVICE, + OsString<[u8; libc::IFNAMSIZ]> +); #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] #[allow(missing_docs)] // Not documented by Linux! - OriginalDst, GetOnly, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in); + OriginalDst, + GetOnly, + libc::SOL_IP, + libc::SO_ORIGINAL_DST, + libc::sockaddr_in +); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!( #[allow(missing_docs)] // Not documented by Linux! - Ip6tOriginalDst, GetOnly, libc::SOL_IPV6, libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6); + Ip6tOriginalDst, + GetOnly, + libc::SOL_IPV6, + libc::IP6T_SO_ORIGINAL_DST, + libc::sockaddr_in6 +); #[cfg(any(target_os = "linux"))] sockopt_impl!( /// Specifies exact type of timestamping information collected by the kernel /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - Timestamping, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPING, super::TimestampingFlag); + Timestamping, + Both, + libc::SOL_SOCKET, + libc::SO_TIMESTAMPING, + super::TimestampingFlag +); #[cfg(not(target_os = "haiku"))] sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. - ReceiveTimestamp, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool); + ReceiveTimestamp, + Both, + libc::SOL_SOCKET, + libc::SO_TIMESTAMP, + bool +); #[cfg(all(target_os = "linux"))] sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message. - ReceiveTimestampns, Both, libc::SOL_SOCKET, libc::SO_TIMESTAMPNS, bool); + ReceiveTimestampns, + Both, + libc::SOL_SOCKET, + libc::SO_TIMESTAMPNS, + bool +); #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Setting this boolean option enables transparent proxying on this socket. - IpTransparent, Both, libc::SOL_IP, libc::IP_TRANSPARENT, bool); + IpTransparent, + Both, + libc::SOL_IP, + libc::IP_TRANSPARENT, + bool +); #[cfg(target_os = "openbsd")] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Allows the socket to be bound to addresses which are not local to the /// machine, so it can be used to make a transparent proxy. - BindAny, Both, libc::SOL_SOCKET, libc::SO_BINDANY, bool); + BindAny, + Both, + libc::SOL_SOCKET, + libc::SO_BINDANY, + bool +); #[cfg(target_os = "freebsd")] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Can `bind(2)` to any address, even one not bound to any available /// network interface in the system. - BindAny, Both, libc::IPPROTO_IP, libc::IP_BINDANY, bool); + BindAny, + Both, + libc::IPPROTO_IP, + libc::IP_BINDANY, + bool +); #[cfg(target_os = "linux")] sockopt_impl!( /// Set the mark for each packet sent through this socket (similar to the /// netfilter MARK target but socket-based). - Mark, Both, libc::SOL_SOCKET, libc::SO_MARK, u32); + Mark, + Both, + libc::SOL_SOCKET, + libc::SO_MARK, + u32 +); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!( /// Enable or disable the receiving of the `SCM_CREDENTIALS` control /// message. - PassCred, Both, libc::SOL_SOCKET, libc::SO_PASSCRED, bool); + PassCred, + Both, + libc::SOL_SOCKET, + libc::SO_PASSCRED, + bool +); #[cfg(any(target_os = "freebsd", target_os = "linux"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// This option allows the caller to set the TCP congestion control /// algorithm to be used, on a per-socket basis. - TcpCongestion, Both, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>); + TcpCongestion, + Both, + libc::IPPROTO_TCP, + libc::TCP_CONGESTION, + OsString<[u8; TCP_CA_NAME_MAX]> +); #[cfg(any( target_os = "android", target_os = "ios", @@ -532,7 +743,12 @@ sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Pass an `IP_PKTINFO` ancillary message that contains a pktinfo /// structure that supplies some information about the incoming packet. - Ipv4PacketInfo, Both, libc::IPPROTO_IP, libc::IP_PKTINFO, bool); + Ipv4PacketInfo, + Both, + libc::IPPROTO_IP, + libc::IP_PKTINFO, + bool +); #[cfg(any( target_os = "android", target_os = "freebsd", @@ -547,7 +763,12 @@ sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// Set delivery of the `IPV6_PKTINFO` control message on incoming /// datagrams. - Ipv6RecvPacketInfo, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool); + Ipv6RecvPacketInfo, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_RECVPKTINFO, + bool +); #[cfg(any( target_os = "freebsd", target_os = "ios", @@ -560,7 +781,12 @@ sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The `recvmsg(2)` call returns a `struct sockaddr_dl` corresponding to /// the interface on which the packet was received. - Ipv4RecvIf, Both, libc::IPPROTO_IP, libc::IP_RECVIF, bool); + Ipv4RecvIf, + Both, + libc::IPPROTO_IP, + libc::IP_RECVIF, + bool +); #[cfg(any( target_os = "freebsd", target_os = "ios", @@ -573,72 +799,137 @@ sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The `recvmsg(2)` call will return the destination IP address for a UDP /// datagram. - Ipv4RecvDstAddr, Both, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool); + Ipv4RecvDstAddr, + Both, + libc::IPPROTO_IP, + libc::IP_RECVDSTADDR, + bool +); #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The `recvmsg(2)` call will return the destination IP address for a UDP /// datagram. - Ipv4OrigDstAddr, Both, libc::IPPROTO_IP, libc::IP_ORIGDSTADDR, bool); + Ipv4OrigDstAddr, + Both, + libc::IPPROTO_IP, + libc::IP_ORIGDSTADDR, + bool +); #[cfg(target_os = "linux")] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] #[allow(missing_docs)] // Not documented by Linux! - UdpGsoSegment, Both, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int); + UdpGsoSegment, + Both, + libc::SOL_UDP, + libc::UDP_SEGMENT, + libc::c_int +); #[cfg(target_os = "linux")] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] #[allow(missing_docs)] // Not documented by Linux! - UdpGroSegment, Both, libc::IPPROTO_UDP, libc::UDP_GRO, bool); + UdpGroSegment, + Both, + libc::IPPROTO_UDP, + libc::UDP_GRO, + bool +); #[cfg(target_os = "linux")] sockopt_impl!( /// Configures the behavior of time-based transmission of packets, for use /// with the `TxTime` control message. - TxTime, Both, libc::SOL_SOCKET, libc::SO_TXTIME, libc::sock_txtime); + TxTime, + Both, + libc::SOL_SOCKET, + libc::SO_TXTIME, + libc::sock_txtime +); #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] sockopt_impl!( /// Indicates that an unsigned 32-bit value ancillary message (cmsg) should /// be attached to received skbs indicating the number of packets dropped by /// the socket since its creation. - RxqOvfl, Both, libc::SOL_SOCKET, libc::SO_RXQ_OVFL, libc::c_int); + RxqOvfl, + Both, + libc::SOL_SOCKET, + libc::SO_RXQ_OVFL, + libc::c_int +); #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The socket is restricted to sending and receiving IPv6 packets only. - Ipv6V6Only, Both, libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, bool); + Ipv6V6Only, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_V6ONLY, + bool +); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!( /// Enable extended reliable error message passing. - Ipv4RecvErr, Both, libc::IPPROTO_IP, libc::IP_RECVERR, bool); + Ipv4RecvErr, + Both, + libc::IPPROTO_IP, + libc::IP_RECVERR, + bool +); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!( /// Control receiving of asynchronous error options. - Ipv6RecvErr, Both, libc::IPPROTO_IPV6, libc::IPV6_RECVERR, bool); + Ipv6RecvErr, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_RECVERR, + bool +); #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] sockopt_impl!( /// Set or retrieve the current time-to-live field that is used in every /// packet sent from this socket. - Ipv4Ttl, Both, libc::IPPROTO_IP, libc::IP_TTL, libc::c_int); + Ipv4Ttl, + Both, + libc::IPPROTO_IP, + libc::IP_TTL, + libc::c_int +); #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] sockopt_impl!( /// Set the unicast hop limit for the socket. - Ipv6Ttl, Both, libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS, libc::c_int); + Ipv6Ttl, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_UNICAST_HOPS, + libc::c_int +); #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] /// The `recvmsg(2)` call will return the destination IP address for a UDP /// datagram. - Ipv6OrigDstAddr, Both, libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR, bool); + Ipv6OrigDstAddr, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_ORIGDSTADDR, + bool +); #[cfg(any(target_os = "ios", target_os = "macos"))] sockopt_impl!( /// Set "don't fragment packet" flag on the IP packet. - IpDontFrag, Both, libc::IPPROTO_IP, libc::IP_DONTFRAG, bool); + IpDontFrag, + Both, + libc::IPPROTO_IP, + libc::IP_DONTFRAG, + bool +); #[cfg(any( target_os = "android", target_os = "ios", @@ -647,7 +938,12 @@ sockopt_impl!( ))] sockopt_impl!( /// Set "don't fragment packet" flag on the IPv6 packet. - Ipv6DontFrag, Both, libc::IPPROTO_IPV6, libc::IPV6_DONTFRAG, bool); + Ipv6DontFrag, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_DONTFRAG, + bool +); #[allow(missing_docs)] // Not documented by Linux! @@ -663,11 +959,13 @@ impl SetSockOpt for AlgSetAeadAuthSize { fn set(&self, fd: RawFd, val: &usize) -> Result<()> { unsafe { - let res = libc::setsockopt(fd, - libc::SOL_ALG, - libc::ALG_SET_AEAD_AUTHSIZE, - ::std::ptr::null(), - *val as libc::socklen_t); + let res = libc::setsockopt( + fd, + libc::SOL_ALG, + libc::ALG_SET_AEAD_AUTHSIZE, + ::std::ptr::null(), + *val as libc::socklen_t, + ); Errno::result(res).map(drop) } } @@ -687,16 +985,21 @@ impl Default for AlgSetKey { } #[cfg(any(target_os = "android", target_os = "linux"))] -impl SetSockOpt for AlgSetKey where T: AsRef<[u8]> + Clone { +impl SetSockOpt for AlgSetKey +where + T: AsRef<[u8]> + Clone, +{ type Val = T; fn set(&self, fd: RawFd, val: &T) -> Result<()> { unsafe { - let res = libc::setsockopt(fd, - libc::SOL_ALG, - libc::ALG_SET_KEY, - val.as_ref().as_ptr() as *const _, - val.as_ref().len() as libc::socklen_t); + let res = libc::setsockopt( + fd, + libc::SOL_ALG, + libc::ALG_SET_KEY, + val.as_ref().as_ptr() as *const _, + val.as_ref().len() as libc::socklen_t, + ); Errno::result(res).map(drop) } } @@ -757,7 +1060,11 @@ impl Get for GetStruct { } unsafe fn assume_init(self) -> T { - assert_eq!(self.len as usize, mem::size_of::(), "invalid getsockopt implementation"); + assert_eq!( + self.len as usize, + mem::size_of::(), + "invalid getsockopt implementation" + ); self.val.assume_init() } } @@ -804,7 +1111,11 @@ impl Get for GetBool { } unsafe fn assume_init(self) -> bool { - assert_eq!(self.len as usize, mem::size_of::(), "invalid getsockopt implementation"); + assert_eq!( + self.len as usize, + mem::size_of::(), + "invalid getsockopt implementation" + ); self.val.assume_init() != 0 } } @@ -816,7 +1127,9 @@ struct SetBool { impl<'a> Set<'a, bool> for SetBool { fn new(val: &'a bool) -> SetBool { - SetBool { val: i32::from(*val) } + SetBool { + val: i32::from(*val), + } } fn ffi_ptr(&self) -> *const c_void { @@ -851,7 +1164,11 @@ impl Get for GetU8 { } unsafe fn assume_init(self) -> u8 { - assert_eq!(self.len as usize, mem::size_of::(), "invalid getsockopt implementation"); + assert_eq!( + self.len as usize, + mem::size_of::(), + "invalid getsockopt implementation" + ); self.val.assume_init() } } @@ -898,7 +1215,11 @@ impl Get for GetUsize { } unsafe fn assume_init(self) -> usize { - assert_eq!(self.len as usize, mem::size_of::(), "invalid getsockopt implementation"); + assert_eq!( + self.len as usize, + mem::size_of::(), + "invalid getsockopt implementation" + ); self.val.assume_init() as usize } } @@ -958,7 +1279,9 @@ struct SetOsString<'a> { impl<'a> Set<'a, OsString> for SetOsString<'a> { fn new(val: &'a OsString) -> SetOsString { - SetOsString { val: val.as_os_str() } + SetOsString { + val: val.as_os_str(), + } } fn ffi_ptr(&self) -> *const c_void { @@ -970,7 +1293,6 @@ impl<'a> Set<'a, OsString> for SetOsString<'a> { } } - #[cfg(test)] mod test { #[cfg(any(target_os = "android", target_os = "linux"))] @@ -978,7 +1300,13 @@ mod test { fn can_get_peercred_on_unix_socket() { use super::super::*; - let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap(); + let (a, b) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); let a_cred = getsockopt(a, super::PeerCredentials).unwrap(); let b_cred = getsockopt(b, super::PeerCredentials).unwrap(); assert_eq!(a_cred, b_cred); @@ -990,7 +1318,13 @@ mod test { use super::super::*; use crate::unistd::close; - let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap(); + let (a, b) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); let a_type = getsockopt(a, super::SockType).unwrap(); assert_eq!(a_type, SockType::Stream); close(a).unwrap(); @@ -1002,20 +1336,31 @@ mod test { use super::super::*; use crate::unistd::close; - let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap(); + let s = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .unwrap(); let s_type = getsockopt(s, super::SockType).unwrap(); assert_eq!(s_type, SockType::Datagram); close(s).unwrap(); } - #[cfg(any(target_os = "freebsd", - target_os = "linux"))] + #[cfg(any(target_os = "freebsd", target_os = "linux"))] #[test] fn can_get_listen_on_tcp_socket() { use super::super::*; use crate::unistd::close; - let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); + let s = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + None, + ) + .unwrap(); let s_listening = getsockopt(s, super::AcceptConn).unwrap(); assert!(!s_listening); listen(s, 10).unwrap(); @@ -1023,5 +1368,4 @@ mod test { assert!(s_listening2); close(s).unwrap(); } - } diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 8b7627d5bc..94be4107bc 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -1,4 +1,3 @@ -pub use libc::{dev_t, mode_t}; #[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] pub use libc::c_uint; #[cfg(any( @@ -8,13 +7,14 @@ pub use libc::c_uint; ))] pub use libc::c_ulong; pub use libc::stat as FileStat; +pub use libc::{dev_t, mode_t}; -use crate::{Result, NixPath, errno::Errno}; #[cfg(not(target_os = "redox"))] -use crate::fcntl::{AtFlags, at_rawfd}; +use crate::fcntl::{at_rawfd, AtFlags}; +use crate::sys::time::{TimeSpec, TimeVal}; +use crate::{errno::Errno, NixPath, Result}; use std::mem; use std::os::unix::io::RawFd; -use crate::sys::time::{TimeSpec, TimeVal}; libc_bitflags!( /// "File type" flags for `mknod` and related functions. @@ -51,7 +51,7 @@ libc_bitflags! { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os="openbsd"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))] pub type type_of_file_flag = c_uint; #[cfg(any( target_os = "netbsd", @@ -156,7 +156,12 @@ libc_bitflags! { } /// Create a special or ordinary file, by pathname. -pub fn mknod(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> { +pub fn mknod( + path: &P, + kind: SFlag, + perm: Mode, + dev: dev_t, +) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) })?; @@ -165,7 +170,12 @@ pub fn mknod(path: &P, kind: SFlag, perm: Mode, dev: dev_t) } /// Create a special or ordinary file, relative to a given directory. -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))] +#[cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "haiku" +)))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn mknodat( dirfd: RawFd, @@ -175,7 +185,12 @@ pub fn mknodat( dev: dev_t, ) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { - libc::mknodat(dirfd, cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) + libc::mknodat( + dirfd, + cstr.as_ptr(), + kind.bits | perm.bits() as mode_t, + dev, + ) })?; Errno::result(res).map(drop) @@ -184,24 +199,22 @@ pub fn mknodat( #[cfg(target_os = "linux")] #[cfg_attr(docsrs, doc(cfg(all())))] pub const fn major(dev: dev_t) -> u64 { - ((dev >> 32) & 0xffff_f000) | - ((dev >> 8) & 0x0000_0fff) + ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff) } #[cfg(target_os = "linux")] #[cfg_attr(docsrs, doc(cfg(all())))] pub const fn minor(dev: dev_t) -> u64 { - ((dev >> 12) & 0xffff_ff00) | - ((dev ) & 0x0000_00ff) + ((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff) } #[cfg(target_os = "linux")] #[cfg_attr(docsrs, doc(cfg(all())))] pub const fn makedev(major: u64, minor: u64) -> dev_t { - ((major & 0xffff_f000) << 32) | - ((major & 0x0000_0fff) << 8) | - ((minor & 0xffff_ff00) << 12) | - (minor & 0x0000_00ff) + ((major & 0xffff_f000) << 32) + | ((major & 0x0000_0fff) << 8) + | ((minor & 0xffff_ff00) << 12) + | (minor & 0x0000_00ff) } pub fn umask(mode: Mode) -> Mode { @@ -211,28 +224,24 @@ pub fn umask(mode: Mode) -> Mode { pub fn stat(path: &P) -> Result { let mut dst = mem::MaybeUninit::uninit(); - let res = path.with_nix_path(|cstr| { - unsafe { - libc::stat(cstr.as_ptr(), dst.as_mut_ptr()) - } + let res = path.with_nix_path(|cstr| unsafe { + libc::stat(cstr.as_ptr(), dst.as_mut_ptr()) })?; Errno::result(res)?; - Ok(unsafe{dst.assume_init()}) + Ok(unsafe { dst.assume_init() }) } pub fn lstat(path: &P) -> Result { let mut dst = mem::MaybeUninit::uninit(); - let res = path.with_nix_path(|cstr| { - unsafe { - libc::lstat(cstr.as_ptr(), dst.as_mut_ptr()) - } + let res = path.with_nix_path(|cstr| unsafe { + libc::lstat(cstr.as_ptr(), dst.as_mut_ptr()) })?; Errno::result(res)?; - Ok(unsafe{dst.assume_init()}) + Ok(unsafe { dst.assume_init() }) } pub fn fstat(fd: RawFd) -> Result { @@ -241,20 +250,29 @@ pub fn fstat(fd: RawFd) -> Result { Errno::result(res)?; - Ok(unsafe{dst.assume_init()}) + Ok(unsafe { dst.assume_init() }) } #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn fstatat(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result { +pub fn fstatat( + dirfd: RawFd, + pathname: &P, + f: AtFlags, +) -> Result { let mut dst = mem::MaybeUninit::uninit(); - let res = pathname.with_nix_path(|cstr| { - unsafe { libc::fstatat(dirfd, cstr.as_ptr(), dst.as_mut_ptr(), f.bits() as libc::c_int) } + let res = pathname.with_nix_path(|cstr| unsafe { + libc::fstatat( + dirfd, + cstr.as_ptr(), + dst.as_mut_ptr(), + f.bits() as libc::c_int, + ) })?; Errno::result(res)?; - Ok(unsafe{dst.assume_init()}) + Ok(unsafe { dst.assume_init() }) } /// Change the file permission bits of the file specified by a file descriptor. @@ -299,11 +317,10 @@ pub fn fchmodat( mode: Mode, flag: FchmodatFlags, ) -> Result<()> { - let atflag = - match flag { - FchmodatFlags::FollowSymlink => AtFlags::empty(), - FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, - }; + let atflag = match flag { + FchmodatFlags::FollowSymlink => AtFlags::empty(), + FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, + }; let res = path.with_nix_path(|cstr| unsafe { libc::fchmodat( at_rawfd(dirfd), @@ -326,7 +343,11 @@ pub fn fchmodat( /// # References /// /// [utimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). -pub fn utimes(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> { +pub fn utimes( + path: &P, + atime: &TimeVal, + mtime: &TimeVal, +) -> Result<()> { let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; let res = path.with_nix_path(|cstr| unsafe { libc::utimes(cstr.as_ptr(), ×[0]) @@ -345,14 +366,20 @@ pub fn utimes(path: &P, atime: &TimeVal, mtime: &TimeVal) - /// # References /// /// [lutimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html). -#[cfg(any(target_os = "linux", - target_os = "haiku", - target_os = "ios", - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd"))] +#[cfg(any( + target_os = "linux", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "netbsd" +))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn lutimes(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> { +pub fn lutimes( + path: &P, + atime: &TimeVal, + mtime: &TimeVal, +) -> Result<()> { let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; let res = path.with_nix_path(|cstr| unsafe { libc::lutimes(cstr.as_ptr(), ×[0]) @@ -405,13 +432,12 @@ pub fn utimensat( path: &P, atime: &TimeSpec, mtime: &TimeSpec, - flag: UtimensatFlags + flag: UtimensatFlags, ) -> Result<()> { - let atflag = - match flag { - UtimensatFlags::FollowSymlink => AtFlags::empty(), - UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, - }; + let atflag = match flag { + UtimensatFlags::FollowSymlink => AtFlags::empty(), + UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, + }; let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()]; let res = path.with_nix_path(|cstr| unsafe { libc::utimensat( @@ -427,9 +453,13 @@ pub fn utimensat( #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn mkdirat(fd: RawFd, path: &P, mode: Mode) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) } +pub fn mkdirat( + fd: RawFd, + path: &P, + mode: Mode, +) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) })?; Errno::result(res).map(drop) diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 9c28bc2120..9be8ca6667 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -1,25 +1,28 @@ //! Get filesystem statistics, non-portably //! //! See [`statvfs`](crate::sys::statvfs) for a portable alternative. +#[cfg(not(any(target_os = "linux", target_os = "android")))] +use std::ffi::CStr; use std::fmt::{self, Debug}; use std::mem; use std::os::unix::io::AsRawFd; -#[cfg(not(any(target_os = "linux", target_os = "android")))] -use std::ffi::CStr; use cfg_if::cfg_if; -use crate::{NixPath, Result, errno::Errno}; -#[cfg(all(feature = "mount", - any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd") +#[cfg(all( + feature = "mount", + any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ) ))] use crate::mount::MntFlags; #[cfg(target_os = "linux")] use crate::sys::statvfs::FsFlags; +use crate::{errno::Errno, NixPath, Result}; /// Identifies a mounted file system #[cfg(target_os = "android")] @@ -65,7 +68,14 @@ type fs_type_t = libc::c_uint; type fs_type_t = libc::c_ulong; #[cfg(all(target_os = "linux", target_env = "uclibc"))] type fs_type_t = libc::c_int; -#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl", target_env = "uclibc"))))] +#[cfg(all( + target_os = "linux", + not(any( + target_arch = "s390x", + target_env = "musl", + target_env = "uclibc" + )) +))] type fs_type_t = libc::__fsword_t; /// Describes the file system type as known by the operating system. @@ -74,7 +84,10 @@ type fs_type_t = libc::__fsword_t; target_os = "android", all(target_os = "linux", target_arch = "s390x"), all(target_os = "linux", target_env = "musl"), - all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))), + all( + target_os = "linux", + not(any(target_arch = "s390x", target_env = "musl")) + ), ))] #[derive(Eq, Copy, Clone, PartialEq, Debug)] pub struct FsType(pub fs_type_t); @@ -83,31 +96,38 @@ pub struct FsType(pub fs_type_t); // can't very well document them here. #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC as fs_type_t); +pub const ADFS_SUPER_MAGIC: FsType = + FsType(libc::ADFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC as fs_type_t); +pub const AFFS_SUPER_MAGIC: FsType = + FsType(libc::AFFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const AFS_SUPER_MAGIC: FsType = FsType(libc::AFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const AUTOFS_SUPER_MAGIC: FsType = FsType(libc::AUTOFS_SUPER_MAGIC as fs_type_t); +pub const AUTOFS_SUPER_MAGIC: FsType = + FsType(libc::AUTOFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const BPF_FS_MAGIC: FsType = FsType(libc::BPF_FS_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const BTRFS_SUPER_MAGIC: FsType = FsType(libc::BTRFS_SUPER_MAGIC as fs_type_t); +pub const BTRFS_SUPER_MAGIC: FsType = + FsType(libc::BTRFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t); +pub const CGROUP2_SUPER_MAGIC: FsType = + FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t); +pub const CGROUP_SUPER_MAGIC: FsType = + FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC as fs_type_t); +pub const CODA_SUPER_MAGIC: FsType = + FsType(libc::CODA_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t); @@ -116,64 +136,82 @@ pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t); pub const DEBUGFS_MAGIC: FsType = FsType(libc::DEBUGFS_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const DEVPTS_SUPER_MAGIC: FsType = FsType(libc::DEVPTS_SUPER_MAGIC as fs_type_t); +pub const DEVPTS_SUPER_MAGIC: FsType = + FsType(libc::DEVPTS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const ECRYPTFS_SUPER_MAGIC: FsType = FsType(libc::ECRYPTFS_SUPER_MAGIC as fs_type_t); +pub const ECRYPTFS_SUPER_MAGIC: FsType = + FsType(libc::ECRYPTFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC as fs_type_t); +pub const EXT2_SUPER_MAGIC: FsType = + FsType(libc::EXT2_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC as fs_type_t); +pub const EXT3_SUPER_MAGIC: FsType = + FsType(libc::EXT3_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC as fs_type_t); +pub const EXT4_SUPER_MAGIC: FsType = + FsType(libc::EXT4_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const F2FS_SUPER_MAGIC: FsType = FsType(libc::F2FS_SUPER_MAGIC as fs_type_t); +pub const F2FS_SUPER_MAGIC: FsType = + FsType(libc::F2FS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const FUSE_SUPER_MAGIC: FsType = FsType(libc::FUSE_SUPER_MAGIC as fs_type_t); +pub const FUSE_SUPER_MAGIC: FsType = + FsType(libc::FUSE_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const FUTEXFS_SUPER_MAGIC: FsType = FsType(libc::FUTEXFS_SUPER_MAGIC as fs_type_t); +pub const FUTEXFS_SUPER_MAGIC: FsType = + FsType(libc::FUTEXFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const HOSTFS_SUPER_MAGIC: FsType = FsType(libc::HOSTFS_SUPER_MAGIC as fs_type_t); +pub const HOSTFS_SUPER_MAGIC: FsType = + FsType(libc::HOSTFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC as fs_type_t); +pub const HPFS_SUPER_MAGIC: FsType = + FsType(libc::HPFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t); +pub const ISOFS_SUPER_MAGIC: FsType = + FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t); +pub const JFFS2_SUPER_MAGIC: FsType = + FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t); +pub const MINIX2_SUPER_MAGIC2: FsType = + FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t); +pub const MINIX2_SUPER_MAGIC: FsType = + FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const MINIX3_SUPER_MAGIC: FsType = FsType(libc::MINIX3_SUPER_MAGIC as fs_type_t); +pub const MINIX3_SUPER_MAGIC: FsType = + FsType(libc::MINIX3_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t); +pub const MINIX_SUPER_MAGIC2: FsType = + FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC as fs_type_t); +pub const MINIX_SUPER_MAGIC: FsType = + FsType(libc::MINIX_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t); +pub const MSDOS_SUPER_MAGIC: FsType = + FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t); @@ -182,34 +220,44 @@ pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t); pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const NILFS_SUPER_MAGIC: FsType = FsType(libc::NILFS_SUPER_MAGIC as fs_type_t); +pub const NILFS_SUPER_MAGIC: FsType = + FsType(libc::NILFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const OCFS2_SUPER_MAGIC: FsType = FsType(libc::OCFS2_SUPER_MAGIC as fs_type_t); +pub const OCFS2_SUPER_MAGIC: FsType = + FsType(libc::OCFS2_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t); +pub const OPENPROM_SUPER_MAGIC: FsType = + FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const OVERLAYFS_SUPER_MAGIC: FsType = FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t); +pub const OVERLAYFS_SUPER_MAGIC: FsType = + FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC as fs_type_t); +pub const PROC_SUPER_MAGIC: FsType = + FsType(libc::PROC_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC as fs_type_t); +pub const QNX4_SUPER_MAGIC: FsType = + FsType(libc::QNX4_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const QNX6_SUPER_MAGIC: FsType = FsType(libc::QNX6_SUPER_MAGIC as fs_type_t); +pub const QNX6_SUPER_MAGIC: FsType = + FsType(libc::QNX6_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const RDTGROUP_SUPER_MAGIC: FsType = FsType(libc::RDTGROUP_SUPER_MAGIC as fs_type_t); +pub const RDTGROUP_SUPER_MAGIC: FsType = + FsType(libc::RDTGROUP_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t); +pub const REISERFS_SUPER_MAGIC: FsType = + FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const SECURITYFS_MAGIC: FsType = FsType(libc::SECURITYFS_MAGIC as fs_type_t); +pub const SECURITYFS_MAGIC: FsType = + FsType(libc::SECURITYFS_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const SELINUX_MAGIC: FsType = FsType(libc::SELINUX_MAGIC as fs_type_t); @@ -233,14 +281,19 @@ pub const TRACEFS_MAGIC: FsType = FsType(libc::TRACEFS_MAGIC as fs_type_t); pub const UDF_SUPER_MAGIC: FsType = FsType(libc::UDF_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t); +pub const USBDEVICE_SUPER_MAGIC: FsType = + FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] -pub const XENFS_SUPER_MAGIC: FsType = FsType(libc::XENFS_SUPER_MAGIC as fs_type_t); +pub const XENFS_SUPER_MAGIC: FsType = + FsType(libc::XENFS_SUPER_MAGIC as fs_type_t); #[cfg(any(target_os = "linux", target_os = "android"))] #[allow(missing_docs)] pub const NSFS_MAGIC: FsType = FsType(libc::NSFS_MAGIC as fs_type_t); -#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "musl")))] +#[cfg(all( + any(target_os = "linux", target_os = "android"), + not(target_env = "musl") +))] #[allow(missing_docs)] pub const XFS_SUPER_MAGIC: FsType = FsType(libc::XFS_SUPER_MAGIC as fs_type_t); @@ -297,7 +350,14 @@ impl Statfs { } /// Optimal transfer block size - #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl", target_env = "uclibc"))))] + #[cfg(all( + target_os = "linux", + not(any( + target_arch = "s390x", + target_env = "musl", + target_env = "uclibc" + )) + ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn optimal_transfer_size(&self) -> libc::__fsword_t { self.0.f_bsize @@ -357,7 +417,14 @@ impl Statfs { /// Size of a block // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471 - #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl", target_env = "uclibc"))))] + #[cfg(all( + target_os = "linux", + not(any( + target_arch = "s390x", + target_env = "musl", + target_env = "uclibc" + )) + ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn block_size(&self) -> libc::__fsword_t { self.0.f_bsize @@ -385,15 +452,18 @@ impl Statfs { } /// Get the mount flags - #[cfg(all(feature = "mount", - any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd") + #[cfg(all( + feature = "mount", + any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ) ))] #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(clippy::unnecessary_cast)] // Not unnecessary on all arches + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all arches pub fn flags(&self) -> MntFlags { MntFlags::from_bits_truncate(self.0.f_flags as i32) } @@ -436,7 +506,14 @@ impl Statfs { } /// Maximum length of filenames - #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl", target_env = "uclibc"))))] + #[cfg(all( + target_os = "linux", + not(any( + target_arch = "s390x", + target_env = "musl", + target_env = "uclibc" + )) + ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn maximum_name_length(&self) -> libc::__fsword_t { self.0.f_namelen @@ -622,16 +699,18 @@ impl Debug for Statfs { ds.field("files", &self.files()); ds.field("files_free", &self.files_free()); ds.field("filesystem_id", &self.filesystem_id()); - #[cfg(all(feature = "mount", - any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd") + #[cfg(all( + feature = "mount", + any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ) ))] ds.field("flags", &self.flags()); ds.finish() - } } @@ -646,7 +725,9 @@ impl Debug for Statfs { pub fn statfs(path: &P) -> Result { unsafe { let mut stat = mem::MaybeUninit::::uninit(); - let res = path.with_nix_path(|path| LIBC_STATFS(path.as_ptr(), stat.as_mut_ptr()))?; + let res = path.with_nix_path(|path| { + LIBC_STATFS(path.as_ptr(), stat.as_mut_ptr()) + })?; Errno::result(res).map(|_| Statfs(stat.assume_init())) } } diff --git a/src/sys/statvfs.rs b/src/sys/statvfs.rs index 38b1fdcc50..8de369f421 100644 --- a/src/sys/statvfs.rs +++ b/src/sys/statvfs.rs @@ -7,7 +7,7 @@ use std::os::unix::io::AsRawFd; use libc::{self, c_ulong}; -use crate::{Result, NixPath, errno::Errno}; +use crate::{errno::Errno, NixPath, Result}; #[cfg(not(target_os = "redox"))] libc_bitflags!( @@ -130,7 +130,6 @@ impl Statvfs { pub fn name_max(&self) -> c_ulong { self.0.f_namemax } - } /// Return a `Statvfs` object with information about the `path` @@ -138,9 +137,9 @@ pub fn statvfs(path: &P) -> Result { unsafe { Errno::clear(); let mut stat = mem::MaybeUninit::::uninit(); - let res = path.with_nix_path(|path| + let res = path.with_nix_path(|path| { libc::statvfs(path.as_ptr(), stat.as_mut_ptr()) - )?; + })?; Errno::result(res).map(|_| Statvfs(stat.assume_init())) } @@ -158,8 +157,8 @@ pub fn fstatvfs(fd: &T) -> Result { #[cfg(test)] mod test { - use std::fs::File; use crate::sys::statvfs::*; + use std::fs::File; #[test] fn statvfs_call() { diff --git a/src/sys/termios.rs b/src/sys/termios.rs index 4ff4e674da..fba2cd8268 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -85,12 +85,28 @@ //! //! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`: //! -#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "macos", target_os = "netbsd", target_os = "openbsd"), - doc = " ```rust,ignore")] -#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "macos", target_os = "netbsd", target_os = "openbsd")), - doc = " ```rust")] +#![cfg_attr( + any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ), + doc = " ```rust,ignore" +)] +#![cfg_attr( + not(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + )), + doc = " ```rust" +)] //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; @@ -102,12 +118,28 @@ //! //! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s: //! -#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "macos", target_os = "netbsd", target_os = "openbsd"), - doc = " ```rust")] -#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "macos", target_os = "netbsd", target_os = "openbsd")), - doc = " ```rust,ignore")] +#![cfg_attr( + any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ), + doc = " ```rust" +)] +#![cfg_attr( + not(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + )), + doc = " ```rust,ignore" +)] //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; @@ -119,12 +151,28 @@ //! //! It's trivial to convert from a `BaudRate` to a `u32` on BSDs: //! -#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "macos", target_os = "netbsd", target_os = "openbsd"), - doc = " ```rust")] -#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "macos", target_os = "netbsd", target_os = "openbsd")), - doc = " ```rust,ignore")] +#![cfg_attr( + any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ), + doc = " ```rust" +)] +#![cfg_attr( + not(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + )), + doc = " ```rust,ignore" +)] //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; @@ -137,12 +185,28 @@ //! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support) //! by specifying baud rates directly using `u32`s: //! -#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "macos", target_os = "netbsd", target_os = "openbsd"), - doc = " ```rust")] -#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "macos", target_os = "netbsd", target_os = "openbsd")), - doc = " ```rust,ignore")] +#![cfg_attr( + any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ), + doc = " ```rust" +)] +#![cfg_attr( + not(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + )), + doc = " ```rust,ignore" +)] //! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios}; //! # fn main() { //! # let mut t: Termios = unsafe { std::mem::zeroed() }; @@ -151,9 +215,9 @@ //! cfsetspeed(&mut t, 9600u32); //! # } //! ``` -use cfg_if::cfg_if; -use crate::Result; use crate::errno::Errno; +use crate::Result; +use cfg_if::cfg_if; use libc::{self, c_int, tcflag_t}; use std::cell::{Ref, RefCell}; use std::convert::From; @@ -182,10 +246,7 @@ pub struct Termios { /// Control characters (see `termios.c_cc` documentation) pub control_chars: [libc::cc_t; NCCS], /// Line discipline (see `termios.c_line` documentation) - #[cfg(any( - target_os = "linux", - target_os = "android", - ))] + #[cfg(any(target_os = "linux", target_os = "android",))] pub line_discipline: libc::cc_t, /// Line discipline (see `termios.c_line` documentation) #[cfg(target_os = "haiku")] @@ -287,7 +348,7 @@ impl From for libc::termios { } } -libc_enum!{ +libc_enum! { /// Baud rates supported by the system. /// /// For the BSDs, arbitrary baud rates can be specified by using `u32`s directly instead of this @@ -402,12 +463,14 @@ libc_enum!{ impl TryFrom } -#[cfg(any(target_os = "freebsd", - target_os = "dragonfly", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] impl From for u32 { fn from(b: BaudRate) -> u32 { b as u32 @@ -421,7 +484,6 @@ impl From for u8 { } } - // TODO: Add TCSASOFT, which will require treating this as a bitfield. libc_enum! { /// Specify when a port configuration change should occur. @@ -538,21 +600,26 @@ libc_enum! { } } -#[cfg(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris"))] +#[cfg(any( + all(target_os = "linux", target_arch = "sparc64"), + target_os = "illumos", + target_os = "solaris" +))] impl SpecialCharacterIndices { pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF; pub const VTIME: SpecialCharacterIndices = SpecialCharacterIndices::VEOL; } pub use libc::NCCS; -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" +))] #[cfg_attr(docsrs, doc(cfg(all())))] pub use libc::_POSIX_VDISABLE; @@ -922,7 +989,7 @@ libc_bitflags! { } } -cfg_if!{ +cfg_if! { if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", @@ -1094,7 +1161,10 @@ pub fn tcgetattr(fd: RawFd) -> Result { /// *any* of the parameters were successfully set, not only if all were set successfully. pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> { let inner_termios = termios.get_libc_termios(); - Errno::result(unsafe { libc::tcsetattr(fd, actions as c_int, &*inner_termios) }).map(drop) + Errno::result(unsafe { + libc::tcsetattr(fd, actions as c_int, &*inner_termios) + }) + .map(drop) } /// Block until all output data is written (see diff --git a/src/sys/timer.rs b/src/sys/timer.rs index dac5e9b599..e1a34051e8 100644 --- a/src/sys/timer.rs +++ b/src/sys/timer.rs @@ -72,7 +72,8 @@ impl Timer { /// of the signal and its handler are defined by the passed `sigevent`. #[doc(alias("timer_create"))] pub fn new(clockid: ClockId, mut sigevent: SigEvent) -> Result { - let mut timer_id: mem::MaybeUninit = mem::MaybeUninit::uninit(); + let mut timer_id: mem::MaybeUninit = + mem::MaybeUninit::uninit(); Errno::result(unsafe { libc::timer_create( clockid.as_raw(), @@ -124,7 +125,11 @@ impl Timer { /// Note: Setting a one shot alarm with a 0s TimeSpec disable the alarm /// altogether. #[doc(alias("timer_settime"))] - pub fn set(&mut self, expiration: Expiration, flags: TimerSetTimeFlags) -> Result<()> { + pub fn set( + &mut self, + expiration: Expiration, + flags: TimerSetTimeFlags, + ) -> Result<()> { let timerspec: TimerSpec = expiration.into(); Errno::result(unsafe { libc::timer_settime( @@ -141,7 +146,10 @@ impl Timer { #[doc(alias("timer_gettime"))] pub fn get(&self) -> Result> { let mut timerspec = TimerSpec::none(); - Errno::result(unsafe { libc::timer_gettime(self.0, timerspec.as_mut()) }).map(|_| { + Errno::result(unsafe { + libc::timer_gettime(self.0, timerspec.as_mut()) + }) + .map(|_| { if timerspec.as_ref().it_interval.tv_sec == 0 && timerspec.as_ref().it_interval.tv_nsec == 0 && timerspec.as_ref().it_value.tv_sec == 0 diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs index b57d33c3ba..a35fc927f4 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -94,8 +94,10 @@ impl TimerFd { /// NONBLOCK). The underlying fd will be closed on drop. #[doc(alias("timerfd_create"))] pub fn new(clockid: ClockId, flags: TimerFlags) -> Result { - Errno::result(unsafe { libc::timerfd_create(clockid as i32, flags.bits()) }) - .map(|fd| Self { fd }) + Errno::result(unsafe { + libc::timerfd_create(clockid as i32, flags.bits()) + }) + .map(|fd| Self { fd }) } /// Sets a new alarm on the timer. @@ -135,7 +137,11 @@ impl TimerFd { /// Note: Setting a one shot alarm with a 0s TimeSpec disables the alarm /// altogether. #[doc(alias("timerfd_settime"))] - pub fn set(&self, expiration: Expiration, flags: TimerSetTimeFlags) -> Result<()> { + pub fn set( + &self, + expiration: Expiration, + flags: TimerSetTimeFlags, + ) -> Result<()> { let timerspec: TimerSpec = expiration.into(); Errno::result(unsafe { libc::timerfd_settime( @@ -152,7 +158,10 @@ impl TimerFd { #[doc(alias("timerfd_gettime"))] pub fn get(&self) -> Result> { let mut timerspec = TimerSpec::none(); - Errno::result(unsafe { libc::timerfd_gettime(self.fd, timerspec.as_mut()) }).map(|_| { + Errno::result(unsafe { + libc::timerfd_gettime(self.fd, timerspec.as_mut()) + }) + .map(|_| { if timerspec.as_ref().it_interval.tv_sec == 0 && timerspec.as_ref().it_interval.tv_nsec == 0 && timerspec.as_ref().it_value.tv_sec == 0 diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 7cddb37265..b31c3068a7 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -1,8 +1,8 @@ //! Vectored I/O -use crate::Result; use crate::errno::Errno; -use libc::{self, c_int, c_void, size_t, off_t}; +use crate::Result; +use libc::{self, c_int, c_void, off_t, size_t}; use std::io::{IoSlice, IoSliceMut}; use std::marker::PhantomData; use std::os::unix::io::RawFd; @@ -12,13 +12,15 @@ use std::os::unix::io::RawFd; /// See also [writev(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html) pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result { // SAFETY: to quote the documentation for `IoSlice`: - // - // [IoSlice] is semantically a wrapper around a &[u8], but is + // + // [IoSlice] is semantically a wrapper around a &[u8], but is // guaranteed to be ABI compatible with the iovec type on Unix // platforms. // // Because it is ABI compatible, a pointer cast here is valid - let res = unsafe { libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; + 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) } @@ -28,7 +30,9 @@ pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result { /// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html) pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result { // SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec - let res = unsafe { libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; + let res = unsafe { + libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) + }; Errno::result(res).map(|r| r as usize) } @@ -41,15 +45,18 @@ pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result { /// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], - offset: off_t) -> Result { - +pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result { #[cfg(target_env = "uclibc")] let offset = offset as libc::off64_t; // uclibc doesn't use off_t // SAFETY: same as in writev() let res = unsafe { - libc::pwritev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset) + libc::pwritev( + fd, + iov.as_ptr() as *const libc::iovec, + iov.len() as c_int, + offset, + ) }; Errno::result(res).map(|r| r as usize) @@ -64,14 +71,22 @@ pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], /// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn preadv(fd: RawFd, iov: &mut [IoSliceMut<'_>], - offset: off_t) -> Result { +pub fn preadv( + fd: RawFd, + iov: &mut [IoSliceMut<'_>], + offset: off_t, +) -> Result { #[cfg(target_env = "uclibc")] let offset = offset as libc::off64_t; // uclibc doesn't use off_t // SAFETY: same as in readv() let res = unsafe { - libc::preadv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset) + libc::preadv( + fd, + iov.as_ptr() as *const libc::iovec, + iov.len() as c_int, + offset, + ) }; Errno::result(res).map(|r| r as usize) @@ -83,8 +98,12 @@ pub fn preadv(fd: RawFd, iov: &mut [IoSliceMut<'_>], // 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, - offset) + libc::pwrite( + fd, + buf.as_ptr() as *const c_void, + buf.len() as size_t, + offset, + ) }; Errno::result(res).map(|r| r as usize) @@ -94,10 +113,14 @@ pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result { /// /// 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{ +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, - offset) + libc::pread( + fd, + buf.as_mut_ptr() as *mut c_void, + buf.len() as size_t, + offset, + ) }; Errno::result(res).map(|r| r as usize) @@ -151,9 +174,7 @@ impl IoVec { use std::slice; unsafe { - slice::from_raw_parts( - self.0.iov_base as *const u8, - self.0.iov_len) + slice::from_raw_parts(self.0.iov_base as *const u8, self.0.iov_len) } } } @@ -161,30 +182,30 @@ impl IoVec { #[allow(deprecated)] impl<'a> IoVec<&'a [u8]> { /// Create an `IoVec` from a Rust slice. - #[deprecated( - since = "0.24.0", - note = "Use `IoSlice::new` instead" - )] + #[deprecated(since = "0.24.0", note = "Use `IoSlice::new` instead")] pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> { - IoVec(libc::iovec { - iov_base: buf.as_ptr() as *mut c_void, - iov_len: buf.len() as size_t, - }, PhantomData) + IoVec( + libc::iovec { + iov_base: buf.as_ptr() as *mut c_void, + iov_len: buf.len() as size_t, + }, + PhantomData, + ) } } #[allow(deprecated)] impl<'a> IoVec<&'a mut [u8]> { /// Create an `IoVec` from a mutable Rust slice. - #[deprecated( - since = "0.24.0", - note = "Use `IoSliceMut::new` instead" - )] + #[deprecated(since = "0.24.0", note = "Use `IoSliceMut::new` instead")] 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, - iov_len: buf.len() as size_t, - }, PhantomData) + IoVec( + libc::iovec { + iov_base: buf.as_ptr() as *mut c_void, + iov_len: buf.len() as size_t, + }, + PhantomData, + ) } } diff --git a/src/sys/utsname.rs b/src/sys/utsname.rs index 0448cb2990..b48ed9f45e 100644 --- a/src/sys/utsname.rs +++ b/src/sys/utsname.rs @@ -1,9 +1,9 @@ //! Get system identification +use crate::{Errno, Result}; +use libc::c_char; +use std::ffi::OsStr; use std::mem; use std::os::unix::ffi::OsStrExt; -use std::ffi::OsStr; -use libc::c_char; -use crate::{Errno, Result}; /// Describes the running system. Return type of [`uname`]. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -53,10 +53,12 @@ pub fn uname() -> Result { } fn cast_and_trim(slice: &[c_char]) -> &OsStr { - let length = slice.iter().position(|&byte| byte == 0).unwrap_or(slice.len()); - let bytes = unsafe { - std::slice::from_raw_parts(slice.as_ptr().cast(), length) - }; + let length = slice + .iter() + .position(|&byte| byte == 0) + .unwrap_or(slice.len()); + let bytes = + unsafe { std::slice::from_raw_parts(slice.as_ptr().cast(), length) }; OsStr::from_bytes(bytes) } diff --git a/src/sys/wait.rs b/src/sys/wait.rs index 5fb2075fd9..b6524e8661 100644 --- a/src/sys/wait.rs +++ b/src/sys/wait.rs @@ -135,7 +135,9 @@ impl WaitStatus { pub fn pid(&self) -> Option { use self::WaitStatus::*; match *self { - Exited(p, _) | Signaled(p, _, _) | Stopped(p, _) | Continued(p) => Some(p), + Exited(p, _) | Signaled(p, _, _) | Stopped(p, _) | Continued(p) => { + Some(p) + } StillAlive => None, #[cfg(any(target_os = "android", target_os = "linux"))] PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p), @@ -274,7 +276,9 @@ impl WaitStatus { Signal::try_from(si_status)?, siginfo.si_code == libc::CLD_DUMPED, ), - libc::CLD_STOPPED => WaitStatus::Stopped(pid, Signal::try_from(si_status)?), + libc::CLD_STOPPED => { + WaitStatus::Stopped(pid, Signal::try_from(si_status)?) + } libc::CLD_CONTINUED => WaitStatus::Continued(pid), #[cfg(any(target_os = "android", target_os = "linux"))] libc::CLD_TRAPPED => { @@ -298,7 +302,10 @@ 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 { +pub fn waitpid>>( + pid: P, + options: Option, +) -> Result { use self::WaitStatus::*; let mut status: i32 = 0; diff --git a/src/time.rs b/src/time.rs index 6a385b90bd..2e03c46cf4 100644 --- a/src/time.rs +++ b/src/time.rs @@ -85,7 +85,8 @@ impl ClockId { target_os = "linux" ))] #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM); + pub const CLOCK_BOOTTIME_ALARM: ClockId = + ClockId(libc::CLOCK_BOOTTIME_ALARM); pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC); #[cfg(any( target_os = "android", @@ -94,13 +95,16 @@ impl ClockId { target_os = "linux" ))] #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE); + pub const CLOCK_MONOTONIC_COARSE: ClockId = + ClockId(libc::CLOCK_MONOTONIC_COARSE); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_MONOTONIC_FAST: ClockId = ClockId(libc::CLOCK_MONOTONIC_FAST); + pub const CLOCK_MONOTONIC_FAST: ClockId = + ClockId(libc::CLOCK_MONOTONIC_FAST); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE); + pub const CLOCK_MONOTONIC_PRECISE: ClockId = + ClockId(libc::CLOCK_MONOTONIC_PRECISE); #[cfg(any( target_os = "android", target_os = "emscripten", @@ -121,7 +125,8 @@ impl ClockId { target_os = "linux" ))] #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID); + pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = + ClockId(libc::CLOCK_PROCESS_CPUTIME_ID); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF); @@ -133,7 +138,8 @@ impl ClockId { target_os = "linux" ))] #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM); + pub const CLOCK_REALTIME_ALARM: ClockId = + ClockId(libc::CLOCK_REALTIME_ALARM); #[cfg(any( target_os = "android", target_os = "emscripten", @@ -141,13 +147,15 @@ impl ClockId { target_os = "linux" ))] #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE); + pub const CLOCK_REALTIME_COARSE: ClockId = + ClockId(libc::CLOCK_REALTIME_COARSE); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_REALTIME_PRECISE: ClockId = ClockId(libc::CLOCK_REALTIME_PRECISE); + pub const CLOCK_REALTIME_PRECISE: ClockId = + ClockId(libc::CLOCK_REALTIME_PRECISE); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND); @@ -177,7 +185,8 @@ impl ClockId { target_os = "linux" ))] #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID); + pub const CLOCK_THREAD_CPUTIME_ID: ClockId = + ClockId(libc::CLOCK_THREAD_CPUTIME_ID); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME); @@ -186,7 +195,8 @@ impl ClockId { pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] #[cfg_attr(docsrs, doc(cfg(all())))] - pub const CLOCK_UPTIME_PRECISE: ClockId = ClockId(libc::CLOCK_UPTIME_PRECISE); + pub const CLOCK_UPTIME_PRECISE: ClockId = + ClockId(libc::CLOCK_UPTIME_PRECISE); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL); @@ -216,7 +226,8 @@ impl std::fmt::Display for ClockId { #[cfg_attr(docsrs, doc(cfg(all())))] pub fn clock_getres(clock_id: ClockId) -> Result { let mut c_time: MaybeUninit = MaybeUninit::uninit(); - let ret = unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) }; + let ret = + unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) }; Errno::result(ret)?; let res = unsafe { c_time.assume_init() }; Ok(TimeSpec::from(res)) @@ -226,7 +237,8 @@ pub fn clock_getres(clock_id: ClockId) -> Result { /// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)). pub fn clock_gettime(clock_id: ClockId) -> Result { let mut c_time: MaybeUninit = MaybeUninit::uninit(); - let ret = unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) }; + let ret = + unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) }; Errno::result(ret)?; let res = unsafe { c_time.assume_init() }; Ok(TimeSpec::from(res)) @@ -242,7 +254,8 @@ pub fn clock_gettime(clock_id: ClockId) -> Result { )))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { - let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) }; + let ret = + unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) }; Errno::result(ret).map(drop) } @@ -259,7 +272,8 @@ pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> { #[cfg_attr(docsrs, doc(cfg(feature = "process")))] pub fn clock_getcpuclockid(pid: Pid) -> Result { let mut clk_id: MaybeUninit = MaybeUninit::uninit(); - let ret = unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) }; + let ret = + unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) }; if ret == 0 { let res = unsafe { clk_id.assume_init() }; Ok(ClockId::from(res)) diff --git a/src/ucontext.rs b/src/ucontext.rs index f2338bd426..b2a39f7699 100644 --- a/src/ucontext.rs +++ b/src/ucontext.rs @@ -1,10 +1,10 @@ #[cfg(not(target_env = "musl"))] -use crate::Result; -#[cfg(not(target_env = "musl"))] use crate::errno::Errno; +use crate::sys::signal::SigSet; +#[cfg(not(target_env = "musl"))] +use crate::Result; #[cfg(not(target_env = "musl"))] use std::mem; -use crate::sys::signal::SigSet; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct UContext { @@ -17,7 +17,9 @@ impl UContext { let mut context = mem::MaybeUninit::::uninit(); let res = unsafe { libc::getcontext(context.as_mut_ptr()) }; Errno::result(res).map(|_| unsafe { - UContext { context: context.assume_init()} + UContext { + context: context.assume_init(), + } }) } @@ -31,13 +33,15 @@ impl UContext { pub fn sigmask_mut(&mut self) -> &mut SigSet { unsafe { - &mut *(&mut self.context.uc_sigmask as *mut libc::sigset_t as *mut SigSet) + &mut *(&mut self.context.uc_sigmask as *mut libc::sigset_t + as *mut SigSet) } } pub fn sigmask(&self) -> &SigSet { unsafe { - &*(&self.context.uc_sigmask as *const libc::sigset_t as *const SigSet) + &*(&self.context.uc_sigmask as *const libc::sigset_t + as *const SigSet) } } } From 58f99947bfd069390dcfaa314b06d0e5ffb76c01 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sun, 6 Nov 2022 11:40:46 -0800 Subject: [PATCH 199/358] Run a round of clippy to fix CI Signed-off-by: Alex Saveau --- test/test_dir.rs | 2 +- test/test_fcntl.rs | 8 ++++---- test/test_kmod/mod.rs | 4 ++-- test/test_unistd.rs | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/test_dir.rs b/test/test_dir.rs index f66299210e..2af4aa5c0a 100644 --- a/test/test_dir.rs +++ b/test/test_dir.rs @@ -19,7 +19,7 @@ fn flags() -> OFlag { #[allow(clippy::unnecessary_sort_by)] // False positive fn read() { let tmp = tempdir().unwrap(); - File::create(&tmp.path().join("foo")).unwrap(); + File::create(tmp.path().join("foo")).unwrap(); std::os::unix::fs::symlink("foo", tmp.path().join("bar")).unwrap(); let mut dir = Dir::open(tmp.path(), flags(), Mode::empty()).unwrap(); let mut entries: Vec<_> = dir.iter().map(|e| e.unwrap()).collect(); diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index bc65b2601a..345e04daa5 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -64,7 +64,7 @@ fn test_renameat() { let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); let old_path = old_dir.path().join("old"); - File::create(&old_path).unwrap(); + File::create(old_path).unwrap(); let new_dir = tempfile::tempdir().unwrap(); let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); @@ -94,7 +94,7 @@ fn test_renameat2_behaves_like_renameat_with_no_flags() { let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); let old_path = old_dir.path().join("old"); - File::create(&old_path).unwrap(); + File::create(old_path).unwrap(); let new_dir = tempfile::tempdir().unwrap(); let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); @@ -186,12 +186,12 @@ fn test_renameat2_noreplace() { let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); let old_path = old_dir.path().join("old"); - File::create(&old_path).unwrap(); + File::create(old_path).unwrap(); let new_dir = tempfile::tempdir().unwrap(); let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); let new_path = new_dir.path().join("new"); - File::create(&new_path).unwrap(); + File::create(new_path).unwrap(); assert_eq!( renameat2( Some(old_dirfd), diff --git a/test/test_kmod/mod.rs b/test/test_kmod/mod.rs index 5ebc2423db..6f9aaa897f 100644 --- a/test/test_kmod/mod.rs +++ b/test/test_kmod/mod.rs @@ -12,12 +12,12 @@ fn compile_kernel_module() -> (PathBuf, String, TempDir) { copy( "test/test_kmod/hello_mod/hello.c", - &tmp_dir.path().join("hello.c"), + tmp_dir.path().join("hello.c"), ) .expect("unable to copy hello.c to temporary build directory"); copy( "test/test_kmod/hello_mod/Makefile", - &tmp_dir.path().join("Makefile"), + tmp_dir.path().join("Makefile"), ) .expect("unable to copy Makefile to temporary build directory"); diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 8ad6340c15..9e20f977ec 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -903,7 +903,7 @@ fn test_linkat_file() { let newfilepath = tempdir.path().join(newfilename); // Create file - File::create(&oldfilepath).unwrap(); + File::create(oldfilepath).unwrap(); // Get file descriptor for base directory let dirfd = @@ -936,7 +936,7 @@ fn test_linkat_olddirfd_none() { let newfilepath = tempdir_newfile.path().join(newfilename); // Create file - File::create(&oldfilepath).unwrap(); + File::create(oldfilepath).unwrap(); // Get file descriptor for base directory of new file let dirfd = fcntl::open( @@ -973,7 +973,7 @@ fn test_linkat_newdirfd_none() { let newfilepath = tempdir_newfile.path().join(newfilename); // Create file - File::create(&oldfilepath).unwrap(); + File::create(oldfilepath).unwrap(); // Get file descriptor for base directory of old file let dirfd = fcntl::open( @@ -1101,7 +1101,7 @@ fn test_unlinkat_dir_noremovedir() { let dirpath = tempdir.path().join(dirname); // Create dir - DirBuilder::new().recursive(true).create(&dirpath).unwrap(); + DirBuilder::new().recursive(true).create(dirpath).unwrap(); // Get file descriptor for base directory let dirfd = From 9374e60809ca0ba5aa2285db1d23d96fe750c8ec Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Fri, 11 Nov 2022 19:41:25 -0800 Subject: [PATCH 200/358] Nuke deprecated Errno flags Signed-off-by: Alex Saveau --- CHANGELOG.md | 3 + src/errno.rs | 155 +-------------------------------------------------- 2 files changed, 4 insertions(+), 154 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43d122ab10..10a95ad934 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Removed +- Removed deprecated error constants and conversions. + ([#1860](https://github.com/nix-rust/nix/pull/1860)) + ## [0.25.0] - 2022-08-13 ### Added diff --git a/src/errno.rs b/src/errno.rs index 0c5b0edaa5..d8ad28de85 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -1,4 +1,4 @@ -use crate::{Error, Result}; +use crate::Result; use cfg_if::cfg_if; use libc::{c_int, c_void}; use std::convert::TryFrom; @@ -51,34 +51,6 @@ pub fn errno() -> i32 { } impl Errno { - /// Convert this `Error` to an [`Errno`](enum.Errno.html). - /// - /// # Example - /// - /// ``` - /// # use nix::Error; - /// # use nix::errno::Errno; - /// let e = Error::from(Errno::EPERM); - /// assert_eq!(Some(Errno::EPERM), e.as_errno()); - /// ``` - #[deprecated(since = "0.22.0", note = "It's a no-op now; just delete it.")] - pub const fn as_errno(self) -> Option { - Some(self) - } - - /// Create a nix Error from a given errno - #[deprecated(since = "0.22.0", note = "It's a no-op now; just delete it.")] - #[allow(clippy::wrong_self_convention)] // False positive - pub fn from_errno(errno: Errno) -> Error { - errno - } - - /// Create a new invalid argument error (`EINVAL`) - #[deprecated(since = "0.22.0", note = "Use Errno::EINVAL instead")] - pub const fn invalid_argument() -> Error { - Errno::EINVAL - } - pub fn last() -> Self { last() } @@ -105,18 +77,6 @@ impl Errno { Ok(value) } } - - /// Backwards compatibility hack for Nix <= 0.21.0 users - /// - /// In older versions of Nix, `Error::Sys` was an enum variant. Now it's a - /// function, which is compatible with most of the former use cases of the - /// enum variant. But you should use `Error(Errno::...)` instead. - #[deprecated(since = "0.22.0", note = "Use Errno::... instead")] - #[allow(non_snake_case)] - #[inline] - pub const fn Sys(errno: Errno) -> Error { - errno - } } /// The sentinel value indicates that a function failed and more detailed @@ -1297,22 +1257,6 @@ mod consts { EHWPOISON = libc::EHWPOISON, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EDEADLOCK instead" - )] - pub const EDEADLOCK: Errno = Errno::EDEADLK; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ENOTSUP instead" - )] - pub const ENOTSUP: Errno = Errno::EOPNOTSUPP; - impl Errno { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; pub const EDEADLOCK: Errno = Errno::EDEADLK; @@ -1576,22 +1520,6 @@ mod consts { EQFULL = libc::EQFULL, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ELAST instead" - )] - pub const ELAST: Errno = Errno::EQFULL; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EDEADLOCK instead" - )] - pub const EDEADLOCK: Errno = Errno::EDEADLK; - impl Errno { pub const ELAST: Errno = Errno::EQFULL; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; @@ -1818,27 +1746,6 @@ mod consts { EOWNERDEAD = libc::EOWNERDEAD, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ELAST instead" - )] - pub const ELAST: Errno = Errno::EOWNERDEAD; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EDEADLOCK instead" - )] - pub const EDEADLOCK: Errno = Errno::EDEADLK; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EOPNOTSUPP instead" - )] - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; - impl Errno { pub const ELAST: Errno = Errno::EOWNERDEAD; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; @@ -2056,27 +1963,6 @@ mod consts { EASYNC = libc::EASYNC, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ELAST instead" - )] - pub const ELAST: Errno = Errno::EASYNC; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EDEADLOCK instead" - )] - pub const EDEADLOCK: Errno = Errno::EDEADLK; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EOPNOTSUPP instead" - )] - pub const EOPNOTSUPP: Errno = Errno::ENOTSUP; - impl Errno { pub const ELAST: Errno = Errno::EASYNC; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; @@ -2291,17 +2177,6 @@ mod consts { EPROTO = libc::EPROTO, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ELAST instead" - )] - pub const ELAST: Errno = Errno::ENOTSUP; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - impl Errno { pub const ELAST: Errno = Errno::ENOTSUP; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; @@ -2516,17 +2391,6 @@ mod consts { EPROTO = libc::EPROTO, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ELAST instead" - )] - pub const ELAST: Errno = Errno::ENOTSUP; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - impl Errno { pub const ELAST: Errno = Errno::ENOTSUP; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; @@ -2731,12 +2595,6 @@ mod consts { EPROTO = libc::EPROTO, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - impl Errno { pub const EWOULDBLOCK: Errno = Errno::EAGAIN; } @@ -2965,17 +2823,6 @@ mod consts { ESTALE = libc::ESTALE, } - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::ELAST instead" - )] - pub const ELAST: Errno = Errno::ELAST; - #[deprecated( - since = "0.22.1", - note = "use nix::errno::Errno::EWOULDBLOCK instead" - )] - pub const EWOULDBLOCK: Errno = Errno::EAGAIN; - impl Errno { pub const ELAST: Errno = Errno::ESTALE; pub const EWOULDBLOCK: Errno = Errno::EAGAIN; From b34333df28f3be429e064cc1ee41673d6e109f5d Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sat, 19 Nov 2022 15:34:29 +0000 Subject: [PATCH 201/358] Mode flag documentation --- src/sys/stat.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 94be4107bc..78203bfbe3 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -33,19 +33,33 @@ libc_bitflags!( libc_bitflags! { /// "File mode / permissions" flags. pub struct Mode: mode_t { + /// Read, write and execute for owner. S_IRWXU; + /// Read for owner. S_IRUSR; + /// Write for owner. S_IWUSR; + /// Execute for owner. S_IXUSR; + /// Read write and execute for group. S_IRWXG; + /// Read fr group. S_IRGRP; + /// Write for group. S_IWGRP; + /// Execute for group. S_IXGRP; + /// Read, write and execute for other. S_IRWXO; + /// Read for other. S_IROTH; + /// Write for other. S_IWOTH; + /// Execute for other. S_IXOTH; + /// Set user id on execution. S_ISUID as mode_t; + /// Set group id on execution. S_ISGID as mode_t; S_ISVTX as mode_t; } From fa62534a238c86334d41bc1da68267388cda9b36 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 19 Nov 2022 13:39:31 -0700 Subject: [PATCH 202/358] Fix using SockaddrStorage to store Unix domain addresses on Linux Since it has variable length, the user of a sockaddr_un must keep track of its true length. On the BSDs, this is handled by the builtin sun_len field. But on Linux-like operating systems it isn't. Fix this bug by explicitly tracking it for SockaddrStorage just like we already do for UnixAddr. Fixes #1866 --- CHANGELOG.md | 6 +- src/sys/socket/addr.rs | 122 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10a95ad934..6551078852 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added -- Add `MntFlags` and `unmount` on all of the BSDs. +- Added `SockaddrStorage::{as_unix_addr, as_unix_addr_mut}` + ([#1871](https://github.com/nix-rust/nix/pull/1871)) +- Added `MntFlags` and `unmount` on all of the BSDs. ([#1849](https://github.com/nix-rust/nix/pull/1849)) - Added a 'Statfs::flags' method. ([#1849](https://github.com/nix-rust/nix/pull/1849)) @@ -38,6 +40,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Fixed +- Fixed using `SockaddrStorage` to store a Unix-domain socket address on Linux. + ([#1871](https://github.com/nix-rust/nix/pull/1871)) - Fix microsecond calculation for `TimeSpec`. ([#1801](https://github.com/nix-rust/nix/pull/1801)) - Fix `User::from_name` and `Group::from_name` panicking diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 4a16eea94e..74420399dc 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1537,6 +1537,17 @@ impl SockaddrLike for SockaddrStorage { let mut ss: libc::sockaddr_storage = mem::zeroed(); let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8; ptr::copy(addr as *const u8, ssp, len as usize); + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + if i32::from(ss.ss_family) == libc::AF_UNIX { + // Safe because we UnixAddr is strictly smaller than + // SockaddrStorage, and we just initialized the structure. + (*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr)).sun_len = len as u8; + } Some(Self { ss }) } } else { @@ -1598,6 +1609,21 @@ impl SockaddrLike for SockaddrStorage { } } } + + #[cfg(any( + target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + fn len(&self) -> libc::socklen_t { + match self.as_unix_addr() { + // The UnixAddr type knows its own length + Some(ua) => ua.len(), + // For all else, we're just a boring SockaddrStorage + None => mem::size_of_val(self) as libc::socklen_t + } + } } macro_rules! accessors { @@ -1635,6 +1661,64 @@ macro_rules! accessors { } impl SockaddrStorage { + /// Downcast to an immutable `[UnixAddr]` reference. + pub fn as_unix_addr(&self) -> Option<&UnixAddr> { + cfg_if! { + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + { + let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; + // Safe because UnixAddr is strictly smaller than + // sockaddr_storage, and we're fully initialized + let len = unsafe { + (*(p as *const UnixAddr )).sun_len as usize + }; + } else { + let len = self.len() as usize; + } + } + // Sanity checks + if self.family() != Some(AddressFamily::Unix) || + len < offset_of!(libc::sockaddr_un, sun_path) || + len > mem::size_of::() { + None + } else { + Some(unsafe{&self.su}) + } + } + + /// Downcast to a mutable `[UnixAddr]` reference. + pub fn as_unix_addr_mut(&mut self) -> Option<&mut UnixAddr> { + cfg_if! { + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + { + let p = unsafe{ &self.ss as *const libc::sockaddr_storage }; + // Safe because UnixAddr is strictly smaller than + // sockaddr_storage, and we're fully initialized + let len = unsafe { + (*(p as *const UnixAddr )).sun_len as usize + }; + } else { + let len = self.len() as usize; + } + } + // Sanity checks + if self.family() != Some(AddressFamily::Unix) || + len < offset_of!(libc::sockaddr_un, sun_path) || + len > mem::size_of::() { + None + } else { + Some(unsafe{&mut self.su}) + } + } + #[cfg(any(target_os = "android", target_os = "linux"))] accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr, AddressFamily::Alg, libc::sockaddr_alg, alg} @@ -3064,6 +3148,44 @@ mod tests { } } + mod sockaddr_storage { + use super::*; + + #[test] + fn from_sockaddr_un_named() { + let ua = UnixAddr::new("/var/run/mysock").unwrap(); + let ptr = ua.as_ptr() as *const libc::sockaddr; + let ss = unsafe { + SockaddrStorage::from_raw(ptr, Some(ua.len())) + }.unwrap(); + assert_eq!(ss.len(), ua.len()); + } + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[test] + fn from_sockaddr_un_abstract_named() { + let name = String::from("nix\0abstract\0test"); + let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap(); + let ptr = ua.as_ptr() as *const libc::sockaddr; + let ss = unsafe { + SockaddrStorage::from_raw(ptr, Some(ua.len())) + }.unwrap(); + assert_eq!(ss.len(), ua.len()); + } + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[test] + fn from_sockaddr_un_abstract_unnamed() { + let empty = String::new(); + let ua = UnixAddr::new_abstract(empty.as_bytes()).unwrap(); + let ptr = ua.as_ptr() as *const libc::sockaddr; + let ss = unsafe { + SockaddrStorage::from_raw(ptr, Some(ua.len())) + }.unwrap(); + assert_eq!(ss.len(), ua.len()); + } + } + mod unixaddr { use super::*; From 80b25720733a62e07c3b9e02e65627c7098e16e9 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 19 Nov 2022 14:57:20 -0700 Subject: [PATCH 203/358] Misc internal optimizations * Make ipv4addr_to_libc const * Use mem::transmute in ipv4addr_to_libc and ipv6addr_to_libc Fixes #1687 Fixes #1688 --- Cargo.toml | 1 + src/sys/socket/addr.rs | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e09f758a25..dc854c5ff4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ libc = { git = "https://github.com/rust-lang/libc", rev = "cc19b6f0801", feature bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } +static_assertions = "1" [target.'cfg(not(target_os = "redox"))'.dependencies] memoffset = { version = "0.6.3", optional = true } diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 4a16eea94e..c7b5f29eb6 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -40,23 +40,22 @@ use std::{fmt, mem, net, ptr, slice}; /// Convert a std::net::Ipv4Addr into the libc form. #[cfg(feature = "net")] -pub(crate) fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { - let octets = addr.octets(); - libc::in_addr { - s_addr: u32::to_be( - ((octets[0] as u32) << 24) - | ((octets[1] as u32) << 16) - | ((octets[2] as u32) << 8) - | (octets[3] as u32), - ), +pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { + static_assertions::assert_eq_size!(net::Ipv4Addr, libc::in_addr); + // Safe because both types have the same memory layout, and no fancy Drop + // impls. + unsafe { + mem::transmute(addr) } } /// Convert a std::net::Ipv6Addr into the libc form. #[cfg(feature = "net")] pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr { - libc::in6_addr { - s6_addr: addr.octets(), + static_assertions::assert_eq_size!(net::Ipv6Addr, libc::in6_addr); + // Safe because both are Newtype wrappers around the same libc type + unsafe { + mem::transmute(*addr) } } From faac24c77985a5ef8634d5f5bd6bbe50af589105 Mon Sep 17 00:00:00 2001 From: mzachar Date: Sun, 6 Nov 2022 01:36:47 +0100 Subject: [PATCH 204/358] Adds IP_TOS, IPV6_TCLASS and SO_PRIORITY sockopt wrappers --- CHANGELOG.md | 4 +++- src/sys/socket/sockopt.rs | 35 ++++++++++++++++++++++++++++ test/sys/test_sockopt.rs | 48 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10a95ad934..5294d286fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1841](https://github.com/nix-rust/nix/pull/1841)) - Added `eaccess()` on FreeBSD, DragonFly and Linux (glibc and musl). ([#1842](https://github.com/nix-rust/nix/pull/1842)) - +- Added `IP_TOS` `SO_PRIORITY` and `IPV6_TCLASS` sockopts for Linux + ([#1853](https://github.com/nix-rust/nix/pull/1853)) + ### Changed - The MSRV is now 1.56.1 diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index e9f26333a3..08b73aaa81 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -371,6 +371,41 @@ sockopt_impl!( libc::IP_MULTICAST_LOOP, bool ); +#[cfg(target_os = "linux")] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Set the protocol-defined priority for all packets to be + /// sent on this socket + Priority, + Both, + libc::SOL_SOCKET, + libc::SO_PRIORITY, + libc::c_int +); +#[cfg(target_os = "linux")] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Set or receive the Type-Of-Service (TOS) field that is + /// sent with every IP packet originating from this socket + IpTos, + Both, + libc::IPPROTO_IP, + libc::IP_TOS, + libc::c_int +); +#[cfg(target_os = "linux")] +#[cfg(feature = "net")] +sockopt_impl!( + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + /// Traffic class associated with outgoing packets + Ipv6TClass, + Both, + libc::IPPROTO_IPV6, + libc::IPV6_TCLASS, + libc::c_int +); #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] #[cfg(feature = "net")] sockopt_impl!( diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 2ddbf77b83..e6acfa5981 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -327,3 +327,51 @@ fn test_v6dontfrag_opts() { "unsetting IPV6_DONTFRAG on an inet6 datagram socket should succeed", ); } + +#[test] +#[cfg(target_os = "linux")] +fn test_so_priority() { + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + let priority = 3; + setsockopt(fd, sockopt::Priority, &priority).unwrap(); + assert_eq!(getsockopt(fd, sockopt::Priority).unwrap(), priority); +} + +#[test] +#[cfg(target_os = "linux")] +fn test_ip_tos() { + let fd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + let tos = 0x80; // CS4 + setsockopt(fd, sockopt::IpTos, &tos).unwrap(); + assert_eq!(getsockopt(fd, sockopt::IpTos).unwrap(), tos); +} + +#[test] +#[cfg(target_os = "linux")] +// Disable the test under emulation because it fails in Cirrus-CI. Lack +// of QEMU support is suspected. +#[cfg_attr(qemu, ignore)] +fn test_ipv6_tclass() { + let fd = socket( + AddressFamily::Inet6, + SockType::Stream, + SockFlag::empty(), + SockProtocol::Tcp, + ) + .unwrap(); + let class = 0x80; // CS4 + setsockopt(fd, sockopt::Ipv6TClass, &class).unwrap(); + assert_eq!(getsockopt(fd, sockopt::Ipv6TClass).unwrap(), class); +} From 16f8ff9b266353df7edb66831351d93dedcc84e2 Mon Sep 17 00:00:00 2001 From: roblabla Date: Wed, 10 Aug 2022 16:47:51 +0200 Subject: [PATCH 205/358] Workaround XNU bug in getifaddrs netmasks --- CHANGELOG.md | 4 +++- src/ifaddrs.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10a95ad934..8d43c9fbea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1815](https://github.com/nix-rust/nix/pull/1815)) - Fix `User::from_uid` and `User::from_name` crash on Android platform. ([#1824](https://github.com/nix-rust/nix/pull/1824)) - +- Workaround XNU bug causing netmasks returned by `getifaddrs` to misbehave. + (#1709) + ### Removed - Removed deprecated error constants and conversions. diff --git a/src/ifaddrs.rs b/src/ifaddrs.rs index 210d4d7742..70b50b01eb 100644 --- a/src/ifaddrs.rs +++ b/src/ifaddrs.rs @@ -4,6 +4,8 @@ //! of interfaces and their associated addresses. use cfg_if::cfg_if; +#[cfg(any(target_os = "ios", target_os = "macos"))] +use std::convert::TryFrom; use std::ffi; use std::iter::Iterator; use std::mem; @@ -42,11 +44,50 @@ cfg_if! { } } +/// Workaround a bug in XNU where netmasks will always have the wrong size in +/// the sa_len field due to the kernel ignoring trailing zeroes in the structure +/// when setting the field. See https://github.com/nix-rust/nix/issues/1709#issuecomment-1199304470 +/// +/// To fix this, we stack-allocate a new sockaddr_storage, zero it out, and +/// memcpy sa_len of the netmask to that new storage. Finally, we reset the +/// ss_len field to sizeof(sockaddr_storage). This is supposedly valid as all +/// members of the sockaddr_storage are "ok" with being zeroed out (there are +/// no pointers). +#[cfg(any(target_os = "ios", target_os = "macos"))] +unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option { + let src_sock = info.ifa_netmask; + if src_sock.is_null() { + return None; + } + + let mut dst_sock = mem::MaybeUninit::::zeroed(); + + // memcpy only sa_len bytes, assume the rest is zero + std::ptr::copy_nonoverlapping( + src_sock as *const u8, + dst_sock.as_mut_ptr() as *mut u8, + (*src_sock).sa_len.into(), + ); + + // Initialize ss_len to sizeof(libc::sockaddr_storage). + (*dst_sock.as_mut_ptr()).ss_len = + u8::try_from(mem::size_of::()).unwrap(); + let dst_sock = dst_sock.assume_init(); + + let dst_sock_ptr = + &dst_sock as *const libc::sockaddr_storage as *const libc::sockaddr; + + SockaddrStorage::from_raw(dst_sock_ptr, None) +} + impl InterfaceAddress { /// Create an `InterfaceAddress` from the libc struct. fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress { let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) }; let address = unsafe { SockaddrStorage::from_raw(info.ifa_addr, None) }; + #[cfg(any(target_os = "ios", target_os = "macos"))] + let netmask = unsafe { workaround_xnu_bug(info) }; + #[cfg(not(any(target_os = "ios", target_os = "macos")))] let netmask = unsafe { SockaddrStorage::from_raw(info.ifa_netmask, None) }; let mut addr = InterfaceAddress { @@ -145,4 +186,28 @@ mod tests { fn test_getifaddrs() { let _ = getifaddrs(); } + + // Ensures getting the netmask works, and in particular that + // `workaround_xnu_bug` works properly. + #[test] + fn test_getifaddrs_netmask_correct() { + let addrs = getifaddrs().unwrap(); + for iface in addrs { + let sock = if let Some(sock) = iface.netmask { + sock + } else { + continue; + }; + if sock.family() == Some(crate::sys::socket::AddressFamily::Inet) { + let _ = sock.as_sockaddr_in().unwrap(); + return; + } else if sock.family() + == Some(crate::sys::socket::AddressFamily::Inet6) + { + let _ = sock.as_sockaddr_in6().unwrap(); + return; + } + } + panic!("No address?"); + } } From d34696c84b0d3b49456fa6f0f12af91d94b11371 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sun, 20 Nov 2022 17:16:21 +0000 Subject: [PATCH 206/358] mmap addr --- CHANGELOG.md | 2 ++ src/sys/mman.rs | 13 +++++++++---- test/sys/test_mman.rs | 6 +++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10a95ad934..065f98fc00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - The MSRV is now 1.56.1 ([#1792](https://github.com/nix-rust/nix/pull/1792)) +- The `addr` argument of `sys::mman::mmap` is now of type `Option`. + ([#1870](https://github.com/nix-rust/nix/pull/1870)) ### Fixed diff --git a/src/sys/mman.rs b/src/sys/mman.rs index 869f44c4b7..dab8f445e1 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -8,7 +8,7 @@ use crate::Result; #[cfg(feature = "fs")] use crate::{fcntl::OFlag, sys::stat::Mode}; use libc::{self, c_int, c_void, off_t, size_t}; -use std::os::unix::io::RawFd; +use std::{os::unix::io::RawFd, num::NonZeroUsize}; libc_bitflags! { /// Desired memory protection of a memory mapping. @@ -417,14 +417,19 @@ pub fn munlockall() -> Result<()> { /// /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html pub unsafe fn mmap( - addr: *mut c_void, + addr: Option, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t, ) -> Result<*mut c_void> { - let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset); + let ptr = addr.map_or( + std::ptr::null_mut(), + |a| usize::from(a) as *mut c_void + ); + + let ret = libc::mmap(ptr, length, prot.bits(), flags.bits(), fd, offset); if ret == libc::MAP_FAILED { Err(Errno::last()) @@ -516,7 +521,7 @@ pub unsafe fn madvise( /// # use std::ptr; /// const ONE_K: size_t = 1024; /// let mut slice: &mut [u8] = unsafe { -/// let mem = mmap(ptr::null_mut(), ONE_K, ProtFlags::PROT_NONE, +/// let mem = mmap(None, ONE_K, ProtFlags::PROT_NONE, /// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap(); /// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap(); /// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) diff --git a/test/sys/test_mman.rs b/test/sys/test_mman.rs index 75cbf6ce8c..a43991c248 100644 --- a/test/sys/test_mman.rs +++ b/test/sys/test_mman.rs @@ -4,7 +4,7 @@ use nix::sys::mman::{mmap, MapFlags, ProtFlags}; fn test_mmap_anonymous() { unsafe { let ptr = mmap( - std::ptr::null_mut(), + None, 1, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, @@ -27,7 +27,7 @@ fn test_mremap_grow() { const ONE_K: size_t = 1024; let slice: &mut [u8] = unsafe { let mem = mmap( - std::ptr::null_mut(), + None, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, @@ -83,7 +83,7 @@ fn test_mremap_shrink() { const ONE_K: size_t = 1024; let slice: &mut [u8] = unsafe { let mem = mmap( - std::ptr::null_mut(), + None, 10 * ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, From 63c56263fbaa723693ff91f082c30f3a44259c4f Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sun, 20 Nov 2022 22:53:34 +0000 Subject: [PATCH 207/358] mmap non-zero length --- CHANGELOG.md | 2 ++ src/sys/mman.rs | 9 +++++---- test/sys/test_mman.rs | 13 +++++++++---- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2742cfb182..917094aaac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1792](https://github.com/nix-rust/nix/pull/1792)) - The `addr` argument of `sys::mman::mmap` is now of type `Option`. ([#1870](https://github.com/nix-rust/nix/pull/1870)) +- The `length` argument of `sys::mman::mmap` is now of type `NonZeroUsize`. + ([#1873](https://github.com/nix-rust/nix/pull/1873)) ### Fixed diff --git a/src/sys/mman.rs b/src/sys/mman.rs index dab8f445e1..2bee091610 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -418,7 +418,7 @@ pub fn munlockall() -> Result<()> { /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html pub unsafe fn mmap( addr: Option, - length: size_t, + length: NonZeroUsize, prot: ProtFlags, flags: MapFlags, fd: RawFd, @@ -428,8 +428,8 @@ pub unsafe fn mmap( std::ptr::null_mut(), |a| usize::from(a) as *mut c_void ); - - let ret = libc::mmap(ptr, length, prot.bits(), flags.bits(), fd, offset); + + let ret = libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset); if ret == libc::MAP_FAILED { Err(Errno::last()) @@ -520,8 +520,9 @@ pub unsafe fn madvise( /// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags}; /// # use std::ptr; /// const ONE_K: size_t = 1024; +/// let one_k_non_zero = std::num::NonZeroUsize::new(ONE_K).unwrap(); /// let mut slice: &mut [u8] = unsafe { -/// let mem = mmap(None, ONE_K, ProtFlags::PROT_NONE, +/// let mem = mmap(None, one_k_non_zero, ProtFlags::PROT_NONE, /// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap(); /// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap(); /// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) diff --git a/test/sys/test_mman.rs b/test/sys/test_mman.rs index a43991c248..e748427bcd 100644 --- a/test/sys/test_mman.rs +++ b/test/sys/test_mman.rs @@ -1,11 +1,12 @@ use nix::sys::mman::{mmap, MapFlags, ProtFlags}; +use std::num::NonZeroUsize; #[test] fn test_mmap_anonymous() { unsafe { let ptr = mmap( None, - 1, + NonZeroUsize::new(1).unwrap(), ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, -1, @@ -25,10 +26,12 @@ fn test_mremap_grow() { use nix::sys::mman::{mremap, MRemapFlags}; const ONE_K: size_t = 1024; + let one_k_non_zero = NonZeroUsize::new(ONE_K).unwrap(); + let slice: &mut [u8] = unsafe { let mem = mmap( None, - ONE_K, + one_k_non_zero, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, @@ -79,12 +82,14 @@ fn test_mremap_grow() { fn test_mremap_shrink() { use nix::libc::{c_void, size_t}; use nix::sys::mman::{mremap, MRemapFlags}; + use std::num::NonZeroUsize; const ONE_K: size_t = 1024; + let ten_one_k = NonZeroUsize::new(10 * ONE_K).unwrap(); let slice: &mut [u8] = unsafe { let mem = mmap( None, - 10 * ONE_K, + ten_one_k, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, @@ -100,7 +105,7 @@ fn test_mremap_shrink() { let slice: &mut [u8] = unsafe { let mem = mremap( slice.as_mut_ptr() as *mut c_void, - 10 * ONE_K, + ten_one_k.into(), ONE_K, MRemapFlags::empty(), None, From 8884ea38ec80d838138070e941c080b0b573575a Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Mon, 7 Nov 2022 15:17:29 -0500 Subject: [PATCH 208/358] Added better support for unnamed unix socket addrs --- src/sys/socket/addr.rs | 29 +++++++++++++++++ test/sys/test_socket.rs | 71 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index c7b5f29eb6..f051d20547 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -885,6 +885,29 @@ impl UnixAddr { } } + /// Create a new `sockaddr_un` representing an "unnamed" unix socket address. + pub fn new_unnamed() -> UnixAddr { + #[allow(unused)] + let mut ret = libc::sockaddr_un { + sun_family: AddressFamily::Unix as sa_family_t, + .. unsafe { mem::zeroed() } + }; + + let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap(); + + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + { + ret.sun_len = sun_len; + } + + unsafe { UnixAddr::from_raw_parts(ret, sun_len) } + } + /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len` /// is the size of the valid portion of the struct, excluding any trailing /// NUL. @@ -941,6 +964,12 @@ impl UnixAddr { } } + /// Check if this address is an "unnamed" unix socket address. + #[inline] + pub fn is_unnamed(&self) -> bool { + matches!(self.kind(), UnixAddrKind::Unnamed) + } + /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)` #[inline] pub fn path_len(&self) -> usize { diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 7ab60ecc28..26ba9b2d0f 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -244,6 +244,22 @@ pub fn test_abstract_uds_addr() { assert_eq!(unsafe { (*addr.as_ptr()).sun_path[0] }, 0); } +// Test getting an unnamed address (without unix socket creation) +#[test] +pub fn test_unnamed_uds_addr() { + use crate::nix::sys::socket::SockaddrLike; + + let addr = UnixAddr::new_unnamed(); + + assert!(addr.is_unnamed()); + assert_eq!(addr.len(), 2); + assert!(addr.path().is_none()); + assert_eq!(addr.path_len(), 0); + + #[cfg(target_os = "linux")] + assert!(addr.as_abstract().is_none()); +} + #[test] pub fn test_getsockname() { use nix::sys::socket::bind; @@ -1484,7 +1500,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { // Test creating and using named unix domain sockets #[test] -pub fn test_unixdomain() { +pub fn test_named_unixdomain() { use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr}; use nix::sys::socket::{SockFlag, SockType}; use nix::unistd::{close, read, write}; @@ -1527,6 +1543,59 @@ pub fn test_unixdomain() { assert_eq!(&buf[..], b"hello"); } +// Test using unnamed unix domain addresses +#[test] +pub fn test_unnamed_unixdomain() { + use nix::sys::socket::{getsockname, socketpair}; + use nix::sys::socket::{SockFlag, SockType}; + use nix::unistd::close; + + let (fd_1, fd_2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .expect("socketpair failed"); + + let addr_1: UnixAddr = getsockname(fd_1).expect("getsockname failed"); + assert!(addr_1.is_unnamed()); + assert_eq!(addr_1, UnixAddr::new_unnamed()); + + close(fd_1).unwrap(); + close(fd_2).unwrap(); +} + +// Test creating and using unnamed unix domain addresses for autobinding sockets +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +pub fn test_unnamed_unixdomain_autobind() { + use nix::sys::socket::{bind, getsockname, socket}; + use nix::sys::socket::{SockFlag, SockType}; + use nix::unistd::close; + + let fd = socket( + AddressFamily::Unix, + SockType::Stream, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + + // unix(7): "If a bind(2) call specifies addrlen as `sizeof(sa_family_t)`, or [...], then the + // socket is autobound to an abstract address" + bind(fd, &UnixAddr::new_unnamed()).expect("bind failed"); + + let addr: UnixAddr = getsockname(fd).expect("getsockname failed"); + let addr = addr.as_abstract().unwrap(); + + // changed from 8 to 5 bytes in Linux 2.3.15, and rust's minimum supported Linux version is 3.2 + // (as of 2022-11) + assert_eq!(addr.len(), 5); + + close(fd).unwrap(); +} + // Test creating and using named system control sockets #[cfg(any(target_os = "macos", target_os = "ios"))] #[test] From 49bab984ee75391f37816eb722bbad9b7ae92b1c Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Mon, 7 Nov 2022 18:25:27 -0500 Subject: [PATCH 209/358] fixup! Added better support for unnamed unix socket addrs Make Linux-only --- src/sys/socket/addr.rs | 17 +++++------------ test/sys/test_socket.rs | 5 +++-- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index f051d20547..34138efcfb 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -886,25 +886,16 @@ impl UnixAddr { } /// Create a new `sockaddr_un` representing an "unnamed" unix socket address. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] pub fn new_unnamed() -> UnixAddr { - #[allow(unused)] - let mut ret = libc::sockaddr_un { + let ret = libc::sockaddr_un { sun_family: AddressFamily::Unix as sa_family_t, .. unsafe { mem::zeroed() } }; let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap(); - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - { - ret.sun_len = sun_len; - } - unsafe { UnixAddr::from_raw_parts(ret, sun_len) } } @@ -965,6 +956,8 @@ impl UnixAddr { } /// Check if this address is an "unnamed" unix socket address. + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] #[inline] pub fn is_unnamed(&self) -> bool { matches!(self.kind(), UnixAddrKind::Unnamed) diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 26ba9b2d0f..07ca4d3420 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -223,7 +223,7 @@ pub fn test_addr_equality_abstract() { } // Test getting/setting abstract addresses (without unix socket creation) -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "android", target_os = "linux"))] #[test] pub fn test_abstract_uds_addr() { let empty = String::new(); @@ -245,6 +245,7 @@ pub fn test_abstract_uds_addr() { } // Test getting an unnamed address (without unix socket creation) +#[cfg(any(target_os = "android", target_os = "linux"))] #[test] pub fn test_unnamed_uds_addr() { use crate::nix::sys::socket::SockaddrLike; @@ -256,7 +257,6 @@ pub fn test_unnamed_uds_addr() { assert!(addr.path().is_none()); assert_eq!(addr.path_len(), 0); - #[cfg(target_os = "linux")] assert!(addr.as_abstract().is_none()); } @@ -1544,6 +1544,7 @@ pub fn test_named_unixdomain() { } // Test using unnamed unix domain addresses +#[cfg(any(target_os = "android", target_os = "linux"))] #[test] pub fn test_unnamed_unixdomain() { use nix::sys::socket::{getsockname, socketpair}; From 500baa1633cb93a11b0b3998ab8075f66d7e6715 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Mon, 21 Nov 2022 12:10:34 -0500 Subject: [PATCH 210/358] fixup! Added better support for unnamed unix socket addrs Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2742cfb182..b2ae4b16a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1842](https://github.com/nix-rust/nix/pull/1842)) - Added `IP_TOS` `SO_PRIORITY` and `IPV6_TCLASS` sockopts for Linux ([#1853](https://github.com/nix-rust/nix/pull/1853)) +- Added `new_unnamed` and `is_unnamed` for `UnixAddr` on Linux and Android. + ([#1857](https://github.com/nix-rust/nix/pull/1857)) ### Changed From f6a22198a48b138f43abeb186ebe9f4ebb1af415 Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Mon, 21 Nov 2022 12:11:43 -0500 Subject: [PATCH 211/358] fixup! Added better support for unnamed unix socket addrs Removed test assertion --- test/sys/test_socket.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 07ca4d3420..5adc77ed6b 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1561,7 +1561,6 @@ pub fn test_unnamed_unixdomain() { let addr_1: UnixAddr = getsockname(fd_1).expect("getsockname failed"); assert!(addr_1.is_unnamed()); - assert_eq!(addr_1, UnixAddr::new_unnamed()); close(fd_1).unwrap(); close(fd_2).unwrap(); From 38597988f4d62357d0670fe0d3f4134b291be030 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Mon, 21 Nov 2022 20:26:16 +0300 Subject: [PATCH 212/358] Added `SockProtocol::Raw = libc::IPPROTO_RAW` for raw sockets --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a5efc2a70..9c580fc893 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1853](https://github.com/nix-rust/nix/pull/1853)) - Added `new_unnamed` and `is_unnamed` for `UnixAddr` on Linux and Android. ([#1857](https://github.com/nix-rust/nix/pull/1857)) +- Added `SockProtocol::Raw` for raw sockets + ([#1848](https://github.com/nix-rust/nix/pull/1848)) ### Changed diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index af19c52dfd..37a4037cd8 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -118,6 +118,8 @@ pub enum SockProtocol { Tcp = libc::IPPROTO_TCP, /// UDP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) Udp = libc::IPPROTO_UDP, + /// Raw sockets ([raw(7)](https://man7.org/linux/man-pages/man7/raw.7.html)) + Raw = libc::IPPROTO_RAW, /// Allows applications and other KEXTs to be notified when certain kernel events occur /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) #[cfg(any(target_os = "ios", target_os = "macos"))] From 59c21f772ac9b9c6c87da91aaf4e752331064990 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 21 Nov 2022 11:15:55 -0700 Subject: [PATCH 213/358] Use the new UnixAddr::new_unnamed in the unit tests Use it in the from_sockaddr_un_abstract_unnamed test. That test and this method were introduced by PRs #1871 and #1857, which crossed each other. --- src/sys/socket/addr.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 2b3e491984..8b23b10cf0 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -3197,8 +3197,7 @@ mod tests { #[cfg(any(target_os = "android", target_os = "linux"))] #[test] fn from_sockaddr_un_abstract_unnamed() { - let empty = String::new(); - let ua = UnixAddr::new_abstract(empty.as_bytes()).unwrap(); + let ua = UnixAddr::new_unnamed(); let ptr = ua.as_ptr() as *const libc::sockaddr; let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) From e9f07eea61d78dd1b4555e0e7814ab1078cb10d9 Mon Sep 17 00:00:00 2001 From: Jonathan de Jong Date: Mon, 14 Nov 2022 09:56:02 +0000 Subject: [PATCH 214/358] add IpMtu sockopt --- CHANGELOG.md | 2 ++ src/sys/socket/sockopt.rs | 9 +++++++++ test/sys/test_sockopt.rs | 27 +++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c580fc893..267d18097d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1857](https://github.com/nix-rust/nix/pull/1857)) - Added `SockProtocol::Raw` for raw sockets ([#1848](https://github.com/nix-rust/nix/pull/1848)) +- added `IP_MTU` (`IpMtu`) `IPPROTO_IP` sockopt on Linux and Android. + ([#1865](https://github.com/nix-rust/nix/pull/1865)) ### Changed diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 08b73aaa81..7489858ee3 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -925,6 +925,15 @@ sockopt_impl!( libc::IPV6_RECVERR, bool ); +#[cfg(any(target_os = "android", target_os = "linux"))] +sockopt_impl!( + /// Fetch the current system-estimated Path MTU. + IpMtu, + GetOnly, + libc::IPPROTO_IP, + libc::IP_MTU, + libc::c_int +); #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] sockopt_impl!( /// Set or retrieve the current time-to-live field that is used in every diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index e6acfa5981..47b01c1605 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -236,6 +236,33 @@ fn test_so_tcp_keepalive() { } } +#[test] +#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg_attr(qemu, ignore)] +fn test_get_mtu() { + use nix::sys::socket::{bind, connect, SockaddrIn}; + use std::net::SocketAddrV4; + use std::str::FromStr; + + let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap(); + let std_sb = SocketAddrV4::from_str("127.0.0.1:4002").unwrap(); + + let usock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + SockProtocol::Udp, + ) + .unwrap(); + + // Bind and initiate connection + bind(usock, &SockaddrIn::from(std_sa)).unwrap(); + connect(usock, &SockaddrIn::from(std_sb)).unwrap(); + + // Loopback connections have 2^16 - the maximum - MTU + assert_eq!(getsockopt(usock, sockopt::IpMtu), Ok(u16::MAX as i32)) +} + #[test] #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] fn test_ttl_opts() { From 0ae109ddad121c53cb0dc315d43613fb5f4549cd Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 25 Nov 2022 08:27:55 -0700 Subject: [PATCH 215/358] Clippy cleanup with the latest nightly. --- src/sys/socket/mod.rs | 2 ++ test/sys/test_aio.rs | 10 +++++----- test/test_fcntl.rs | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 37a4037cd8..a07025856e 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1727,6 +1727,8 @@ where { type Item = RecvMsg<'a, 'a, S>; + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] fn next(&mut self) -> Option { if self.current_index >= self.received { return None; diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index 6a36f3e7cf..84086f80ce 100644 --- a/test/sys/test_aio.rs +++ b/test/sys/test_aio.rs @@ -1,5 +1,5 @@ use std::{ - io::{Read, Seek, SeekFrom, Write}, + io::{Read, Seek, Write}, ops::Deref, os::unix::io::AsRawFd, pin::Pin, @@ -371,7 +371,7 @@ mod aio_write { assert_eq!(err, Ok(())); assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len()); - f.seek(SeekFrom::Start(0)).unwrap(); + f.rewind().unwrap(); let len = f.read_to_end(&mut rbuf).unwrap(); assert_eq!(len, EXPECT.len()); assert_eq!(rbuf, EXPECT); @@ -402,7 +402,7 @@ mod aio_write { assert_eq!(err, Ok(())); assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len()); - f.seek(SeekFrom::Start(0)).unwrap(); + f.rewind().unwrap(); let len = f.read_to_end(&mut rbuf).unwrap(); assert_eq!(len, EXPECT.len()); assert_eq!(rbuf, EXPECT); @@ -487,7 +487,7 @@ mod aio_writev { assert_eq!(err, Ok(())); assert_eq!(aiow.as_mut().aio_return().unwrap(), wlen); - f.seek(SeekFrom::Start(0)).unwrap(); + f.rewind().unwrap(); let len = f.read_to_end(&mut rbuf).unwrap(); assert_eq!(len, EXPECT.len()); assert_eq!(rbuf, EXPECT); @@ -537,7 +537,7 @@ fn sigev_signal() { } assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); - f.seek(SeekFrom::Start(0)).unwrap(); + f.rewind().unwrap(); let len = f.read_to_end(&mut rbuf).unwrap(); assert_eq!(len, EXPECT.len()); assert_eq!(rbuf, EXPECT); diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 345e04daa5..e51044a069 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -231,7 +231,7 @@ fn test_readlink() { mod linux_android { use libc::loff_t; use std::io::prelude::*; - use std::io::{IoSlice, SeekFrom}; + use std::io::IoSlice; use std::os::unix::prelude::*; use nix::fcntl::*; @@ -272,7 +272,7 @@ mod linux_android { .unwrap(); let mut res: String = String::new(); - tmp2.seek(SeekFrom::Start(0)).unwrap(); + tmp2.rewind().unwrap(); tmp2.read_to_string(&mut res).unwrap(); assert_eq!(res, String::from("bar")); From e0bfc3a4043441f2a64ec70c2dcfd1dcf9cc5423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 28 Nov 2022 10:53:49 +0200 Subject: [PATCH 216/358] Update to memoffset 0.7 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index dc854c5ff4..dbce0df474 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ pin-utils = { version = "0.1.0", optional = true } static_assertions = "1" [target.'cfg(not(target_os = "redox"))'.dependencies] -memoffset = { version = "0.6.3", optional = true } +memoffset = { version = "0.7", optional = true } [features] default = [ From 006fc6f7975b3a6b64329847b780622aab392109 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 28 Nov 2022 13:14:06 -0500 Subject: [PATCH 217/358] Update use of libc::timespec to prepare for future libc version In a future release of the `libc` crate, `libc::timespec` will contain private padding fields on `*-linux-musl` targets and so the struct will no longer be able to be created using the literal initialization syntax. Update places where `libc::timespec` is created to first zero initialize the value and then update the `tv_sec` and `tv_nsec` fields manually. Many of these places are in `const fn`s so a helper function `zero_init_timespec()` is introduced to help with this as `std::mem::MaybeUninit::zeroed()` is not a `const` function. Some matches on `libc::timespec` are also updated to include a trailing `..` pattern which works when `libc::timespec` has additional, private fields as well as when it does not (like for `x86_64-unknown-linux-gnu`). --- src/sys/time.rs | 68 ++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/sys/time.rs b/src/sys/time.rs index a724084950..0042c45084 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -6,6 +6,13 @@ use std::convert::From; use std::time::Duration; use std::{cmp, fmt, ops}; +const fn zero_init_timespec() -> timespec { + // `std::mem::MaybeUninit::zeroed()` is not yet a const fn + // (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of + // the appropriate size to zero and then transmute it to a timespec value. + unsafe { std::mem::transmute([0u8; std::mem::size_of::()]) } +} + #[cfg(any( all(feature = "time", any(target_os = "android", target_os = "linux")), all( @@ -20,7 +27,7 @@ use std::{cmp, fmt, ops}; ) ))] pub(crate) mod timer { - use crate::sys::time::TimeSpec; + use crate::sys::time::{zero_init_timespec, TimeSpec}; use bitflags::bitflags; #[derive(Debug, Clone, Copy)] @@ -29,14 +36,8 @@ pub(crate) mod timer { impl TimerSpec { pub const fn none() -> Self { Self(libc::itimerspec { - it_interval: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, - it_value: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, + it_interval: zero_init_timespec(), + it_value: zero_init_timespec(), }) } } @@ -57,10 +58,7 @@ pub(crate) mod timer { fn from(expiration: Expiration) -> TimerSpec { match expiration { Expiration::OneShot(t) => TimerSpec(libc::itimerspec { - it_interval: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, + it_interval: zero_init_timespec(), it_value: *t.as_ref(), }), Expiration::IntervalDelayed(start, interval) => { @@ -118,6 +116,7 @@ pub(crate) mod timer { libc::timespec { tv_sec: 0, tv_nsec: 0, + .. }, it_value: ts, }) => Expiration::OneShot(ts.into()), @@ -257,18 +256,17 @@ impl PartialOrd for TimeSpec { impl TimeValLike for TimeSpec { #[inline] + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 fn seconds(seconds: i64) -> TimeSpec { assert!( (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds), "TimeSpec out of bounds; seconds={}", seconds ); - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - TimeSpec(timespec { - tv_sec: seconds as time_t, - tv_nsec: 0, - }) + let mut ts = zero_init_timespec(); + ts.tv_sec = seconds as time_t; + TimeSpec(ts) } #[inline] @@ -292,18 +290,18 @@ impl TimeValLike for TimeSpec { /// Makes a new `TimeSpec` with given number of nanoseconds. #[inline] + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 fn nanoseconds(nanoseconds: i64) -> TimeSpec { let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); assert!( (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs), "TimeSpec out of bounds" ); - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - TimeSpec(timespec { - tv_sec: secs as time_t, - tv_nsec: nanos as timespec_tv_nsec_t, - }) + let mut ts = zero_init_timespec(); + ts.tv_sec = secs as time_t; + ts.tv_nsec = nanos as timespec_tv_nsec_t; + TimeSpec(ts) } // The cast is not unnecessary on all platforms. @@ -337,10 +335,10 @@ impl TimeSpec { /// Construct a new `TimeSpec` from its components #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self { - Self(timespec { - tv_sec: seconds, - tv_nsec: nanoseconds, - }) + let mut ts = zero_init_timespec(); + ts.tv_sec = seconds; + ts.tv_nsec = nanoseconds; + Self(ts) } fn nanos_mod_sec(&self) -> timespec_tv_nsec_t { @@ -360,13 +358,13 @@ impl TimeSpec { self.0.tv_nsec } + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 pub const fn from_duration(duration: Duration) -> Self { - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - TimeSpec(timespec { - tv_sec: duration.as_secs() as time_t, - tv_nsec: duration.subsec_nanos() as timespec_tv_nsec_t, - }) + let mut ts = zero_init_timespec(); + ts.tv_sec = duration.as_secs() as time_t; + ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t; + TimeSpec(ts) } pub const fn from_timespec(timespec: timespec) -> Self { From 92dd75475915990ab8804f01833964d990a9aeea Mon Sep 17 00:00:00 2001 From: Jonathan Date: Mon, 21 Nov 2022 01:59:17 +0000 Subject: [PATCH 218/358] PollFd utility functions --- CHANGELOG.md | 3 +++ src/poll.rs | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 267d18097d..d406c1bc8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added `SockaddrStorage::{as_unix_addr, as_unix_addr_mut}` ([#1871](https://github.com/nix-rust/nix/pull/1871)) - Added `MntFlags` and `unmount` on all of the BSDs. +- Added `any()` and `all()` to `poll::PollFd`. + ([#1877](https://github.com/nix-rust/nix/pull/1877)) +- Add `MntFlags` and `unmount` on all of the BSDs. ([#1849](https://github.com/nix-rust/nix/pull/1849)) - Added a 'Statfs::flags' method. ([#1849](https://github.com/nix-rust/nix/pull/1849)) diff --git a/src/poll.rs b/src/poll.rs index e1baa814f1..6f227fee9e 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -37,6 +37,26 @@ impl PollFd { PollFlags::from_bits(self.pollfd.revents) } + /// Returns if any of the events of interest occured in the last call to `poll` or `ppoll`. Will + /// only return `None` if the kernel provides status flags that Nix does not know about. + /// + /// Equivalent to `x.revents()? != PollFlags::empty()`. + /// + /// This is marginally more efficient than [`PollFd::all`]. + pub fn any(self) -> Option { + Some(self.revents()? != PollFlags::empty()) + } + + /// Returns if all the events of interest occured in the last call to `poll` or `ppoll`. Will + /// only return `None` if the kernel provides status flags that Nix does not know about. + /// + /// Equivalent to `x.revents()? & x.events() == x.events()`. + /// + /// This is marginally less efficient than [`PollFd::any`]. + pub fn all(self) -> Option { + Some(self.revents()? & self.events() == self.events()) + } + /// The events of interest for this `PollFd`. pub fn events(self) -> PollFlags { PollFlags::from_bits(self.pollfd.events).unwrap() From 9e6951fd16582a0e7c813380439d572af1da3271 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 28 Nov 2022 21:01:57 -0700 Subject: [PATCH 219/358] Elaborate CHANGELOG entry for PR #1788 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d43c9fbea..d11b155572 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,7 +46,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fix `User::from_uid` and `User::from_name` crash on Android platform. ([#1824](https://github.com/nix-rust/nix/pull/1824)) - Workaround XNU bug causing netmasks returned by `getifaddrs` to misbehave. - (#1709) + ([#1788](https://github.com/nix-rust/nix/pull/1788)) ### Removed From 345fd36f1745ea4a99143353feb8c805cfe413ce Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 28 Nov 2022 21:35:45 -0700 Subject: [PATCH 220/358] [skip ci] fix CHANGELOG formatting --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9ec6b408e..88035d608f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1877](https://github.com/nix-rust/nix/pull/1877)) - Add `MntFlags` and `unmount` on all of the BSDs. ([#1849](https://github.com/nix-rust/nix/pull/1849)) -- Added a 'Statfs::flags' method. +- Added a `Statfs::flags` method. ([#1849](https://github.com/nix-rust/nix/pull/1849)) - Added `NSFS_MAGIC` FsType on Linux and Android. ([#1829](https://github.com/nix-rust/nix/pull/1829)) From ff219e3c42f3a3929407af0b1532a52e3dcf3227 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 28 Nov 2022 22:18:29 -0700 Subject: [PATCH 221/358] [skip ci] add CHANGELOG entries for old point releases. I opted to preserve explicit entries for backports in both the original feature release and the backported point release, rather than trying to pretend that the releases were actually sequential. Also, remove some empty subsections from the file. --- CHANGELOG.md | 113 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 100 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88035d608f..4110fc263c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -385,6 +385,30 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Removed `SigevNotify` on OpenBSD and Redox. (#[1511](https://github.com/nix-rust/nix/pull/1511)) +## [0.22.3] - 22 January 2022 +### Changed +- Relaxed the bitflags requirement from 1.3.1 to 1.1. This partially reverts + #1492. From now on, the MSRV is not guaranteed to work with all versions of + all dependencies, just with some version of all dependencies. + (#[1607](https://github.com/nix-rust/nix/pull/1607)) + +## [0.22.2] - 28 September 2021 +### Fixed +- Fixed buffer overflow in `unistd::getgrouplist`. + (#[1545](https://github.com/nix-rust/nix/pull/1545)) +- Added more errno definitions for better backwards compatibility with + Nix 0.21.0. + (#[1467](https://github.com/nix-rust/nix/pull/1467)) + +## [0.22.1] - 13 August 2021 +### Fixed +- Locked bitflags to < 1.3.0 to fix the build with rust < 1.46.0. + +### Removed +- Removed a couple of termios constants on redox that were never actually + supported. + (#[1483](https://github.com/nix-rust/nix/pull/1483)) + ## [0.22.0] - 9 July 2021 ### Added - Added `if_nameindex` (#[1445](https://github.com/nix-rust/nix/pull/1445)) @@ -410,8 +434,19 @@ This project adheres to [Semantic Versioning](https://semver.org/). `nix::Error::EINVAL`. ([#1446](https://github.com/nix-rust/nix/pull/1446)) +## [0.21.2] - 29 September 2021 +### Fixed +- Fixed buffer overflow in `unistd::getgrouplist`. + (#[1545](https://github.com/nix-rust/nix/pull/1545)) + +## [0.21.1] - 13 August 2021 ### Fixed +- Locked bitflags to < 1.3.0 to fix the build with rust < 1.46.0. + ### Removed +- Removed a couple of termios constants on redox that were never actually + supported. + (#[1483](https://github.com/nix-rust/nix/pull/1483)) ## [0.21.0] - 31 May 2021 ### Added @@ -467,6 +502,20 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Removed some Errno values from platforms where they aren't actually defined. (#[1452](https://github.com/nix-rust/nix/pull/1452)) +## [0.20.2] - 28 September 2021 +### Fixed +- Fixed buffer overflow in `unistd::getgrouplist`. + (#[1545](https://github.com/nix-rust/nix/pull/1545)) + +## [0.20.1] - 13 August 2021 +### Fixed +- Locked bitflags to < 1.3.0 to fix the build with rust < 1.46.0. + +### Removed +- Removed a couple of termios constants on redox that were never actually + supported. + (#[1483](https://github.com/nix-rust/nix/pull/1483)) + ## [0.20.0] - 20 February 2021 ### Added @@ -530,8 +579,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1278](https://github.com/nix-rust/nix/pull/1278)) - Made `unistd::fork` an unsafe funtion, bringing it in line with [libstd's decision](https://github.com/rust-lang/rust/pull/58059). (#[1293](https://github.com/nix-rust/nix/pull/1293)) -### Fixed -### Removed ## [0.18.0] - 26 July 2020 ### Added @@ -644,22 +691,16 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Added - Add `CLK_TCK` to `SysconfVar` (#[1177](https://github.com/nix-rust/nix/pull/1177)) -### Changed -### Fixed ### Removed - Removed deprecated Error::description from error types (#[1175](https://github.com/nix-rust/nix/pull/1175)) ## [0.16.1] - 23 December 2019 -### Added -### Changed ### Fixed - Fixed the build for OpenBSD (#[1168](https://github.com/nix-rust/nix/pull/1168)) -### Removed - ## [0.16.0] - 1 December 2019 ### Added - Added `ptrace::seize()`: similar to `attach()` on Linux @@ -787,8 +828,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Enabled `sched_yield` for all nix hosts. ([#1090](https://github.com/nix-rust/nix/pull/1090)) -### Removed - ## [0.14.1] - 2019-06-06 ### Added - Macros exported by `nix` may now be imported via `use` on the Rust 2018 @@ -813,8 +852,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fix the build on Android and Linux/mips with recent versions of libc. ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) -### Removed - ## [0.14.0] - 2019-05-21 ### Added - Add IP_RECVIF & IP_RECVDSTADDR. Enable IP_PKTINFO and IP6_PKTINFO on netbsd/openbsd. @@ -883,6 +920,23 @@ This project adheres to [Semantic Versioning](https://semver.org/). should've been defined in the first place. ([#1055](https://github.com/nix-rust/nix/pull/1055)) +## [0.13.1] - 2019-06-10 +### Changed +- Changed some public types from reexports of libc types like `uint32_t` to the + native equivalents like `u32.` + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) + +### Fixed +- Fix the build on Android and Linux/mips with recent versions of libc. + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) +- Fixed build on Linux/arm and Linux/s390x with the latest Rust libc + ([52102cb](https://github.com/nix-rust/nix/commit/52102cb76398c4dfb9ea141b98c5b01a2e050973)) + +### Removed +- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX + and iOS. + ([#1033](https://github.com/nix-rust/nix/pull/1033)) + ## [0.13.0] - 2019-01-15 ### Added - Added PKTINFO(V4) & V6PKTINFO cmsg support - Android/FreeBSD/iOS/Linux/MacOS. @@ -900,14 +954,30 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added an `mprotect` wrapper. ([#991](https://github.com/nix-rust/nix/pull/991)) -### Changed ### Fixed - `lutimes` never worked on OpenBSD as it is not implemented on OpenBSD. It has been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000)) - `fexecve` never worked on NetBSD or on OpenBSD as it is not implemented on either OS. It has been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000)) +## [0.12.1] 2019-06-08 +### Changed +- Changed some public types from reexports of libc types like `uint32_t` to the + native equivalents like `u32.` + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) + +### Fixed +- Fix the build on Android and Linux/mips with recent versions of libc. + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) +- Fixed build on Linux/arm and Linux/s390x with the latest Rust libc + ([52102cb](https://github.com/nix-rust/nix/commit/52102cb76398c4dfb9ea141b98c5b01a2e050973)) + ### Removed +- `fexecve` never worked on NetBSD or on OpenBSD as it is not implemented on + either OS. It has been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000)) +- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX + and iOS. + ([#1033](https://github.com/nix-rust/nix/pull/1033)) ## [0.12.0] 2018-11-28 @@ -959,7 +1029,24 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed passing multiple file descriptors over Unix Sockets. ([#918](https://github.com/nix-rust/nix/pull/918)) +## [0.11.1] 2019-06-06 +### Changed +- Changed some public types from reexports of libc types like `uint32_t` to the + native equivalents like `u32.` + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) + +### Fixed +- Fix the build on Android and Linux/mips with recent versions of libc. + ([#1072](https://github.com/nix-rust/nix/pull/1072/commits)) +- Fixed build on Linux/arm and Linux/s390x with the latest Rust libc + ([52102cb](https://github.com/nix-rust/nix/commit/52102cb76398c4dfb9ea141b98c5b01a2e050973)) + ### Removed +- `fexecve` never worked on NetBSD or on OpenBSD as it is not implemented on + either OS. It has been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000)) +- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX + and iOS. + ([#1033](https://github.com/nix-rust/nix/pull/1033)) ## [0.11.0] 2018-06-01 From 17e56e1f38144c3afa7f04de45e4b20b75333617 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 28 Nov 2022 22:26:33 -0700 Subject: [PATCH 222/358] Prepare for release 0.26.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index dbce0df474..b7bdc6bf54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { git = "https://github.com/rust-lang/libc", rev = "cc19b6f0801", features = [ "extra_traits" ] } +libc = { version = "0.2.137", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } From e0af65b0a0b362499e61e8cad234debbd0fe0b45 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 28 Nov 2022 22:56:21 -0700 Subject: [PATCH 223/358] (cargo-release) version 0.26.0 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4110fc263c..029d585953 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). -## [Unreleased] - ReleaseDate +## [0.26.0] - 2022-11-29 ### Added - Added `SockaddrStorage::{as_unix_addr, as_unix_addr_mut}` diff --git a/Cargo.toml b/Cargo.toml index b7bdc6bf54..48fab2632c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2018" -version = "0.25.0" +version = "0.26.0" rust-version = "1.56" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" From 12fb35434f04dccf941c3e1e52fb98df6cea41e6 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 28 Nov 2022 23:00:24 -0700 Subject: [PATCH 224/358] [skip ci] add a CHANGELOG section for the next release --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 029d585953..1f83dd7b40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +## [Unreleased] - ReleaseDate +### Added +### Changed +### Fixed +### Removed + ## [0.26.0] - 2022-11-29 ### Added From 8e91b28b64bdd18fc6fa61af8e89947ad7fb97bf Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Thu, 15 Sep 2022 14:58:56 -0600 Subject: [PATCH 225/358] Fix UB in the SO_TYPE sockopt When reading a value into an enum from getsockopt, we must validate it. Failing to do so can lead to UB for example with SOCK_PACKET on Linux. Perform the validation in GetSockOpt::get. Currently SockType is the only type that requires validation. Fixes #1819 --- CHANGELOG.md | 3 +++ src/sys/socket/mod.rs | 20 +++++++++++++++++++- src/sys/socket/sockopt.rs | 13 ++++++++++--- test/sys/test_sockopt.rs | 27 +++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f83dd7b40..882c57674d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Added ### Changed ### Fixed +- Fix UB with `sys::socket::sockopt::SockType` using `SOCK_PACKET`. + ([#1821](https://github.com/nix-rust/nix/pull/1821)) + ### Removed ## [0.26.0] - 2022-11-29 diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index a07025856e..2d7159a63a 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -12,7 +12,7 @@ use libc::{ self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, }; -use std::convert::TryInto; +use std::convert::{TryFrom, TryInto}; use std::io::{IoSlice, IoSliceMut}; #[cfg(feature = "net")] use std::net; @@ -107,6 +107,24 @@ pub enum SockType { #[cfg(not(any(target_os = "haiku")))] Rdm = libc::SOCK_RDM, } +// The TryFrom impl could've been derived using libc_enum!. But for +// backwards-compatibility with Nix-0.25.0 we manually implement it, so as to +// keep the old variant names. +impl TryFrom for SockType { + type Error = crate::Error; + + fn try_from(x: i32) -> Result { + match x { + libc::SOCK_STREAM => Ok(Self::Stream), + libc::SOCK_DGRAM => Ok(Self::Datagram), + libc::SOCK_SEQPACKET => Ok(Self::SeqPacket), + libc::SOCK_RAW => Ok(Self::Raw), + #[cfg(not(any(target_os = "haiku")))] + libc::SOCK_RDM => Ok(Self::Rdm), + _ => Err(Errno::EINVAL) + } + } +} /// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) /// to specify the protocol to use. diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 7489858ee3..06e9ee4563 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -6,7 +6,10 @@ use crate::Result; use cfg_if::cfg_if; use libc::{self, c_int, c_void, socklen_t}; use std::ffi::{OsStr, OsString}; -use std::mem::{self, MaybeUninit}; +use std::{ + convert::TryFrom, + mem::{self, MaybeUninit} +}; #[cfg(target_family = "unix")] use std::os::unix::ffi::OsStrExt; use std::os::unix::io::RawFd; @@ -102,7 +105,10 @@ macro_rules! getsockopt_impl { ); Errno::result(res)?; - Ok(getter.assume_init()) + match <$ty>::try_from(getter.assume_init()) { + Err(_) => Err(Errno::EINVAL), + Ok(r) => Ok(r) + } } } } @@ -629,7 +635,8 @@ sockopt_impl!( GetOnly, libc::SOL_SOCKET, libc::SO_TYPE, - super::SockType + super::SockType, + GetStruct ); sockopt_impl!( /// Returns a value indicating whether or not this socket has been marked to diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 47b01c1605..34bef945e1 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -151,6 +151,33 @@ fn test_so_tcp_maxseg() { close(ssock).unwrap(); } +#[test] +fn test_so_type() { + let sockfd = socket( + AddressFamily::Inet, + SockType::Stream, + SockFlag::empty(), + None, + ) + .unwrap(); + + assert_eq!(Ok(SockType::Stream), getsockopt(sockfd, sockopt::SockType)); +} + +/// getsockopt(_, sockopt::SockType) should gracefully handle unknown socket +/// types. Regression test for https://github.com/nix-rust/nix/issues/1819 +#[cfg(any(target_os = "android", target_os = "linux",))] +#[test] +fn test_so_type_unknown() { + use nix::errno::Errno; + + require_capability!("test_so_type", CAP_NET_RAW); + let sockfd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) }; + assert!(sockfd >= 0, "Error opening socket: {}", nix::Error::last()); + + assert_eq!(Err(Errno::EINVAL), getsockopt(sockfd, sockopt::SockType)); +} + // The CI doesn't supported getsockopt and setsockopt on emulated processors. // It's believed that a QEMU issue, the tests run ok on a fully emulated system. // Current CI just run the binary with QEMU but the Kernel remains the same as the host. From e7a646ddff63b912b3a5afab6464465d800de350 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 28 Nov 2022 23:28:58 -0700 Subject: [PATCH 226/358] (cargo-release) version 0.26.1 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 882c57674d..a332bc5f09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). -## [Unreleased] - ReleaseDate +## [0.26.1] - 2022-11-29 ### Added ### Changed ### Fixed diff --git a/Cargo.toml b/Cargo.toml index 48fab2632c..cfe20d8297 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2018" -version = "0.26.0" +version = "0.26.1" rust-version = "1.56" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" From f263f453a351a1fa3eeffe7d115a9e85ac76541e Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 28 Nov 2022 23:30:33 -0700 Subject: [PATCH 227/358] [skip ci] add a CHANGELOG section for the next release --- CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a332bc5f09..e1ed2e8a63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,15 +3,17 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). -## [0.26.1] - 2022-11-29 +## [Unreleased] - ReleaseDate ### Added ### Changed ### Fixed +### Removed + +## [0.26.1] - 2022-11-29 +### Fixed - Fix UB with `sys::socket::sockopt::SockType` using `SOCK_PACKET`. ([#1821](https://github.com/nix-rust/nix/pull/1821)) -### Removed - ## [0.26.0] - 2022-11-29 ### Added From d08d4e2f15042ba09aab9fe0e66ab2bdff81cb16 Mon Sep 17 00:00:00 2001 From: Emils Date: Wed, 16 Nov 2022 15:38:34 +0000 Subject: [PATCH 228/358] Add routing socket type --- CHANGELOG.md | 3 +++ src/sys/socket/addr.rs | 5 +++++ src/sys/socket/mod.rs | 12 ++++++++++++ 3 files changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1ed2e8a63..129d93f212 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Add `PF_ROUTE` to `SockType` on macOS, iOS, all of the BSDs, Fuchsia, Haiku, Illumos. + ([#1867](https://github.com/nix-rust/nix/pull/1867)) + ### Changed ### Fixed ### Removed diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 8b23b10cf0..55a7b2ffca 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -80,6 +80,9 @@ pub enum AddressFamily { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Netlink = libc::AF_NETLINK, + /// Kernel interface for interacting with the routing table + #[cfg(not(any(target_os = "redox", target_os = "linux", target_os = "android")))] + Route = libc::PF_ROUTE, /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html)) #[cfg(any( target_os = "android", @@ -421,6 +424,8 @@ impl AddressFamily { libc::AF_NETLINK => Some(AddressFamily::Netlink), #[cfg(any(target_os = "macos", target_os = "macos"))] libc::AF_SYSTEM => Some(AddressFamily::System), + #[cfg(not(any(target_os = "redox", target_os = "linux", target_os = "android")))] + libc::PF_ROUTE => Some(AddressFamily::Route), #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_PACKET => Some(AddressFamily::Packet), #[cfg(any( diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 2d7159a63a..154403c5fd 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -2484,4 +2484,16 @@ mod tests { fn can_use_cmsg_space() { let _ = cmsg_space!(u8); } + + #[cfg(not(any(target_os = "redox", target_os = "linux", target_os = "android")))] + #[test] + fn can_open_routing_socket() { + let _ = super::socket( + super::AddressFamily::Route, + super::SockType::Raw, + super::SockFlag::empty(), + None, + ) + .expect("Failed to open routing socket"); + } } From d26534fb8081031548509d67863a1e2defe92ca7 Mon Sep 17 00:00:00 2001 From: Ryan Zoeller Date: Fri, 2 Dec 2022 19:43:25 -0600 Subject: [PATCH 229/358] Enable ucontext module on aarch64-unknown-linux-gnu --- CHANGELOG.md | 4 +++- Cargo.toml | 2 +- src/lib.rs | 7 ++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 129d93f212..4ac9dec5c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Added - Add `PF_ROUTE` to `SockType` on macOS, iOS, all of the BSDs, Fuchsia, Haiku, Illumos. ([#1867](https://github.com/nix-rust/nix/pull/1867)) +- Added `nix::ucontext` module on `aarch64-unknown-linux-gnu`. + (#[1662](https://github.com/nix-rust/nix/pull/1662)) ### Changed ### Fixed @@ -213,7 +215,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1563](https://github.com/nix-rust/nix/pull/1563)) - Added `process_vm_readv` and `process_vm_writev` on Android. (#[1557](https://github.com/nix-rust/nix/pull/1557)) -- Added `nix::uncontext` module on s390x. +- Added `nix::ucontext` module on s390x. (#[1662](https://github.com/nix-rust/nix/pull/1662)) - Implemented `Extend`, `FromIterator`, and `IntoIterator` for `SigSet` and added `SigSet::iter` and `SigSetIter`. diff --git a/Cargo.toml b/Cargo.toml index cfe20d8297..c337127f4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.137", features = [ "extra_traits" ] } +libc = { git = "https://github.com/rust-lang/libc", rev = "15d27952bfa93e5e4f419c603f275486f15a050c", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } diff --git a/src/lib.rs b/src/lib.rs index 6b82125761..6349d37e0f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -144,7 +144,12 @@ feature! { // provides bindings for them. #[cfg(all( target_os = "linux", - any(target_arch = "s390x", target_arch = "x86", target_arch = "x86_64") + any( + target_arch = "aarch64", + target_arch = "s390x", + target_arch = "x86", + target_arch = "x86_64" + ) ))] feature! { #![feature = "ucontext"] From fab11e97e22df216fd6fd6a663ce575780694b91 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sun, 6 Nov 2022 11:59:36 -0800 Subject: [PATCH 230/358] Nuke IoVec Signed-off-by: Alex Saveau --- CHANGELOG.md | 3 +++ src/sys/uio.rs | 72 -------------------------------------------------- 2 files changed, 3 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 129d93f212..3da3a509cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Fixed ### Removed +- Removed deprecated IoVec API. + ([#1855](https://github.com/nix-rust/nix/pull/1855)) + ## [0.26.1] - 2022-11-29 ### Fixed - Fix UB with `sys::socket::sockopt::SockType` using `SOCK_PACKET`. diff --git a/src/sys/uio.rs b/src/sys/uio.rs index b31c3068a7..7248bd0c04 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -4,7 +4,6 @@ use crate::errno::Errno; use crate::Result; use libc::{self, c_int, c_void, off_t, size_t}; use std::io::{IoSlice, IoSliceMut}; -use std::marker::PhantomData; use std::os::unix::io::RawFd; /// Low-level vectored write to a raw file descriptor @@ -145,77 +144,6 @@ pub struct RemoteIoVec { pub len: 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. -#[deprecated( - since = "0.24.0", - note = "`IoVec` is no longer used in the public interface, use `IoSlice` or `IoSliceMut` instead" -)] -#[repr(transparent)] -#[allow(renamed_and_removed_lints)] -#[allow(clippy::unknown_clippy_lints)] -// Clippy false positive: https://github.com/rust-lang/rust-clippy/issues/8867 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct IoVec(pub(crate) libc::iovec, PhantomData); - -#[allow(deprecated)] -impl IoVec { - /// View the `IoVec` as a Rust slice. - #[deprecated( - since = "0.24.0", - note = "Use the `Deref` impl of `IoSlice` or `IoSliceMut` instead" - )] - #[inline] - pub fn as_slice(&self) -> &[u8] { - use std::slice; - - unsafe { - slice::from_raw_parts(self.0.iov_base as *const u8, self.0.iov_len) - } - } -} - -#[allow(deprecated)] -impl<'a> IoVec<&'a [u8]> { - /// Create an `IoVec` from a Rust slice. - #[deprecated(since = "0.24.0", note = "Use `IoSlice::new` instead")] - pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> { - IoVec( - libc::iovec { - iov_base: buf.as_ptr() as *mut c_void, - iov_len: buf.len() as size_t, - }, - PhantomData, - ) - } -} - -#[allow(deprecated)] -impl<'a> IoVec<&'a mut [u8]> { - /// Create an `IoVec` from a mutable Rust slice. - #[deprecated(since = "0.24.0", note = "Use `IoSliceMut::new` instead")] - 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, - iov_len: buf.len() as size_t, - }, - PhantomData, - ) - } -} - -// The only reason IoVec isn't automatically Send+Sync is because libc::iovec -// contains raw pointers. -#[allow(deprecated)] -unsafe impl Send for IoVec where T: Send {} -#[allow(deprecated)] -unsafe impl Sync for IoVec where T: Sync {} - feature! { #![feature = "process"] From f3aa1affb0772e8b7ff1afb38783407bb558be4e Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Fri, 11 Nov 2022 19:47:39 -0800 Subject: [PATCH 231/358] Nuke deprecated net APIs Signed-off-by: Alex Saveau --- CHANGELOG.md | 2 + src/sys/socket/addr.rs | 656 ---------------------------------------- src/sys/socket/mod.rs | 103 +------ test/sys/test_socket.rs | 102 +------ 4 files changed, 17 insertions(+), 846 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5a2dc6714..d708ba72af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Removed deprecated IoVec API. ([#1855](https://github.com/nix-rust/nix/pull/1855)) +- Removed deprecated net APIs. + ([#1861](https://github.com/nix-rust/nix/pull/1861)) ## [0.26.1] - 2022-11-29 ### Fixed diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 55a7b2ffca..970e838122 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -33,8 +33,6 @@ use std::convert::TryInto; use std::ffi::OsStr; use std::hash::{Hash, Hasher}; use std::os::unix::ffi::OsStrExt; -#[cfg(any(target_os = "ios", target_os = "macos"))] -use std::os::unix::io::RawFd; use std::path::Path; use std::{fmt, mem, net, ptr, slice}; @@ -445,308 +443,6 @@ impl AddressFamily { } } -feature! { -#![feature = "net"] - -#[deprecated( - since = "0.24.0", - note = "use SockaddrIn, SockaddrIn6, or SockaddrStorage instead" -)] -#[allow(missing_docs)] // Since they're all deprecated anyway -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum InetAddr { - V4(libc::sockaddr_in), - V6(libc::sockaddr_in6), -} - -#[allow(missing_docs)] // It's deprecated anyway -#[allow(deprecated)] -impl InetAddr { - #[allow(clippy::needless_update)] // It isn't needless on all OSes - pub fn from_std(std: &net::SocketAddr) -> InetAddr { - match *std { - net::SocketAddr::V4(ref addr) => { - InetAddr::V4(libc::sockaddr_in { - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "haiku", target_os = "hermit", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] - sin_len: mem::size_of::() as u8, - sin_family: AddressFamily::Inet as sa_family_t, - sin_port: addr.port().to_be(), // network byte order - sin_addr: Ipv4Addr::from_std(addr.ip()).0, - .. unsafe { mem::zeroed() } - }) - } - net::SocketAddr::V6(ref addr) => { - InetAddr::V6(libc::sockaddr_in6 { - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", - target_os = "haiku", target_os = "hermit", - target_os = "ios", target_os = "macos", - target_os = "netbsd", target_os = "openbsd"))] - sin6_len: mem::size_of::() as u8, - sin6_family: AddressFamily::Inet6 as sa_family_t, - sin6_port: addr.port().to_be(), // network byte order - sin6_addr: Ipv6Addr::from_std(addr.ip()).0, - sin6_flowinfo: addr.flowinfo(), // host byte order - sin6_scope_id: addr.scope_id(), // host byte order - .. unsafe { mem::zeroed() } - }) - } - } - } - - #[allow(clippy::needless_update)] // It isn't needless on all OSes - pub fn new(ip: IpAddr, port: u16) -> InetAddr { - match ip { - IpAddr::V4(ref ip) => { - InetAddr::V4(libc::sockaddr_in { - sin_family: AddressFamily::Inet as sa_family_t, - sin_port: port.to_be(), - sin_addr: ip.0, - .. unsafe { mem::zeroed() } - }) - } - IpAddr::V6(ref ip) => { - InetAddr::V6(libc::sockaddr_in6 { - sin6_family: AddressFamily::Inet6 as sa_family_t, - sin6_port: port.to_be(), - sin6_addr: ip.0, - .. unsafe { mem::zeroed() } - }) - } - } - } - /// Gets the IP address associated with this socket address. - pub const fn ip(&self) -> IpAddr { - match *self { - InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)), - InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)), - } - } - - /// Gets the port number associated with this socket address - pub const fn port(&self) -> u16 { - match *self { - InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port), - InetAddr::V4(ref sa) => u16::from_be(sa.sin_port), - } - } - - pub fn to_std(&self) -> net::SocketAddr { - match *self { - InetAddr::V4(ref sa) => net::SocketAddr::V4( - net::SocketAddrV4::new( - Ipv4Addr(sa.sin_addr).to_std(), - self.port())), - InetAddr::V6(ref sa) => net::SocketAddr::V6( - net::SocketAddrV6::new( - Ipv6Addr(sa.sin6_addr).to_std(), - self.port(), - sa.sin6_flowinfo, - sa.sin6_scope_id)), - } - } - - #[deprecated(since = "0.23.0", note = "use .to_string() instead")] - pub fn to_str(&self) -> String { - format!("{}", self) - } -} - -#[allow(deprecated)] -impl fmt::Display for InetAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()), - InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()), - } - } -} - -/* - * - * ===== IpAddr ===== - * - */ -#[allow(missing_docs)] // Since they're all deprecated anyway -#[allow(deprecated)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[deprecated( - since = "0.24.0", - note = "Use std::net::IpAddr instead" -)] -pub enum IpAddr { - V4(Ipv4Addr), - V6(Ipv6Addr), -} - -#[allow(deprecated)] -#[allow(missing_docs)] // Since they're all deprecated anyway -impl IpAddr { - /// Create a new IpAddr that contains an IPv4 address. - /// - /// The result will represent the IP address a.b.c.d - pub const fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr { - IpAddr::V4(Ipv4Addr::new(a, b, c, d)) - } - - /// Create a new IpAddr that contains an IPv6 address. - /// - /// The result will represent the IP address a:b:c:d:e:f - #[allow(clippy::many_single_char_names)] - #[allow(clippy::too_many_arguments)] - pub const fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr { - IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)) - } - - pub fn from_std(std: &net::IpAddr) -> IpAddr { - match *std { - net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)), - net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)), - } - } - - pub const fn to_std(&self) -> net::IpAddr { - match *self { - IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()), - IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()), - } - } -} - -#[allow(deprecated)] -impl fmt::Display for IpAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - IpAddr::V4(ref v4) => v4.fmt(f), - IpAddr::V6(ref v6) => v6.fmt(f) - } - } -} - -/* - * - * ===== Ipv4Addr ===== - * - */ - -#[deprecated( - since = "0.24.0", - note = "Use std::net::Ipv4Addr instead" -)] -#[allow(missing_docs)] // Since they're all deprecated anyway -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct Ipv4Addr(pub libc::in_addr); - -#[allow(deprecated)] -#[allow(missing_docs)] // Since they're all deprecated anyway -impl Ipv4Addr { - #[allow(clippy::identity_op)] // More readable this way - pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { - let ip = (((a as u32) << 24) | - ((b as u32) << 16) | - ((c as u32) << 8) | - ((d as u32) << 0)).to_be(); - - Ipv4Addr(libc::in_addr { s_addr: ip }) - } - - // Use pass by reference for symmetry with Ipv6Addr::from_std - #[allow(clippy::trivially_copy_pass_by_ref)] - pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr { - let bits = std.octets(); - Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) - } - - pub const fn any() -> Ipv4Addr { - Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY }) - } - - pub const fn octets(self) -> [u8; 4] { - let bits = u32::from_be(self.0.s_addr); - [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] - } - - pub const fn to_std(self) -> net::Ipv4Addr { - let bits = self.octets(); - net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]) - } -} - -#[allow(deprecated)] -impl fmt::Display for Ipv4Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let octets = self.octets(); - write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) - } -} - -/* - * - * ===== Ipv6Addr ===== - * - */ - -#[deprecated( - since = "0.24.0", - note = "Use std::net::Ipv6Addr instead" -)] -#[allow(missing_docs)] // Since they're all deprecated anyway -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[repr(transparent)] -pub struct Ipv6Addr(pub libc::in6_addr); - -// Note that IPv6 addresses are stored in big endian order on all architectures. -// See https://tools.ietf.org/html/rfc1700 or consult your favorite search -// engine. - -macro_rules! to_u8_array { - ($($num:ident),*) => { - [ $(($num>>8) as u8, ($num&0xff) as u8,)* ] - } -} - -macro_rules! to_u16_array { - ($slf:ident, $($first:expr, $second:expr),*) => { - [$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*] - } -} - -#[allow(deprecated)] -#[allow(missing_docs)] // Since they're all deprecated anyway -impl Ipv6Addr { - #[allow(clippy::many_single_char_names)] - #[allow(clippy::too_many_arguments)] - pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { - Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)}) - } - - pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr { - let s = std.segments(); - Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) - } - - /// Return the eight 16-bit segments that make up this address - pub const fn segments(&self) -> [u16; 8] { - to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) - } - - pub const fn to_std(&self) -> net::Ipv6Addr { - let s = self.segments(); - net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]) - } -} - -#[allow(deprecated)] -impl fmt::Display for Ipv6Addr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - self.to_std().fmt(fmt) - } -} -} - /// A wrapper around `sockaddr_un`. #[derive(Clone, Copy, Debug)] #[repr(C)] @@ -1982,358 +1678,6 @@ mod private { } } -/// Represents a socket address -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[deprecated( - since = "0.24.0", - note = "use SockaddrLike or SockaddrStorage instead" -)] -#[allow(missing_docs)] // Since they're all deprecated anyway -#[allow(deprecated)] -#[non_exhaustive] -pub enum SockAddr { - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Inet(InetAddr), - Unix(UnixAddr), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Netlink(NetlinkAddr), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Alg(AlgAddr), - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] - SysControl(SysControlAddr), - /// Datalink address (MAC) - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - #[cfg_attr(docsrs, doc(cfg(feature = "net")))] - Link(LinkAddr), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - Vsock(VsockAddr), -} - -#[allow(missing_docs)] // Since they're all deprecated anyway -#[allow(deprecated)] -impl SockAddr { - feature! { - #![feature = "net"] - pub fn new_inet(addr: InetAddr) -> SockAddr { - SockAddr::Inet(addr) - } - } - - pub fn new_unix(path: &P) -> Result { - Ok(SockAddr::Unix(UnixAddr::new(path)?)) - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_netlink(pid: u32, groups: u32) -> SockAddr { - SockAddr::Netlink(NetlinkAddr::new(pid, groups)) - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr { - SockAddr::Alg(AlgAddr::new(alg_type, alg_name)) - } - - feature! { - #![feature = "ioctl"] - #[cfg(any(target_os = "ios", target_os = "macos"))] - pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result { - SysControlAddr::from_name(sockfd, name, unit).map(SockAddr::SysControl) - } - } - - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn new_vsock(cid: u32, port: u32) -> SockAddr { - SockAddr::Vsock(VsockAddr::new(cid, port)) - } - - pub fn family(&self) -> AddressFamily { - match *self { - #[cfg(feature = "net")] - SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet, - #[cfg(feature = "net")] - SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6, - SockAddr::Unix(..) => AddressFamily::Unix, - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Netlink(..) => AddressFamily::Netlink, - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Alg(..) => AddressFamily::Alg, - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - SockAddr::SysControl(..) => AddressFamily::System, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - SockAddr::Link(..) => AddressFamily::Packet, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - SockAddr::Link(..) => AddressFamily::Link, - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Vsock(..) => AddressFamily::Vsock, - } - } - - #[deprecated(since = "0.23.0", note = "use .to_string() instead")] - pub fn to_str(&self) -> String { - format!("{}", self) - } - - /// Creates a `SockAddr` struct from libc's sockaddr. - /// - /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System. - /// Returns None for unsupported families. - /// - /// # Safety - /// - /// unsafe because it takes a raw pointer as argument. The caller must - /// ensure that the pointer is valid. - #[cfg(not(target_os = "fuchsia"))] - #[cfg(feature = "net")] - pub(crate) unsafe fn from_libc_sockaddr( - addr: *const libc::sockaddr, - ) -> Option { - if addr.is_null() { - None - } else { - match AddressFamily::from_i32(i32::from((*addr).sa_family)) { - Some(AddressFamily::Unix) => None, - #[cfg(feature = "net")] - Some(AddressFamily::Inet) => Some(SockAddr::Inet( - InetAddr::V4(ptr::read_unaligned(addr as *const _)), - )), - #[cfg(feature = "net")] - Some(AddressFamily::Inet6) => Some(SockAddr::Inet( - InetAddr::V6(ptr::read_unaligned(addr as *const _)), - )), - #[cfg(any(target_os = "android", target_os = "linux"))] - Some(AddressFamily::Netlink) => Some(SockAddr::Netlink( - NetlinkAddr(ptr::read_unaligned(addr as *const _)), - )), - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - Some(AddressFamily::System) => Some(SockAddr::SysControl( - SysControlAddr(ptr::read_unaligned(addr as *const _)), - )), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - Some(AddressFamily::Packet) => Some(SockAddr::Link(LinkAddr( - ptr::read_unaligned(addr as *const _), - ))), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - Some(AddressFamily::Link) => { - let ether_addr = - LinkAddr(ptr::read_unaligned(addr as *const _)); - if ether_addr.is_empty() { - None - } else { - Some(SockAddr::Link(ether_addr)) - } - } - #[cfg(any(target_os = "android", target_os = "linux"))] - Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(VsockAddr( - ptr::read_unaligned(addr as *const _), - ))), - // Other address families are currently not supported and simply yield a None - // entry instead of a proper conversion to a `SockAddr`. - Some(_) | None => None, - } - } - } - - /// Conversion from nix's SockAddr type to the underlying libc sockaddr type. - /// - /// This is useful for interfacing with other libc functions that don't yet have nix wrappers. - /// Returns a reference to the underlying data type (as a sockaddr reference) along - /// with the size of the actual data type. sockaddr is commonly used as a proxy for - /// a superclass as C doesn't support inheritance, so many functions that take - /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back. - pub fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) { - match *self { - #[cfg(feature = "net")] - SockAddr::Inet(InetAddr::V4(ref addr)) => ( - // This cast is always allowed in C - unsafe { - &*(addr as *const libc::sockaddr_in - as *const libc::sockaddr) - }, - mem::size_of_val(addr) as libc::socklen_t, - ), - #[cfg(feature = "net")] - SockAddr::Inet(InetAddr::V6(ref addr)) => ( - // This cast is always allowed in C - unsafe { - &*(addr as *const libc::sockaddr_in6 - as *const libc::sockaddr) - }, - mem::size_of_val(addr) as libc::socklen_t, - ), - SockAddr::Unix(ref unix_addr) => ( - // This cast is always allowed in C - unsafe { - &*(&unix_addr.sun as *const libc::sockaddr_un - as *const libc::sockaddr) - }, - unix_addr.sun_len() as libc::socklen_t, - ), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Netlink(NetlinkAddr(ref sa)) => ( - // This cast is always allowed in C - unsafe { - &*(sa as *const libc::sockaddr_nl as *const libc::sockaddr) - }, - mem::size_of_val(sa) as libc::socklen_t, - ), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Alg(AlgAddr(ref sa)) => ( - // This cast is always allowed in C - unsafe { - &*(sa as *const libc::sockaddr_alg as *const libc::sockaddr) - }, - mem::size_of_val(sa) as libc::socklen_t, - ), - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - SockAddr::SysControl(SysControlAddr(ref sa)) => ( - // This cast is always allowed in C - unsafe { - &*(sa as *const libc::sockaddr_ctl as *const libc::sockaddr) - }, - mem::size_of_val(sa) as libc::socklen_t, - ), - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - SockAddr::Link(LinkAddr(ref addr)) => ( - // This cast is always allowed in C - unsafe { - &*(addr as *const libc::sockaddr_ll - as *const libc::sockaddr) - }, - mem::size_of_val(addr) as libc::socklen_t, - ), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - SockAddr::Link(LinkAddr(ref addr)) => ( - // This cast is always allowed in C - unsafe { - &*(addr as *const libc::sockaddr_dl - as *const libc::sockaddr) - }, - mem::size_of_val(addr) as libc::socklen_t, - ), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Vsock(VsockAddr(ref sa)) => ( - // This cast is always allowed in C - unsafe { - &*(sa as *const libc::sockaddr_vm as *const libc::sockaddr) - }, - mem::size_of_val(sa) as libc::socklen_t, - ), - } - } -} - -#[allow(deprecated)] -impl fmt::Display for SockAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - #[cfg(feature = "net")] - SockAddr::Inet(ref inet) => inet.fmt(f), - SockAddr::Unix(ref unix) => unix.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Netlink(ref nl) => nl.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Alg(ref nl) => nl.fmt(f), - #[cfg(all( - feature = "ioctl", - any(target_os = "ios", target_os = "macos") - ))] - SockAddr::SysControl(ref sc) => sc.fmt(f), - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd" - ))] - #[cfg(feature = "net")] - SockAddr::Link(ref ether_addr) => ether_addr.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] - SockAddr::Vsock(ref svm) => svm.fmt(f), - } - } -} - -#[cfg(not(target_os = "fuchsia"))] -#[cfg(feature = "net")] -#[allow(deprecated)] -impl private::SockaddrLikePriv for SockAddr {} -#[cfg(not(target_os = "fuchsia"))] -#[cfg(feature = "net")] -#[allow(deprecated)] -impl SockaddrLike for SockAddr { - unsafe fn from_raw( - addr: *const libc::sockaddr, - _len: Option, - ) -> Option { - Self::from_libc_sockaddr(addr) - } -} - #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub mod netlink { diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 154403c5fd..5a16417131 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -12,7 +12,7 @@ use libc::{ self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, }; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryFrom; use std::io::{IoSlice, IoSliceMut}; #[cfg(feature = "net")] use std::net; @@ -32,32 +32,24 @@ pub mod sockopt; pub use self::addr::{SockaddrLike, SockaddrStorage}; -#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] -#[allow(deprecated)] -pub use self::addr::{AddressFamily, SockAddr, UnixAddr}; #[cfg(any(target_os = "illumos", target_os = "solaris"))] -#[allow(deprecated)] -pub use self::addr::{AddressFamily, SockAddr, UnixAddr}; -#[allow(deprecated)] +pub use self::addr::{AddressFamily, UnixAddr}; +#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] +pub use self::addr::{AddressFamily, UnixAddr}; #[cfg(not(any( target_os = "illumos", target_os = "solaris", target_os = "haiku" )))] #[cfg(feature = "net")] -pub use self::addr::{ - InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, LinkAddr, SockaddrIn, SockaddrIn6, -}; -#[allow(deprecated)] +pub use self::addr::{LinkAddr, SockaddrIn, SockaddrIn6}; #[cfg(any( target_os = "illumos", target_os = "solaris", target_os = "haiku" ))] #[cfg(feature = "net")] -pub use self::addr::{ - InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, SockaddrIn, SockaddrIn6, -}; +pub use self::addr::{SockaddrIn, SockaddrIn6}; #[cfg(any(target_os = "android", target_os = "linux"))] pub use crate::sys::socket::addr::alg::AlgAddr; @@ -121,7 +113,7 @@ impl TryFrom for SockType { libc::SOCK_RAW => Ok(Self::Raw), #[cfg(not(any(target_os = "haiku")))] libc::SOCK_RDM => Ok(Self::Rdm), - _ => Err(Errno::EINVAL) + _ => Err(Errno::EINVAL), } } } @@ -2376,81 +2368,6 @@ pub fn getsockname(fd: RawFd) -> Result { } } -/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a -/// certain size. -/// -/// In C this would usually be done by casting. The `len` argument -/// should be the number of bytes in the `sockaddr_storage` that are actually -/// allocated and valid. It must be at least as large as all the useful parts -/// of the structure. Note that in the case of a `sockaddr_un`, `len` need not -/// include the terminating null. -#[deprecated( - since = "0.24.0", - note = "use SockaddrLike or SockaddrStorage instead" -)] -#[allow(deprecated)] -pub fn sockaddr_storage_to_addr( - addr: &sockaddr_storage, - len: usize, -) -> Result { - assert!(len <= mem::size_of::()); - if len < mem::size_of_val(&addr.ss_family) { - return Err(Errno::ENOTCONN); - } - - match c_int::from(addr.ss_family) { - #[cfg(feature = "net")] - libc::AF_INET => { - assert!(len >= mem::size_of::()); - let sin = unsafe { - *(addr as *const sockaddr_storage as *const sockaddr_in) - }; - Ok(SockAddr::Inet(InetAddr::V4(sin))) - } - #[cfg(feature = "net")] - libc::AF_INET6 => { - assert!(len >= mem::size_of::()); - let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) }; - Ok(SockAddr::Inet(InetAddr::V6(sin6))) - } - libc::AF_UNIX => unsafe { - let sun = *(addr as *const _ as *const sockaddr_un); - let sun_len = len.try_into().unwrap(); - Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len))) - }, - #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg(feature = "net")] - libc::AF_PACKET => { - use libc::sockaddr_ll; - // Don't assert anything about the size. - // Apparently the Linux kernel can return smaller sizes when - // the value in the last element of sockaddr_ll (`sll_addr`) is - // smaller than the declared size of that field - let sll = unsafe { *(addr as *const _ as *const sockaddr_ll) }; - Ok(SockAddr::Link(LinkAddr(sll))) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_NETLINK => { - use libc::sockaddr_nl; - let snl = unsafe { *(addr as *const _ as *const sockaddr_nl) }; - Ok(SockAddr::Netlink(NetlinkAddr(snl))) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_ALG => { - use libc::sockaddr_alg; - let salg = unsafe { *(addr as *const _ as *const sockaddr_alg) }; - Ok(SockAddr::Alg(AlgAddr(salg))) - } - #[cfg(any(target_os = "android", target_os = "linux"))] - libc::AF_VSOCK => { - use libc::sockaddr_vm; - let svm = unsafe { *(addr as *const _ as *const sockaddr_vm) }; - Ok(SockAddr::Vsock(VsockAddr(svm))) - } - af => panic!("unexpected address family {}", af), - } -} - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum Shutdown { /// Further receptions will be disallowed. @@ -2485,7 +2402,11 @@ mod tests { let _ = cmsg_space!(u8); } - #[cfg(not(any(target_os = "redox", target_os = "linux", target_os = "android")))] + #[cfg(not(any( + target_os = "redox", + target_os = "linux", + target_os = "android" + )))] #[test] fn can_open_routing_socket() { let _ = super::socket( diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 5adc77ed6b..1413eb6b2e 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1,73 +1,15 @@ #[cfg(any(target_os = "linux", target_os = "android"))] use crate::*; -use libc::{c_char, sockaddr_storage}; -#[allow(deprecated)] -use nix::sys::socket::InetAddr; -use nix::sys::socket::{ - getsockname, sockaddr, sockaddr_in6, AddressFamily, UnixAddr, -}; +use libc::c_char; +use nix::sys::socket::{getsockname, AddressFamily, UnixAddr}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; -use std::mem::{self, MaybeUninit}; -use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::net::{SocketAddrV4, SocketAddrV6}; use std::os::unix::io::RawFd; use std::path::Path; use std::slice; use std::str::FromStr; -#[allow(deprecated)] -#[test] -pub fn test_inetv4_addr_to_sock_addr() { - let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); - let addr = InetAddr::from_std(&actual); - - match addr { - InetAddr::V4(addr) => { - let ip: u32 = 0x7f00_0001; - let port: u16 = 3000; - let saddr = addr.sin_addr.s_addr; - - assert_eq!(saddr, ip.to_be()); - assert_eq!(addr.sin_port, port.to_be()); - } - _ => panic!("nope"), - } - - assert_eq!(addr.to_string(), "127.0.0.1:3000"); - - let inet = addr.to_std(); - assert_eq!(actual, inet); -} - -#[allow(deprecated)] -#[test] -pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() { - use nix::sys::socket::{sockaddr_storage_to_addr, SockAddr}; - - let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); - let addr = InetAddr::from_std(&actual); - let sockaddr = SockAddr::new_inet(addr); - - let (storage, ffi_size) = { - let mut storage = MaybeUninit::::zeroed(); - let storage_ptr = storage.as_mut_ptr().cast::(); - let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); - assert_eq!(mem::size_of::(), ffi_size as usize); - unsafe { - storage_ptr.copy_from_nonoverlapping(ffi_ptr as *const sockaddr, 1); - (storage.assume_init(), ffi_size) - } - }; - - let from_storage = - sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); - assert_eq!(from_storage, sockaddr); - let from_storage = - sockaddr_storage_to_addr(&storage, mem::size_of::()) - .unwrap(); - assert_eq!(from_storage, sockaddr); -} - #[cfg(any(target_os = "linux"))] #[cfg_attr(qemu, ignore)] #[test] @@ -128,44 +70,6 @@ pub fn test_timestamping() { assert!(std::time::Duration::from(diff).as_secs() < 60); } -#[allow(deprecated)] -#[test] -pub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr() { - use nix::sys::socket::{sockaddr_storage_to_addr, SockAddr}; - - let port: u16 = 3000; - let flowinfo: u32 = 1; - let scope_id: u32 = 2; - let ip: Ipv6Addr = "fe80::1".parse().unwrap(); - - let actual = - SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id)); - let addr = InetAddr::from_std(&actual); - let sockaddr = SockAddr::new_inet(addr); - - let (storage, ffi_size) = { - let mut storage = MaybeUninit::::zeroed(); - let storage_ptr = storage.as_mut_ptr().cast::(); - let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); - assert_eq!(mem::size_of::(), ffi_size as usize); - unsafe { - storage_ptr.copy_from_nonoverlapping( - (ffi_ptr as *const sockaddr).cast::(), - 1, - ); - (storage.assume_init(), ffi_size) - } - }; - - let from_storage = - sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); - assert_eq!(from_storage, sockaddr); - let from_storage = - sockaddr_storage_to_addr(&storage, mem::size_of::()) - .unwrap(); - assert_eq!(from_storage, sockaddr); -} - #[test] pub fn test_path_to_sock_addr() { let path = "/foo/bar"; From c59cd2b846c71c6f366bd88cf50180aebca3c266 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 3 Dec 2022 16:46:42 -0700 Subject: [PATCH 232/358] Drop x86_64-unknown-darwin to Tier 2 And promote aarch64-unknown-darwin to Tier 1. Because that's what Cirrus CI is doing. Fixes #1904 --- .cirrus.yml | 14 +++++++------- README.md | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index ab1178dd1a..1e073d707e 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -67,13 +67,13 @@ task: - if [ -z "$NOHACK" ]; then cargo hack check --each-feature --target i686-unknown-freebsd; fi before_cache_script: rm -rf $CARGO_HOME/registry/index -# Test macOS x86_64 in a full VM +# Test macOS aarch64 in a full VM task: - name: macOS x86_64 + name: macOS aarch64 env: - TARGET: x86_64-apple-darwin - osx_instance: - image: big-sur-xcode + TARGET: aarch64-apple-darwin + macos_instance: + image: ghcr.io/cirruslabs/macos-ventura-base:latest setup_script: - curl --proto '=https' --tlsv1.2 -sSf -o rustup.sh https://sh.rustup.rs - sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN @@ -235,9 +235,9 @@ task: - name: Linux x32 env: TARGET: x86_64-unknown-linux-gnux32 - - name: macOS aarch64 + - name: macOS x86_64 env: - TARGET: aarch64-apple-darwin + TARGET: x86_64-apple-darwin - name: NetBSD x86_64 env: TARGET: x86_64-unknown-netbsd diff --git a/README.md b/README.md index 7597ba0afc..2c42b905f7 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ limitations. Support for platforms is split into three tiers: The following targets are supported by `nix`: Tier 1: + * aarch64-apple-darwin * aarch64-unknown-linux-gnu * arm-unknown-linux-gnueabi * armv7-unknown-linux-gnueabihf @@ -58,13 +59,11 @@ Tier 1: * mips64el-unknown-linux-gnuabi64 * mipsel-unknown-linux-gnu * powerpc64le-unknown-linux-gnu - * x86_64-apple-darwin * x86_64-unknown-freebsd * x86_64-unknown-linux-gnu * x86_64-unknown-linux-musl Tier 2: - * aarch64-apple-darwin * aarch64-apple-ios * aarch64-linux-android * arm-linux-androideabi @@ -75,6 +74,7 @@ Tier 2: * s390x-unknown-linux-gnu * x86_64-apple-ios * x86_64-linux-android + * x86_64-apple-darwin * x86_64-unknown-illumos * x86_64-unknown-netbsd From 59f66d128b6664ff618e12c193ec2adc4a862f2f Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sun, 4 Dec 2022 11:44:33 -0800 Subject: [PATCH 233/358] Move some pure formatting changes out of #1863 Signed-off-by: Alex Saveau --- src/dir.rs | 2 +- src/fcntl.rs | 111 ++++++++++++-------- src/sys/socket/mod.rs | 18 ++-- src/unistd.rs | 230 +++++++++++++++++++++++------------------- 4 files changed, 199 insertions(+), 162 deletions(-) diff --git a/src/dir.rs b/src/dir.rs index 5ce503644e..e1854c35e8 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -240,7 +240,7 @@ impl Entry { /// Returns the bare file name of this directory entry without any other leading path component. pub fn file_name(&self) -> &ffi::CStr { - unsafe { ::std::ffi::CStr::from_ptr(self.0.d_name.as_ptr()) } + unsafe { ffi::CStr::from_ptr(self.0.d_name.as_ptr()) } } /// Returns the type of this directory entry, if known. diff --git a/src/fcntl.rs b/src/fcntl.rs index 650828345b..65bbd4ca7a 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -237,7 +237,7 @@ pub fn renameat( } } -#[cfg(all(target_os = "linux", target_env = "gnu",))] +#[cfg(all(target_os = "linux", target_env = "gnu"))] #[cfg(feature = "fs")] libc_bitflags! { #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] @@ -250,10 +250,7 @@ libc_bitflags! { feature! { #![feature = "fs"] -#[cfg(all( - target_os = "linux", - target_env = "gnu", -))] +#[cfg(all(target_os = "linux", target_env = "gnu"))] pub fn renameat2( old_dirfd: Option, old_path: &P1, @@ -308,54 +305,80 @@ fn readlink_maybe_at( fn inner_readlink(dirfd: Option, path: &P) -> Result { let mut v = Vec::with_capacity(libc::PATH_MAX as usize); - // simple case: result is strictly less than `PATH_MAX` - let res = readlink_maybe_at(dirfd, path, &mut v)?; - let len = Errno::result(res)?; - debug_assert!(len >= 0); - if (len as usize) < v.capacity() { - return wrap_readlink_result(v, res); + + { + // simple case: result is strictly less than `PATH_MAX` + let res = readlink_maybe_at(dirfd, path, &mut v)?; + let len = Errno::result(res)?; + debug_assert!(len >= 0); + if (len as usize) < v.capacity() { + return wrap_readlink_result(v, res); + } } + // Uh oh, the result is too long... // Let's try to ask lstat how many bytes to allocate. - let reported_size = match dirfd { - #[cfg(target_os = "redox")] - Some(_) => unreachable!(), - #[cfg(any(target_os = "android", target_os = "linux"))] - Some(dirfd) => { - let flags = if path.is_empty() { AtFlags::AT_EMPTY_PATH } else { AtFlags::empty() }; - super::sys::stat::fstatat(dirfd, path, flags | AtFlags::AT_SYMLINK_NOFOLLOW) - }, - #[cfg(not(any(target_os = "android", target_os = "linux", target_os = "redox")))] - Some(dirfd) => super::sys::stat::fstatat(dirfd, path, AtFlags::AT_SYMLINK_NOFOLLOW), - None => super::sys::stat::lstat(path) - } + let mut try_size = { + let reported_size = match dirfd { + #[cfg(target_os = "redox")] + Some(_) => unreachable!(), + #[cfg(any(target_os = "android", target_os = "linux"))] + Some(dirfd) => { + let flags = if path.is_empty() { + AtFlags::AT_EMPTY_PATH + } else { + AtFlags::empty() + }; + super::sys::stat::fstatat( + dirfd, + path, + flags | AtFlags::AT_SYMLINK_NOFOLLOW, + ) + } + #[cfg(not(any( + target_os = "android", + target_os = "linux", + target_os = "redox" + )))] + Some(dirfd) => super::sys::stat::fstatat( + dirfd, + path, + AtFlags::AT_SYMLINK_NOFOLLOW, + ), + None => super::sys::stat::lstat(path), + } .map(|x| x.st_size) .unwrap_or(0); - let mut try_size = if reported_size > 0 { - // Note: even if `lstat`'s apparently valid answer turns out to be - // wrong, we will still read the full symlink no matter what. - reported_size as usize + 1 - } else { - // If lstat doesn't cooperate, or reports an error, be a little less - // precise. - (libc::PATH_MAX as usize).max(128) << 1 + + if reported_size > 0 { + // Note: even if `lstat`'s apparently valid answer turns out to be + // wrong, we will still read the full symlink no matter what. + reported_size as usize + 1 + } else { + // If lstat doesn't cooperate, or reports an error, be a little less + // precise. + (libc::PATH_MAX as usize).max(128) << 1 + } }; + loop { - v.reserve_exact(try_size); - let res = readlink_maybe_at(dirfd, path, &mut v)?; - let len = Errno::result(res)?; - debug_assert!(len >= 0); - if (len as usize) < v.capacity() { - break wrap_readlink_result(v, res); - } else { - // Ugh! Still not big enough! - match try_size.checked_shl(1) { - Some(next_size) => try_size = next_size, - // It's absurd that this would happen, but handle it sanely - // anyway. - None => break Err(Errno::ENAMETOOLONG), + { + v.reserve_exact(try_size); + let res = readlink_maybe_at(dirfd, path, &mut v)?; + let len = Errno::result(res)?; + debug_assert!(len >= 0); + if (len as usize) < v.capacity() { + return wrap_readlink_result(v, res); } } + + // Ugh! Still not big enough! + match try_size.checked_shl(1) { + Some(next_size) => try_size = next_size, + // It's absurd that this would happen, but handle it sanely + // anyway. + None => break Err(Errno::ENAMETOOLONG), + } } } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 5a16417131..eea74cf699 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -2221,14 +2221,14 @@ pub fn recvfrom( buf.as_ptr() as *mut c_void, buf.len() as size_t, 0, - addr.as_mut_ptr() as *mut libc::sockaddr, + addr.as_mut_ptr() as *mut sockaddr, &mut len as *mut socklen_t, ))? as usize; Ok(( ret, T::from_raw( - addr.assume_init().as_ptr() as *const libc::sockaddr, + addr.assume_init().as_ptr() as *const sockaddr, Some(len), ), )) @@ -2336,11 +2336,8 @@ pub fn getpeername(fd: RawFd) -> Result { let mut addr = mem::MaybeUninit::::uninit(); let mut len = T::size(); - let ret = libc::getpeername( - fd, - addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len, - ); + let ret = + libc::getpeername(fd, addr.as_mut_ptr() as *mut sockaddr, &mut len); Errno::result(ret)?; @@ -2356,11 +2353,8 @@ pub fn getsockname(fd: RawFd) -> Result { let mut addr = mem::MaybeUninit::::uninit(); let mut len = T::size(); - let ret = libc::getsockname( - fd, - addr.as_mut_ptr() as *mut libc::sockaddr, - &mut len, - ); + let ret = + libc::getsockname(fd, addr.as_mut_ptr() as *mut sockaddr, &mut len); Errno::result(ret)?; diff --git a/src/unistd.rs b/src/unistd.rs index ca07b34a2e..1bfeb7b94f 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -585,8 +585,12 @@ pub fn mkfifo(path: &P, mode: Mode) -> Result<()> { // mkfifoat is not implemented in OSX or android #[inline] #[cfg(not(any( - target_os = "macos", target_os = "ios", target_os = "haiku", - target_os = "android", target_os = "redox")))] + target_os = "macos", + target_os = "ios", + target_os = "haiku", + target_os = "android", + target_os = "redox" +)))] pub fn mkfifoat(dirfd: Option, path: &P, mode: Mode) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t) @@ -695,13 +699,18 @@ feature! { /// Computes the raw UID and GID values to pass to a `*chown` call. // The cast is not unnecessary on all platforms. #[allow(clippy::unnecessary_cast)] -fn chown_raw_ids(owner: Option, group: Option) -> (libc::uid_t, libc::gid_t) { +fn chown_raw_ids( + owner: Option, + group: Option, +) -> (uid_t, gid_t) { // According to the POSIX specification, -1 is used to indicate that owner and group // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap // around to get -1. - let uid = owner.map(Into::into) + let uid = owner + .map(Into::into) .unwrap_or_else(|| (0 as uid_t).wrapping_sub(1)); - let gid = group.map(Into::into) + let gid = group + .map(Into::into) .unwrap_or_else(|| (0 as gid_t).wrapping_sub(1)); (uid, gid) } @@ -714,7 +723,11 @@ fn chown_raw_ids(owner: Option, group: Option) -> (libc::uid_t, libc:: /// provided for that argument. Ownership change will be attempted for the path /// only if `Some` owner/group is provided. #[inline] -pub fn chown(path: &P, owner: Option, group: Option) -> Result<()> { +pub fn chown( + path: &P, + owner: Option, + group: Option, +) -> Result<()> { let res = path.with_nix_path(|cstr| { let (uid, gid) = chown_raw_ids(owner, group); unsafe { libc::chown(cstr.as_ptr(), uid, gid) } @@ -773,11 +786,10 @@ pub fn fchownat( group: Option, flag: FchownatFlags, ) -> Result<()> { - let atflag = - match flag { - FchownatFlags::FollowSymlink => AtFlags::empty(), - FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, - }; + let atflag = match flag { + FchownatFlags::FollowSymlink => AtFlags::empty(), + FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, + }; let res = path.with_nix_path(|cstr| unsafe { let (uid, gid) = chown_raw_ids(owner, group); libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid, @@ -808,14 +820,11 @@ fn to_exec_array>(args: &[S]) -> Vec<*const c_char> { pub fn execv>(path: &CStr, argv: &[S]) -> Result { let args_p = to_exec_array(argv); - unsafe { - libc::execv(path.as_ptr(), args_p.as_ptr()) - }; + unsafe { libc::execv(path.as_ptr(), args_p.as_ptr()) }; Err(Errno::last()) } - /// Replace the current process image with a new one (see /// [execve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)). /// @@ -829,13 +838,15 @@ pub fn execv>(path: &CStr, argv: &[S]) -> Result { /// in the `args` list is an argument to the new process. Each element in the /// `env` list should be a string in the form "key=value". #[inline] -pub fn execve, SE: AsRef>(path: &CStr, args: &[SA], env: &[SE]) -> Result { +pub fn execve, SE: AsRef>( + path: &CStr, + args: &[SA], + env: &[SE], +) -> Result { let args_p = to_exec_array(args); let env_p = to_exec_array(env); - unsafe { - libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) - }; + unsafe { libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) }; Err(Errno::last()) } @@ -850,12 +861,13 @@ pub fn execve, SE: AsRef>(path: &CStr, args: &[SA], env: & /// would not work if "bash" was specified for the path argument, but `execvp` /// would assuming that a bash executable was on the system `PATH`. #[inline] -pub fn execvp>(filename: &CStr, args: &[S]) -> Result { +pub fn execvp>( + filename: &CStr, + args: &[S], +) -> Result { let args_p = to_exec_array(args); - unsafe { - libc::execvp(filename.as_ptr(), args_p.as_ptr()) - }; + unsafe { libc::execvp(filename.as_ptr(), args_p.as_ptr()) }; Err(Errno::last()) } @@ -867,10 +879,12 @@ pub fn execvp>(filename: &CStr, args: &[S]) -> Result /// This functions like a combination of `execvp(2)` and `execve(2)` to pass an /// environment and have a search path. See these two for additional /// information. -#[cfg(any(target_os = "haiku", - target_os = "linux", - target_os = "openbsd"))] -pub fn execvpe, SE: AsRef>(filename: &CStr, args: &[SA], env: &[SE]) -> Result { +#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))] +pub fn execvpe, SE: AsRef>( + filename: &CStr, + args: &[SA], + env: &[SE], +) -> Result { let args_p = to_exec_array(args); let env_p = to_exec_array(env); @@ -891,10 +905,12 @@ pub fn execvpe, SE: AsRef>(filename: &CStr, args: &[SA], e /// /// This function is similar to `execve`, except that the program to be executed /// is referenced as a file descriptor instead of a path. -#[cfg(any(target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd"))] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd" +))] #[inline] pub fn fexecve ,SE: AsRef>(fd: RawFd, args: &[SA], env: &[SE]) -> Result { let args_p = to_exec_array(args); @@ -957,14 +973,16 @@ pub fn execveat,SE: AsRef>(dirfd: RawFd, pathname: &CStr, /// descriptors will remain identical after daemonizing. /// * `noclose = false`: The process' stdin, stdout, and stderr will point to /// `/dev/null` after daemonizing. -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris" +))] pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; Errno::result(res).map(drop) @@ -1106,23 +1124,27 @@ pub enum Whence { /// Specify an offset relative to the next location in the file greater than or /// equal to offset that contains some data. If offset points to /// some data, then the file offset is set to offset. - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "solaris"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + ))] SeekData = libc::SEEK_DATA, /// Specify an offset relative to the next hole in the file greater than /// or equal to offset. If offset points into the middle of a hole, then /// the file offset should be set to offset. If there is no hole past offset, /// then the file offset should be adjusted to the end of the file (i.e., there /// is an implicit hole at the end of any file). - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "solaris"))] - SeekHole = libc::SEEK_HOLE + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + ))] + SeekHole = libc::SEEK_HOLE, } /// Move the read/write file offset. @@ -1163,21 +1185,29 @@ feature! { /// created: /// /// - `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors. -#[cfg_attr(target_os = "linux", doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode.")] -#[cfg_attr(target_os = "netbsd", doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`.")] +#[cfg_attr( + target_os = "linux", + doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode." +)] +#[cfg_attr( + target_os = "netbsd", + doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`." +)] /// - `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe. /// /// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html) -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "redox", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "redox", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris" +))] pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); @@ -1196,11 +1226,8 @@ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { /// [truncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html) #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] pub fn truncate(path: &P, len: off_t) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::truncate(cstr.as_ptr(), len) - } - })?; + let res = path + .with_nix_path(|cstr| unsafe { libc::truncate(cstr.as_ptr(), len) })?; Errno::result(res).map(drop) } @@ -1224,7 +1251,7 @@ pub fn isatty(fd: RawFd) -> Result { Errno::ENOTTY => Ok(false), err => Err(err), } - } + } } } @@ -1280,16 +1307,12 @@ pub fn linkat( Errno::result(res).map(drop) } - /// Remove a directory entry /// /// See also [unlink(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html) pub fn unlink(path: &P) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::unlink(cstr.as_ptr()) - } - })?; + let res = + path.with_nix_path(|cstr| unsafe { libc::unlink(cstr.as_ptr()) })?; Errno::result(res).map(drop) } @@ -1329,13 +1352,11 @@ pub fn unlinkat( Errno::result(res).map(drop) } - #[inline] #[cfg(not(target_os = "fuchsia"))] pub fn chroot(path: &P) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::chroot(cstr.as_ptr()) } - })?; + let res = + path.with_nix_path(|cstr| unsafe { libc::chroot(cstr.as_ptr()) })?; Errno::result(res).map(drop) } @@ -1379,15 +1400,17 @@ pub fn fsync(fd: RawFd) -> Result<()> { /// /// See also /// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html) -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos", - target_os = "solaris"))] +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "netbsd", + target_os = "openbsd", + target_os = "illumos", + target_os = "solaris" +))] #[inline] pub fn fdatasync(fd: RawFd) -> Result<()> { let res = unsafe { libc::fdatasync(fd) }; @@ -2739,28 +2762,29 @@ pub fn sysconf(var: SysconfVar) -> Result> { } } -feature! { -#![feature = "fs"] - #[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(feature = "fs")] mod pivot_root { - use crate::{Result, NixPath}; use crate::errno::Errno; + use crate::{NixPath, Result}; pub fn pivot_root( - new_root: &P1, put_old: &P2) -> Result<()> { + new_root: &P1, + put_old: &P2, + ) -> Result<()> { let res = new_root.with_nix_path(|new_root| { - put_old.with_nix_path(|put_old| { - unsafe { - libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr()) - } + put_old.with_nix_path(|put_old| unsafe { + libc::syscall( + libc::SYS_pivot_root, + new_root.as_ptr(), + put_old.as_ptr(), + ) }) })??; Errno::result(res).map(drop) } } -} #[cfg(any( target_os = "android", @@ -2904,10 +2928,8 @@ feature! { /// Checks the file named by `path` for accessibility according to the flags given by `amode` /// See [access(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html) pub fn access(path: &P, amode: AccessFlags) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::access(cstr.as_ptr(), amode.bits) - } + let res = path.with_nix_path(|cstr| unsafe { + libc::access(cstr.as_ptr(), amode.bits) })?; Errno::result(res).map(drop) } @@ -2945,10 +2967,8 @@ pub fn faccessat(dirfd: Option, path: &P, mode: Acce target_os = "dragonfly" ))] pub fn eaccess(path: &P, mode: AccessFlags) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::eaccess(cstr.as_ptr(), mode.bits) - } + let res = path.with_nix_path(|cstr| unsafe { + libc::eaccess(cstr.as_ptr(), mode.bits) })?; Errno::result(res).map(drop) } From 5fd4b8a4d4fdfa79c59796f73ba24a72a579bb49 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sun, 4 Dec 2022 12:44:28 -0800 Subject: [PATCH 234/358] More annoying formatting changes Signed-off-by: Alex Saveau --- src/sys/mman.rs | 13 ++++---- src/sys/socket/addr.rs | 64 +++++++++++++++++++++------------------ src/sys/socket/sockopt.rs | 10 +++--- 3 files changed, 46 insertions(+), 41 deletions(-) diff --git a/src/sys/mman.rs b/src/sys/mman.rs index 2bee091610..d4c6ecb05e 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -8,7 +8,7 @@ use crate::Result; #[cfg(feature = "fs")] use crate::{fcntl::OFlag, sys::stat::Mode}; use libc::{self, c_int, c_void, off_t, size_t}; -use std::{os::unix::io::RawFd, num::NonZeroUsize}; +use std::{num::NonZeroUsize, os::unix::io::RawFd}; libc_bitflags! { /// Desired memory protection of a memory mapping. @@ -424,12 +424,11 @@ pub unsafe fn mmap( fd: RawFd, offset: off_t, ) -> Result<*mut c_void> { - let ptr = addr.map_or( - std::ptr::null_mut(), - |a| usize::from(a) as *mut c_void - ); - - let ret = libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset); + let ptr = + addr.map_or(std::ptr::null_mut(), |a| usize::from(a) as *mut c_void); + + let ret = + libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset); if ret == libc::MAP_FAILED { Err(Errno::last()) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 970e838122..d83adcfeea 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -42,9 +42,7 @@ pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { static_assertions::assert_eq_size!(net::Ipv4Addr, libc::in_addr); // Safe because both types have the same memory layout, and no fancy Drop // impls. - unsafe { - mem::transmute(addr) - } + unsafe { mem::transmute(addr) } } /// Convert a std::net::Ipv6Addr into the libc form. @@ -52,9 +50,7 @@ pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr { static_assertions::assert_eq_size!(net::Ipv6Addr, libc::in6_addr); // Safe because both are Newtype wrappers around the same libc type - unsafe { - mem::transmute(*addr) - } + unsafe { mem::transmute(*addr) } } /// These constants specify the protocol family to be used @@ -79,7 +75,11 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] Netlink = libc::AF_NETLINK, /// Kernel interface for interacting with the routing table - #[cfg(not(any(target_os = "redox", target_os = "linux", target_os = "android")))] + #[cfg(not(any( + target_os = "redox", + target_os = "linux", + target_os = "android" + )))] Route = libc::PF_ROUTE, /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html)) #[cfg(any( @@ -422,7 +422,11 @@ impl AddressFamily { libc::AF_NETLINK => Some(AddressFamily::Netlink), #[cfg(any(target_os = "macos", target_os = "macos"))] libc::AF_SYSTEM => Some(AddressFamily::System), - #[cfg(not(any(target_os = "redox", target_os = "linux", target_os = "android")))] + #[cfg(not(any( + target_os = "redox", + target_os = "linux", + target_os = "android" + )))] libc::PF_ROUTE => Some(AddressFamily::Route), #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_PACKET => Some(AddressFamily::Packet), @@ -592,10 +596,11 @@ impl UnixAddr { pub fn new_unnamed() -> UnixAddr { let ret = libc::sockaddr_un { sun_family: AddressFamily::Unix as sa_family_t, - .. unsafe { mem::zeroed() } + ..unsafe { mem::zeroed() } }; - let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap(); + let sun_len: u8 = + offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap(); unsafe { UnixAddr::from_raw_parts(ret, sun_len) } } @@ -1268,7 +1273,9 @@ impl SockaddrLike for SockaddrStorage { if i32::from(ss.ss_family) == libc::AF_UNIX { // Safe because we UnixAddr is strictly smaller than // SockaddrStorage, and we just initialized the structure. - (*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr)).sun_len = len as u8; + (*(&mut ss as *mut libc::sockaddr_storage + as *mut UnixAddr)) + .sun_len = len as u8; } Some(Self { ss }) } @@ -1343,7 +1350,7 @@ impl SockaddrLike for SockaddrStorage { // The UnixAddr type knows its own length Some(ua) => ua.len(), // For all else, we're just a boring SockaddrStorage - None => mem::size_of_val(self) as libc::socklen_t + None => mem::size_of_val(self) as libc::socklen_t, } } } @@ -1403,12 +1410,13 @@ impl SockaddrStorage { } } // Sanity checks - if self.family() != Some(AddressFamily::Unix) || - len < offset_of!(libc::sockaddr_un, sun_path) || - len > mem::size_of::() { + if self.family() != Some(AddressFamily::Unix) + || len < offset_of!(libc::sockaddr_un, sun_path) + || len > mem::size_of::() + { None } else { - Some(unsafe{&self.su}) + Some(unsafe { &self.su }) } } @@ -1432,12 +1440,13 @@ impl SockaddrStorage { } } // Sanity checks - if self.family() != Some(AddressFamily::Unix) || - len < offset_of!(libc::sockaddr_un, sun_path) || - len > mem::size_of::() { + if self.family() != Some(AddressFamily::Unix) + || len < offset_of!(libc::sockaddr_un, sun_path) + || len > mem::size_of::() + { None } else { - Some(unsafe{&mut self.su}) + Some(unsafe { &mut self.su }) } } @@ -2525,9 +2534,8 @@ mod tests { fn from_sockaddr_un_named() { let ua = UnixAddr::new("/var/run/mysock").unwrap(); let ptr = ua.as_ptr() as *const libc::sockaddr; - let ss = unsafe { - SockaddrStorage::from_raw(ptr, Some(ua.len())) - }.unwrap(); + let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } + .unwrap(); assert_eq!(ss.len(), ua.len()); } @@ -2537,9 +2545,8 @@ mod tests { let name = String::from("nix\0abstract\0test"); let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap(); let ptr = ua.as_ptr() as *const libc::sockaddr; - let ss = unsafe { - SockaddrStorage::from_raw(ptr, Some(ua.len())) - }.unwrap(); + let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } + .unwrap(); assert_eq!(ss.len(), ua.len()); } @@ -2548,9 +2555,8 @@ mod tests { fn from_sockaddr_un_abstract_unnamed() { let ua = UnixAddr::new_unnamed(); let ptr = ua.as_ptr() as *const libc::sockaddr; - let ss = unsafe { - SockaddrStorage::from_raw(ptr, Some(ua.len())) - }.unwrap(); + let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) } + .unwrap(); assert_eq!(ss.len(), ua.len()); } } diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 06e9ee4563..4e0abfbe74 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -6,13 +6,13 @@ use crate::Result; use cfg_if::cfg_if; use libc::{self, c_int, c_void, socklen_t}; use std::ffi::{OsStr, OsString}; -use std::{ - convert::TryFrom, - mem::{self, MaybeUninit} -}; #[cfg(target_family = "unix")] use std::os::unix::ffi::OsStrExt; use std::os::unix::io::RawFd; +use std::{ + convert::TryFrom, + mem::{self, MaybeUninit}, +}; // Constants // TCP_CA_NAME_MAX isn't defined in user space include files @@ -107,7 +107,7 @@ macro_rules! getsockopt_impl { match <$ty>::try_from(getter.assume_init()) { Err(_) => Err(Errno::EINVAL), - Ok(r) => Ok(r) + Ok(r) => Ok(r), } } } From 1f68cf663360cf8ce299ff1ea613f699a05f65b3 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sat, 12 Nov 2022 19:51:18 -0800 Subject: [PATCH 235/358] Bump MSRV to 1.63 for I/O safety Signed-off-by: Alex Saveau --- .cirrus.yml | 15 ++++++++------- CHANGELOG.md | 4 ++++ Cargo.toml | 2 +- README.md | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 1e073d707e..bdbfed539e 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -9,7 +9,7 @@ env: RUSTDOCFLAGS: -D warnings TOOL: cargo # The MSRV - TOOLCHAIN: 1.56.1 + TOOLCHAIN: 1.63 ZFLAGS: # Tests that don't require executing the build binaries @@ -140,23 +140,24 @@ task: matrix: - name: Linux aarch64 arm_container: - image: rust:1.56 + image: rust:1.63 env: RUSTFLAGS: --cfg graviton -D warnings TARGET: aarch64-unknown-linux-gnu - name: Linux x86_64 container: - image: rust:1.56 + image: rust:1.63 env: TARGET: x86_64-unknown-linux-gnu - name: Linux x86_64 musl container: - image: rust:1.56 + image: rust:1.63 env: TARGET: x86_64-unknown-linux-musl setup_script: - rustup target add $TARGET - - rustup component add clippy + - rustup toolchain install $TOOLCHAIN --profile minimal --target $TARGET + - rustup component add --toolchain $TOOLCHAIN clippy << : *TEST before_cache_script: rm -rf $CARGO_HOME/registry/index @@ -176,7 +177,7 @@ task: # Tasks for cross-compiling, but no testing task: container: - image: rust:1.56 + image: rust:1.63 env: BUILD: check HOST: x86_64-unknown-linux-gnu @@ -250,7 +251,7 @@ task: task: container: - image: rust:1.56 + image: rust:1.63 env: BUILD: check name: Redox x86_64 diff --git a/CHANGELOG.md b/CHANGELOG.md index d708ba72af..4f7855d380 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1662](https://github.com/nix-rust/nix/pull/1662)) ### Changed + +- The MSRV is now 1.63 + ([#1862](https://github.com/nix-rust/nix/pull/1862)) + ### Fixed ### Removed diff --git a/Cargo.toml b/Cargo.toml index c337127f4d..fb0e4cfd4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2018" version = "0.26.1" -rust-version = "1.56" +rust-version = "1.63" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" license = "MIT" diff --git a/README.md b/README.md index 2c42b905f7..97ca145f1a 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Tier 3: ## Minimum Supported Rust Version (MSRV) -nix is supported on Rust 1.56.1 and higher. Its MSRV will not be +nix is supported on Rust 1.63 and higher. Its MSRV will not be changed in the future without bumping the major or minor version. ## Contributing From e2ff9d53b66b719f3d356604497747d87a7474a5 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sat, 3 Dec 2022 12:19:46 -0800 Subject: [PATCH 236/358] Bump the edition since why not Signed-off-by: Alex Saveau --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fb0e4cfd4c..ad9d29fc8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nix" description = "Rust friendly bindings to *nix APIs" -edition = "2018" +edition = "2021" version = "0.26.1" rust-version = "1.63" authors = ["The nix-rust Project Developers"] From fb802462a6c5c254f544dc2601ebe5ef8ab110bc Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sat, 3 Dec 2022 13:40:32 -0800 Subject: [PATCH 237/358] Fix clippy lints Signed-off-by: Alex Saveau --- src/sys/aio.rs | 2 +- src/sys/socket/addr.rs | 6 +++--- src/sys/socket/mod.rs | 1 - src/sys/socket/sockopt.rs | 5 +---- src/sys/time.rs | 32 ++++++++++++++--------------- test/sys/test_aio.rs | 2 +- test/sys/test_signal.rs | 8 +++----- test/sys/test_socket.rs | 12 +++++------ test/test_fcntl.rs | 2 +- test/test_mount.rs | 42 ++++++++++++++++++--------------------- test/test_unistd.rs | 13 ++++-------- 11 files changed, 54 insertions(+), 71 deletions(-) diff --git a/src/sys/aio.rs b/src/sys/aio.rs index e2ce19b79d..ee78d9c2f0 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -163,7 +163,7 @@ impl AioCb { 0 => Ok(()), num if num > 0 => Err(Errno::from_i32(num)), -1 => Err(Errno::last()), - num => panic!("unknown aio_error return value {:?}", num), + num => panic!("unknown aio_error return value {num:?}"), } } diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index d83adcfeea..4e36ca4700 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -2373,7 +2373,7 @@ mod tests { sdl_slen: 0, ..unsafe { mem::zeroed() } }); - format!("{}", la); + format!("{la}"); } #[cfg(all( @@ -2495,7 +2495,7 @@ mod tests { fn display() { let s = "127.0.0.1:8080"; let addr = SockaddrIn::from_str(s).unwrap(); - assert_eq!(s, format!("{}", addr)); + assert_eq!(s, format!("{addr}")); } #[test] @@ -2515,7 +2515,7 @@ mod tests { fn display() { let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; let addr = SockaddrIn6::from_str(s).unwrap(); - assert_eq!(s, format!("{}", addr)); + assert_eq!(s, format!("{addr}")); } #[test] diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index eea74cf699..5dac869899 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -12,7 +12,6 @@ use libc::{ self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, }; -use std::convert::TryFrom; use std::io::{IoSlice, IoSliceMut}; #[cfg(feature = "net")] use std::net; diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 4e0abfbe74..c2daeae7a0 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -6,13 +6,10 @@ use crate::Result; use cfg_if::cfg_if; use libc::{self, c_int, c_void, socklen_t}; use std::ffi::{OsStr, OsString}; +use std::mem::{self, MaybeUninit}; #[cfg(target_family = "unix")] use std::os::unix::ffi::OsStrExt; use std::os::unix::io::RawFd; -use std::{ - convert::TryFrom, - mem::{self, MaybeUninit}, -}; // Constants // TCP_CA_NAME_MAX isn't defined in user space include files diff --git a/src/sys/time.rs b/src/sys/time.rs index 0042c45084..a1894e4d54 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -261,8 +261,7 @@ impl TimeValLike for TimeSpec { fn seconds(seconds: i64) -> TimeSpec { assert!( (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds), - "TimeSpec out of bounds; seconds={}", - seconds + "TimeSpec out of bounds; seconds={seconds}", ); let mut ts = zero_init_timespec(); ts.tv_sec = seconds as time_t; @@ -428,20 +427,20 @@ impl fmt::Display for TimeSpec { let sec = abs.tv_sec(); - write!(f, "{}", sign)?; + write!(f, "{sign}")?; if abs.tv_nsec() == 0 { - if abs.tv_sec() == 1 { - write!(f, "{} second", sec)?; + if sec == 1 { + write!(f, "1 second")?; } else { - write!(f, "{} seconds", sec)?; + write!(f, "{sec} seconds")?; } } else if abs.tv_nsec() % 1_000_000 == 0 { - write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?; + write!(f, "{sec}.{:03} seconds", abs.tv_nsec() / 1_000_000)?; } else if abs.tv_nsec() % 1_000 == 0 { - write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?; + write!(f, "{sec}.{:06} seconds", abs.tv_nsec() / 1_000)?; } else { - write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?; + write!(f, "{sec}.{:09} seconds", abs.tv_nsec())?; } Ok(()) @@ -497,8 +496,7 @@ impl TimeValLike for TimeVal { fn seconds(seconds: i64) -> TimeVal { assert!( (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds), - "TimeVal out of bounds; seconds={}", - seconds + "TimeVal out of bounds; seconds={seconds}" ); #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 @@ -662,18 +660,18 @@ impl fmt::Display for TimeVal { let sec = abs.tv_sec(); - write!(f, "{}", sign)?; + write!(f, "{sign}")?; if abs.tv_usec() == 0 { - if abs.tv_sec() == 1 { - write!(f, "{} second", sec)?; + if sec == 1 { + write!(f, "1 second")?; } else { - write!(f, "{} seconds", sec)?; + write!(f, "{sec} seconds")?; } } else if abs.tv_usec() % 1000 == 0 { - write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?; + write!(f, "{sec}.{:03} seconds", abs.tv_usec() / 1000)?; } else { - write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?; + write!(f, "{sec}.{:06} seconds", abs.tv_usec())?; } Ok(()) diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index 84086f80ce..fdabaca6aa 100644 --- a/test/sys/test_aio.rs +++ b/test/sys/test_aio.rs @@ -610,7 +610,7 @@ fn test_aio_suspend() { let r = aio_suspend(&cbbuf[..], Some(timeout)); match r { Err(Errno::EINTR) => continue, - Err(e) => panic!("aio_suspend returned {:?}", e), + Err(e) => panic!("aio_suspend returned {e:?}"), Ok(_) => (), }; } diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs index 3ad14f40c7..721cb9c948 100644 --- a/test/sys/test_signal.rs +++ b/test/sys/test_signal.rs @@ -54,9 +54,8 @@ fn test_sigprocmask() { // test don't make sense. assert!( !old_signal_set.contains(SIGNAL), - "the {:?} signal is already blocked, please change to a \ - different one", - SIGNAL + "the {SIGNAL:?} signal is already blocked, please change to a \ + different one" ); // Now block the signal. @@ -71,8 +70,7 @@ fn test_sigprocmask() { .expect("expect to be able to retrieve old signals"); assert!( old_signal_set.contains(SIGNAL), - "expected the {:?} to be blocked", - SIGNAL + "expected the {SIGNAL:?} to be blocked" ); // Reset the signal. diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 1413eb6b2e..2ab6c54f6e 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -626,7 +626,7 @@ mod recvfrom { println!("IPv6 not available, skipping test."); return; } - Err(e) => panic!("bind: {}", e), + Err(e) => panic!("bind: {e}"), Ok(()) => (), } let ssock = socket( @@ -1272,7 +1272,7 @@ fn test_scm_credentials() { ControlMessageOwned::ScmCredentials(cred) => cred, #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ControlMessageOwned::ScmCreds(cred) => cred, - other => panic!("unexpected cmsg {:?}", other), + other => panic!("unexpected cmsg {other:?}"), }; assert!(received_cred.is_none()); assert_eq!(cred.pid(), getpid().as_raw()); @@ -1550,7 +1550,7 @@ fn loopback_address( Err(e) => { let stdioerr = io::stderr(); let mut handle = stdioerr.lock(); - writeln!(handle, "getifaddrs: {:?}", e).unwrap(); + writeln!(handle, "getifaddrs: {e:?}").unwrap(); return None; } }; @@ -2347,7 +2347,7 @@ mod linux_errqueue { } *ext_err } else { - panic!("Unexpected control message {:?}", cmsg); + panic!("Unexpected control message {cmsg:?}"); } }, ) @@ -2398,7 +2398,7 @@ mod linux_errqueue { } *ext_err } else { - panic!("Unexpected control message {:?}", cmsg); + panic!("Unexpected control message {cmsg:?}"); } }, ) @@ -2432,7 +2432,7 @@ mod linux_errqueue { MsgFlags::empty(), ) { assert_eq!(e, Errno::EADDRNOTAVAIL); - println!("{:?} not available, skipping test.", af); + println!("{af:?} not available, skipping test."); return; } diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index e51044a069..fb2a5e2ea0 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -559,7 +559,7 @@ mod test_posix_fallocate { let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err(); match err { Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (), - errno => panic!("unexpected errno {}", errno,), + errno => panic!("unexpected errno {errno}",), } } } diff --git a/test/test_mount.rs b/test/test_mount.rs index 2fd612e358..5cf00408e8 100644 --- a/test/test_mount.rs +++ b/test/test_mount.rs @@ -38,7 +38,7 @@ exit 23"; MsFlags::empty(), NONE, ) - .unwrap_or_else(|e| panic!("mount failed: {}", e)); + .unwrap_or_else(|e| panic!("mount failed: {e}")); let test_path = tempdir.path().join("test"); @@ -67,17 +67,17 @@ exit 23"; .unwrap(); process::exit(0); } else { - panic!("open failed: {}", e); + panic!("open failed: {e}"); } }) .and_then(|mut f| f.write(SCRIPT_CONTENTS)) - .unwrap_or_else(|e| panic!("write failed: {}", e)); + .unwrap_or_else(|e| panic!("write failed: {e}")); // Verify read. let mut buf = Vec::new(); File::open(&test_path) .and_then(|mut f| f.read_to_end(&mut buf)) - .unwrap_or_else(|e| panic!("read failed: {}", e)); + .unwrap_or_else(|e| panic!("read failed: {e}")); assert_eq!(buf, SCRIPT_CONTENTS); // Verify execute. @@ -85,13 +85,12 @@ exit 23"; EXPECTED_STATUS, Command::new(&test_path) .status() - .unwrap_or_else(|e| panic!("exec failed: {}", e)) + .unwrap_or_else(|e| panic!("exec failed: {e}")) .code() .unwrap_or_else(|| panic!("child killed by signal")) ); - umount(tempdir.path()) - .unwrap_or_else(|e| panic!("umount failed: {}", e)); + umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); } pub fn test_mount_rdonly_disallows_write() { @@ -104,7 +103,7 @@ exit 23"; MsFlags::MS_RDONLY, NONE, ) - .unwrap_or_else(|e| panic!("mount failed: {}", e)); + .unwrap_or_else(|e| panic!("mount failed: {e}")); // EROFS: Read-only file system assert_eq!( @@ -115,8 +114,7 @@ exit 23"; .unwrap() ); - umount(tempdir.path()) - .unwrap_or_else(|e| panic!("umount failed: {}", e)); + umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); } pub fn test_mount_noexec_disallows_exec() { @@ -129,7 +127,7 @@ exit 23"; MsFlags::MS_NOEXEC, NONE, ) - .unwrap_or_else(|e| panic!("mount failed: {}", e)); + .unwrap_or_else(|e| panic!("mount failed: {e}")); let test_path = tempdir.path().join("test"); @@ -139,13 +137,13 @@ exit 23"; .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) .open(&test_path) .and_then(|mut f| f.write(SCRIPT_CONTENTS)) - .unwrap_or_else(|e| panic!("write failed: {}", e)); + .unwrap_or_else(|e| panic!("write failed: {e}")); // Verify that we cannot execute despite a+x permissions being set. let mode = stat::Mode::from_bits_truncate( fs::metadata(&test_path) .map(|md| md.permissions().mode()) - .unwrap_or_else(|e| panic!("metadata failed: {}", e)), + .unwrap_or_else(|e| panic!("metadata failed: {e}")), ); assert!( @@ -164,8 +162,7 @@ exit 23"; .unwrap() ); - umount(tempdir.path()) - .unwrap_or_else(|e| panic!("umount failed: {}", e)); + umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}")); } pub fn test_mount_bind() { @@ -182,7 +179,7 @@ exit 23"; MsFlags::MS_BIND, NONE, ) - .unwrap_or_else(|e| panic!("mount failed: {}", e)); + .unwrap_or_else(|e| panic!("mount failed: {e}")); fs::OpenOptions::new() .create(true) @@ -190,10 +187,10 @@ exit 23"; .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits()) .open(mount_point.path().join(file_name)) .and_then(|mut f| f.write(SCRIPT_CONTENTS)) - .unwrap_or_else(|e| panic!("write failed: {}", e)); + .unwrap_or_else(|e| panic!("write failed: {e}")); umount(mount_point.path()) - .unwrap_or_else(|e| panic!("umount failed: {}", e)); + .unwrap_or_else(|e| panic!("umount failed: {e}")); } // Verify the file written in the mount shows up in source directory, even @@ -202,7 +199,7 @@ exit 23"; let mut buf = Vec::new(); File::open(tempdir.path().join(file_name)) .and_then(|mut f| f.read_to_end(&mut buf)) - .unwrap_or_else(|e| panic!("read failed: {}", e)); + .unwrap_or_else(|e| panic!("read failed: {e}")); assert_eq!(buf, SCRIPT_CONTENTS); } @@ -214,8 +211,7 @@ exit 23"; let stderr = io::stderr(); let mut handle = stderr.lock(); writeln!(handle, - "unshare failed: {}. Are unprivileged user namespaces available?", - e).unwrap(); + "unshare failed: {e}. Are unprivileged user namespaces available?").unwrap(); writeln!(handle, "mount is not being tested").unwrap(); // Exit with success because not all systems support unprivileged user namespaces, and // that's not what we're testing for. @@ -226,8 +222,8 @@ exit 23"; fs::OpenOptions::new() .write(true) .open("/proc/self/uid_map") - .and_then(|mut f| f.write(format!("1000 {} 1\n", uid).as_bytes())) - .unwrap_or_else(|e| panic!("could not write uid map: {}", e)); + .and_then(|mut f| f.write(format!("1000 {uid} 1\n").as_bytes())) + .unwrap_or_else(|e| panic!("could not write uid map: {e}")); } } diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 9e20f977ec..6619262e93 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -56,11 +56,11 @@ fn test_fork_and_waitpid() { // panic, must never happen s @ Ok(_) => { - panic!("Child exited {:?}, should never happen", s) + panic!("Child exited {s:?}, should never happen") } // panic, waitpid should never fail - Err(s) => panic!("Error: waitpid returned Err({:?}", s), + Err(s) => panic!("Error: waitpid returned Err({s:?}"), } } } @@ -94,7 +94,7 @@ fn test_mkstemp() { close(fd).unwrap(); unlink(path.as_path()).unwrap(); } - Err(e) => panic!("mkstemp failed: {}", e), + Err(e) => panic!("mkstemp failed: {e}"), } } @@ -799,12 +799,7 @@ static mut ALARM_CALLED: bool = false; // Used in `test_alarm`. #[cfg(not(target_os = "redox"))] pub extern "C" fn alarm_signal_handler(raw_signal: libc::c_int) { - assert_eq!( - raw_signal, - libc::SIGALRM, - "unexpected signal: {}", - raw_signal - ); + assert_eq!(raw_signal, libc::SIGALRM, "unexpected signal: {raw_signal}"); unsafe { ALARM_CALLED = true }; } From bc2b023e2473531448e1e24502da746dca9ff2ac Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sun, 4 Dec 2022 11:34:22 -0800 Subject: [PATCH 238/358] Tweak cirrus rust versions Signed-off-by: Alex Saveau --- .cirrus.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index bdbfed539e..d69716db6f 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -9,7 +9,7 @@ env: RUSTDOCFLAGS: -D warnings TOOL: cargo # The MSRV - TOOLCHAIN: 1.63 + TOOLCHAIN: 1.63.0 ZFLAGS: # Tests that don't require executing the build binaries @@ -140,24 +140,23 @@ task: matrix: - name: Linux aarch64 arm_container: - image: rust:1.63 + image: rust:1.63.0 env: RUSTFLAGS: --cfg graviton -D warnings TARGET: aarch64-unknown-linux-gnu - name: Linux x86_64 container: - image: rust:1.63 + image: rust:1.63.0 env: TARGET: x86_64-unknown-linux-gnu - name: Linux x86_64 musl container: - image: rust:1.63 + image: rust:1.63.0 env: TARGET: x86_64-unknown-linux-musl setup_script: - rustup target add $TARGET - - rustup toolchain install $TOOLCHAIN --profile minimal --target $TARGET - - rustup component add --toolchain $TOOLCHAIN clippy + - rustup component add clippy << : *TEST before_cache_script: rm -rf $CARGO_HOME/registry/index @@ -177,7 +176,7 @@ task: # Tasks for cross-compiling, but no testing task: container: - image: rust:1.63 + image: rust:1.63.0 env: BUILD: check HOST: x86_64-unknown-linux-gnu @@ -251,7 +250,7 @@ task: task: container: - image: rust:1.63 + image: rust:1.63.0 env: BUILD: check name: Redox x86_64 From 4f61d1200966eed9d9d27c63863a6ec9352fc003 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sun, 4 Dec 2022 22:50:10 +0000 Subject: [PATCH 239/358] Epoll --- CHANGELOG.md | 2 + src/sys/epoll.rs | 114 +++++++++++++++++++++++++++++++++++++++-- test/sys/test_epoll.rs | 2 + 3 files changed, 114 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f7855d380..f6ee0fc5dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - The MSRV is now 1.63 ([#1862](https://github.com/nix-rust/nix/pull/1862)) +- The epoll interface now uses a type. + ([#1882](https://github.com/nix-rust/nix/pull/1882)) ### Fixed ### Removed diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 58def2e788..02c25d4d04 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -2,8 +2,7 @@ use crate::errno::Errno; use crate::Result; use libc::{self, c_int}; use std::mem; -use std::os::unix::io::RawFd; -use std::ptr; +use std::os::unix::io::{FromRawFd,RawFd, OwnedFd, AsFd, AsRawFd}; libc_bitflags!( pub struct EpollFlags: c_int { @@ -70,6 +69,110 @@ impl EpollEvent { } } +/// A safe wrapper around [`epoll`](https://man7.org/linux/man-pages/man7/epoll.7.html). +/// ``` +/// # use nix::sys::{epoll::{Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{eventfd, EfdFlags}}; +/// # use nix::unistd::write; +/// # use std::os::unix::io::{OwnedFd, FromRawFd, AsRawFd, AsFd}; +/// # use std::time::{Instant, Duration}; +/// # fn main() -> nix::Result<()> { +/// const DATA: u64 = 17; +/// const MILLIS: u64 = 100; +/// +/// // Create epoll +/// let epoll = Epoll::new(EpollCreateFlags::empty())?; +/// +/// // Create eventfd & Add event +/// let eventfd = unsafe { OwnedFd::from_raw_fd(eventfd(0, EfdFlags::empty())?) }; +/// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?; +/// +/// // Arm eventfd & Time wait +/// write(eventfd.as_raw_fd(), &1u64.to_ne_bytes())?; +/// let now = Instant::now(); +/// +/// // Wait on event +/// let mut events = [EpollEvent::empty()]; +/// epoll.wait(&mut events, MILLIS as isize)?; +/// +/// // Assert data correct & timeout didn't occur +/// assert_eq!(events[0].data(), DATA); +/// assert!(now.elapsed() < Duration::from_millis(MILLIS)); +/// # Ok(()) +/// # } +/// ``` +#[derive(Debug)] +pub struct Epoll(pub OwnedFd); +impl Epoll { + /// Creates a new epoll instance and returns a file descriptor referring to that instance. + /// + /// [`epoll_create1`](https://man7.org/linux/man-pages/man2/epoll_create1.2.html). + pub fn new(flags: EpollCreateFlags) -> Result { + let res = unsafe { libc::epoll_create1(flags.bits()) }; + let fd = Errno::result(res)?; + let owned_fd = unsafe { OwnedFd::from_raw_fd(fd) }; + Ok(Self(owned_fd)) + } + /// Add an entry to the interest list of the epoll file descriptor for + /// specified in events. + /// + /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_ADD`. + pub fn add(&self, fd: Fd, mut event: EpollEvent) -> Result<()> { + self.epoll_ctl(EpollOp::EpollCtlAdd,fd,&mut event) + } + /// Remove (deregister) the target file descriptor `fd` from the interest list. + /// + /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_DEL` . + pub fn delete(&self, fd: Fd) -> Result<()> { + self.epoll_ctl(EpollOp::EpollCtlDel,fd,None) + } + /// Change the settings associated with `fd` in the interest list to the new settings specified + /// in `event`. + /// + /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_MOD`. + pub fn modify(&self,fd: Fd, event: &mut EpollEvent) -> Result<()> { + self.epoll_ctl(EpollOp::EpollCtlMod,fd,event) + } + /// Waits for I/O events, blocking the calling thread if no events are currently available. + /// (This can be thought of as fetching items from the ready list of the epoll instance.) + /// + /// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html) + pub fn wait(&self, events: &mut [EpollEvent], timeout: isize) -> Result { + let res = unsafe { + libc::epoll_wait( + self.0.as_raw_fd(), + events.as_mut_ptr() as *mut libc::epoll_event, + events.len() as c_int, + timeout as c_int, + ) + }; + + Errno::result(res).map(|r| r as usize) + } + /// This system call is used to add, modify, or remove entries in the interest list of the epoll + /// instance referred to by `self`. It requests that the operation `op` be performed for the + /// target file descriptor, `fd`. + /// + /// When possible prefer [`Epoll::add`], [`Epoll::delete`] and [`Epoll::modify`]. + /// + /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) + fn epoll_ctl<'a, Fd: AsFd, T>( + &self, + op: EpollOp, + fd: Fd, + event: T, + ) -> Result<()> + where + T: Into>, + { + let event: Option<&mut EpollEvent> = event.into(); + let ptr = event.map(|x|&mut x.event as *mut libc::epoll_event).unwrap_or(std::ptr::null_mut()); + unsafe { + Errno::result(libc::epoll_ctl(self.0.as_raw_fd(), op as c_int, fd.as_fd().as_raw_fd(), ptr)).map(drop) + } + } +} + +#[deprecated(since = "0.27.0", note = "Use Epoll::new() instead")] #[inline] pub fn epoll_create() -> Result { let res = unsafe { libc::epoll_create(1024) }; @@ -77,6 +180,7 @@ pub fn epoll_create() -> Result { Errno::result(res) } +#[deprecated(since = "0.27.0", note = "Use Epoll::new() instead")] #[inline] pub fn epoll_create1(flags: EpollCreateFlags) -> Result { let res = unsafe { libc::epoll_create1(flags.bits()) }; @@ -84,6 +188,7 @@ pub fn epoll_create1(flags: EpollCreateFlags) -> Result { Errno::result(res) } +#[deprecated(since = "0.27.0", note = "Use Epoll::epoll_ctl() instead")] #[inline] pub fn epoll_ctl<'a, T>( epfd: RawFd, @@ -102,13 +207,14 @@ where if let Some(ref mut event) = event { libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event) } else { - libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut()) + libc::epoll_ctl(epfd, op as c_int, fd, std::ptr::null_mut()) } }; Errno::result(res).map(drop) } } +#[deprecated(since = "0.27.0", note = "Use Epoll::wait() instead")] #[inline] pub fn epoll_wait( epfd: RawFd, @@ -125,4 +231,4 @@ pub fn epoll_wait( }; Errno::result(res).map(|r| r as usize) -} +} \ No newline at end of file diff --git a/test/sys/test_epoll.rs b/test/sys/test_epoll.rs index 915691595c..84b100c1e9 100644 --- a/test/sys/test_epoll.rs +++ b/test/sys/test_epoll.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + use nix::errno::Errno; use nix::sys::epoll::{epoll_create1, epoll_ctl}; use nix::sys::epoll::{EpollCreateFlags, EpollEvent, EpollFlags, EpollOp}; From 2b827ad79c5de4c7745ea55a25a2a2f3528056df Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 4 Dec 2022 16:15:28 -0700 Subject: [PATCH 240/358] Cleanup old Clippy directives. --- src/macros.rs | 1 - src/sys/quota.rs | 3 +-- src/sys/signal.rs | 1 - src/sys/socket/mod.rs | 15 ++------------- src/sys/socket/sockopt.rs | 1 - 5 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 99e0de8866..07d80f68cc 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -95,7 +95,6 @@ macro_rules! libc_bitflags { /// } /// ``` // Some targets don't use all rules. -#[allow(unknown_lints)] #[allow(unused_macro_rules)] macro_rules! libc_enum { // Exit rule. diff --git a/src/sys/quota.rs b/src/sys/quota.rs index b3c44ca705..a32d07aa1e 100644 --- a/src/sys/quota.rs +++ b/src/sys/quota.rs @@ -21,9 +21,8 @@ use std::{mem, ptr}; struct QuotaCmd(QuotaSubCmd, QuotaType); impl QuotaCmd { - #[allow(unused_unsafe)] fn as_int(&self) -> c_int { - unsafe { libc::QCMD(self.0 as i32, self.1 as i32) } + libc::QCMD(self.0 as i32, self.1 as i32) } } diff --git a/src/sys/signal.rs b/src/sys/signal.rs index d3746e609a..baa5d79d54 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -641,7 +641,6 @@ impl<'a> IntoIterator for &'a SigSet { } /// A signal handler. -#[allow(unknown_lints)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum SigHandler { /// Default signal handling. diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 5dac869899..a67a5ab34a 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -283,17 +283,14 @@ libc_bitflags! { /// Sends or requests out-of-band data on sockets that support this notion /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also /// support out-of-band data. - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_OOB; /// Peeks at an incoming message. The data is treated as unread and the next /// [`recv()`](fn.recv.html) /// or similar function shall still return this data. - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_PEEK; /// Receive operation blocks until the full amount of data can be /// returned. The function may return smaller amount of data if a signal /// is caught, an error or disconnect occurs. - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_WAITALL; /// Enables nonblocking operation; if the operation would block, /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar @@ -305,10 +302,8 @@ libc_bitflags! { /// which will affect all threads in /// the calling process and as well as other processes that hold /// file descriptors referring to the same open file description. - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_DONTWAIT; /// Receive flags: Control Data was discarded (buffer too small) - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_CTRUNC; /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram /// (since Linux 2.4.27/2.6.8), @@ -318,18 +313,15 @@ libc_bitflags! { /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets. /// /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp). - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_TRUNC; /// Terminates a record (when this notion is supported, as for /// sockets of type [`SeqPacket`](enum.SockType.html)). - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_EOR; /// This flag specifies that queued errors should be received from /// the socket error queue. (For more details, see /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom)) #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_ERRQUEUE; /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain /// file descriptor using the `SCM_RIGHTS` operation (described in @@ -345,7 +337,6 @@ libc_bitflags! { target_os = "netbsd", target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_CMSG_CLOEXEC; /// Requests not to send `SIGPIPE` errors when the other end breaks the connection. /// (For more details, see [send(2)](https://linux.die.net/man/2/send)). @@ -360,7 +351,6 @@ libc_bitflags! { target_os = "openbsd", target_os = "solaris"))] #[cfg_attr(docsrs, doc(cfg(all())))] - #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_NOSIGNAL; } } @@ -1581,8 +1571,7 @@ pub struct MultiHeaders { addresses: Box<[mem::MaybeUninit]>, // while we are not using it directly - this is used to store control messages // and we retain pointers to them inside items array - #[allow(dead_code)] - cmsg_buffers: Option>, + _cmsg_buffers: Option>, msg_controllen: usize, } @@ -1630,7 +1619,7 @@ impl MultiHeaders { Self { items: items.into_boxed_slice(), addresses, - cmsg_buffers, + _cmsg_buffers: cmsg_buffers, msg_controllen, } } diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index c2daeae7a0..dd24208f31 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -138,7 +138,6 @@ macro_rules! getsockopt_impl { /// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`. /// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`. // Some targets don't use all rules. -#[allow(unknown_lints)] #[allow(unused_macro_rules)] macro_rules! sockopt_impl { ($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => { From 16a8c0298305d76feb87c2430f36ea583bc4bc5f Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 5 Dec 2022 11:32:35 -0700 Subject: [PATCH 241/358] Use I/O safety in sys::mman --- src/sys/mman.rs | 21 ++++++++++++++------- test/sys/test_mman.rs | 14 +++++++------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/sys/mman.rs b/src/sys/mman.rs index d4c6ecb05e..deef7005b5 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -8,7 +8,7 @@ use crate::Result; #[cfg(feature = "fs")] use crate::{fcntl::OFlag, sys::stat::Mode}; use libc::{self, c_int, c_void, off_t, size_t}; -use std::{num::NonZeroUsize, os::unix::io::RawFd}; +use std::{num::NonZeroUsize, os::unix::io::{AsRawFd, AsFd}}; libc_bitflags! { /// Desired memory protection of a memory mapping. @@ -416,17 +416,18 @@ pub fn munlockall() -> Result<()> { /// See the [`mmap(2)`] man page for detailed requirements. /// /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html -pub unsafe fn mmap( +pub unsafe fn mmap( addr: Option, length: NonZeroUsize, prot: ProtFlags, flags: MapFlags, - fd: RawFd, + f: Option<&F>, offset: off_t, ) -> Result<*mut c_void> { let ptr = addr.map_or(std::ptr::null_mut(), |a| usize::from(a) as *mut c_void); + let fd = f.map(|f| f.as_fd().as_raw_fd()).unwrap_or(-1); let ret = libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset); @@ -518,11 +519,12 @@ pub unsafe fn madvise( /// # use nix::libc::size_t; /// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags}; /// # use std::ptr; +/// # use std::os::unix::io::BorrowedFd; /// const ONE_K: size_t = 1024; /// let one_k_non_zero = std::num::NonZeroUsize::new(ONE_K).unwrap(); /// let mut slice: &mut [u8] = unsafe { -/// let mem = mmap(None, one_k_non_zero, ProtFlags::PROT_NONE, -/// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap(); +/// let mem = mmap::(None, one_k_non_zero, ProtFlags::PROT_NONE, +/// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, None, 0).unwrap(); /// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap(); /// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) /// }; @@ -566,9 +568,11 @@ pub fn shm_open

( name: &P, flag: OFlag, mode: Mode - ) -> Result + ) -> Result where P: ?Sized + NixPath { + use std::os::unix::io::{FromRawFd, OwnedFd}; + let ret = name.with_nix_path(|cstr| { #[cfg(any(target_os = "macos", target_os = "ios"))] unsafe { @@ -580,7 +584,10 @@ pub fn shm_open

( } })?; - Errno::result(ret) + match ret { + -1 => Err(Errno::last()), + fd => Ok(unsafe{ OwnedFd::from_raw_fd(fd) }) + } } } diff --git a/test/sys/test_mman.rs b/test/sys/test_mman.rs index e748427bcd..b4674e53fa 100644 --- a/test/sys/test_mman.rs +++ b/test/sys/test_mman.rs @@ -1,15 +1,15 @@ use nix::sys::mman::{mmap, MapFlags, ProtFlags}; -use std::num::NonZeroUsize; +use std::{num::NonZeroUsize, os::unix::io::BorrowedFd}; #[test] fn test_mmap_anonymous() { unsafe { - let ptr = mmap( + let ptr = mmap::( None, NonZeroUsize::new(1).unwrap(), ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, - -1, + None, 0, ) .unwrap() as *mut u8; @@ -29,12 +29,12 @@ fn test_mremap_grow() { let one_k_non_zero = NonZeroUsize::new(ONE_K).unwrap(); let slice: &mut [u8] = unsafe { - let mem = mmap( + let mem = mmap::( None, one_k_non_zero, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, - -1, + None, 0, ) .unwrap(); @@ -87,12 +87,12 @@ fn test_mremap_shrink() { const ONE_K: size_t = 1024; let ten_one_k = NonZeroUsize::new(10 * ONE_K).unwrap(); let slice: &mut [u8] = unsafe { - let mem = mmap( + let mem = mmap::( None, ten_one_k, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, - -1, + None, 0, ) .unwrap(); From b1fe9cf0cdd8e51b026f5cafe842efde87276c23 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 5 Dec 2022 13:31:03 -0700 Subject: [PATCH 242/358] Update CI environment to FreeBSD 12.4 --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index d69716db6f..213696724e 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -42,7 +42,7 @@ task: matrix: - name: FreeBSD 12 amd64 & i686 freebsd_instance: - image: freebsd-12-3-release-amd64 + image: freebsd-12-4-release-amd64 - name: FreeBSD 14 amd64 & i686 freebsd_instance: image_family: freebsd-14-0-snap From 7058bcef55ecdab7e7df463d450fda1beff3e92b Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Tue, 6 Dec 2022 21:45:12 +0800 Subject: [PATCH 243/358] feat: I/O safety for 'sys/statfs' --- src/sys/statfs.rs | 6 +++--- test/test_fcntl.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 9be8ca6667..721d45cb21 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -5,7 +5,7 @@ use std::ffi::CStr; use std::fmt::{self, Debug}; use std::mem; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsFd, AsRawFd}; use cfg_if::cfg_if; @@ -740,10 +740,10 @@ pub fn statfs(path: &P) -> Result { /// # Arguments /// /// `fd` - File descriptor of any open file within the file system to describe -pub fn fstatfs(fd: &T) -> Result { +pub fn fstatfs(fd: &Fd) -> Result { unsafe { let mut stat = mem::MaybeUninit::::uninit(); - Errno::result(LIBC_FSTATFS(fd.as_raw_fd(), stat.as_mut_ptr())) + Errno::result(LIBC_FSTATFS(fd.as_fd().as_raw_fd(), stat.as_mut_ptr())) .map(|_| Statfs(stat.assume_init())) } } diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index fb2a5e2ea0..8f50f16b5a 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -383,7 +383,7 @@ mod linux_android { let tmp = NamedTempFile::new().unwrap(); let fd = tmp.as_raw_fd(); - let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); + let statfs = nix::sys::statfs::fstatfs(tmp.as_file()).unwrap(); if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { // OverlayFS is a union file system. It returns one inode value in // stat(2), but a different one shows up in /proc/locks. So we must @@ -421,7 +421,7 @@ mod linux_android { let tmp = NamedTempFile::new().unwrap(); let fd = tmp.as_raw_fd(); - let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap(); + let statfs = nix::sys::statfs::fstatfs(tmp.as_file()).unwrap(); if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC { // OverlayFS is a union file system. It returns one inode value in // stat(2), but a different one shows up in /proc/locks. So we must From 2f546c98cb1abb4463f13b084443ae4bf1597cb3 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Wed, 7 Dec 2022 20:31:38 +0800 Subject: [PATCH 244/358] feat: I/O safety for 'kmod' --- src/kmod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/kmod.rs b/src/kmod.rs index 1fa6c170d9..d7146612d5 100644 --- a/src/kmod.rs +++ b/src/kmod.rs @@ -3,7 +3,7 @@ //! For more details see use std::ffi::CStr; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsFd, AsRawFd}; use crate::errno::Errno; use crate::Result; @@ -79,15 +79,15 @@ libc_bitflags!( /// ``` /// /// See [`man init_module(2)`](https://man7.org/linux/man-pages/man2/init_module.2.html) for more information. -pub fn finit_module( - fd: &T, +pub fn finit_module( + fd: &Fd, param_values: &CStr, flags: ModuleInitFlags, ) -> Result<()> { let res = unsafe { libc::syscall( libc::SYS_finit_module, - fd.as_raw_fd(), + fd.as_fd().as_raw_fd(), param_values.as_ptr(), flags.bits(), ) From 8f52bc97c96922f61140948eacabf966712d105e Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Thu, 8 Dec 2022 14:04:22 +0800 Subject: [PATCH 245/358] feat: I/O safety for 'sys/termios' & 'pty' --- CHANGELOG.md | 3 ++ Cargo.toml | 4 -- src/pty.rs | 62 +++++++++++-------------------- src/sys/termios.rs | 49 +++++++++++++++++-------- test/sys/test_termios.rs | 59 ++++++++---------------------- test/test.rs | 8 ++-- test/test_pty.rs | 73 +++++++++---------------------------- test/test_ptymaster_drop.rs | 20 ---------- test/test_unistd.rs | 14 ++----- 9 files changed, 99 insertions(+), 193 deletions(-) delete mode 100644 test/test_ptymaster_drop.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f6ee0fc5dc..c75e875ea0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1862](https://github.com/nix-rust/nix/pull/1862)) - The epoll interface now uses a type. ([#1882](https://github.com/nix-rust/nix/pull/1882)) +- With I/O-safe type applied in `pty::OpenptyResult` and `pty::ForkptyResult`, + users no longer need to manually close the file descriptors in these types. + ([#1921](https://github.com/nix-rust/nix/pull/1921)) ### Fixed ### Removed diff --git a/Cargo.toml b/Cargo.toml index ad9d29fc8c..e0cfac14f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,7 +108,3 @@ path = "test/test_clearenv.rs" name = "test-mount" path = "test/test_mount.rs" harness = false - -[[test]] -name = "test-ptymaster-drop" -path = "test/test_ptymaster_drop.rs" diff --git a/src/pty.rs b/src/pty.rs index 28ae5e924b..2866c6df48 100644 --- a/src/pty.rs +++ b/src/pty.rs @@ -16,26 +16,24 @@ use crate::{fcntl, unistd, Result}; /// Representation of a master/slave pty pair /// -/// This is returned by `openpty`. Note that this type does *not* implement `Drop`, so the user -/// must manually close the file descriptors. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +/// This is returned by [`openpty`]. +#[derive(Debug)] pub struct OpenptyResult { /// The master port in a virtual pty pair - pub master: RawFd, + pub master: OwnedFd, /// The slave port in a virtual pty pair - pub slave: RawFd, + pub slave: OwnedFd, } feature! { #![feature = "process"] /// Representation of a master with a forked pty /// -/// This is returned by `forkpty`. Note that this type does *not* implement `Drop`, so the user -/// must manually close the file descriptors. -#[derive(Clone, Copy, Debug)] +/// This is returned by [`forkpty`]. +#[derive(Debug)] pub struct ForkptyResult { /// The master port in a virtual pty pair - pub master: RawFd, + pub master: OwnedFd, /// Metadata about forked process pub fork_result: ForkResult, } @@ -43,51 +41,33 @@ pub struct ForkptyResult { /// Representation of the Master device in a master/slave pty pair /// -/// While this datatype is a thin wrapper around `RawFd`, it enforces that the available PTY -/// functions are given the correct file descriptor. Additionally this type implements `Drop`, -/// so that when it's consumed or goes out of scope, it's automatically cleaned-up. -#[derive(Debug, Eq, Hash, PartialEq)] -pub struct PtyMaster(RawFd); +/// While this datatype is a thin wrapper around `OwnedFd`, it enforces that the available PTY +/// functions are given the correct file descriptor. +#[derive(Debug)] +pub struct PtyMaster(OwnedFd); impl AsRawFd for PtyMaster { fn as_raw_fd(&self) -> RawFd { - self.0 + self.0.as_raw_fd() } } impl IntoRawFd for PtyMaster { fn into_raw_fd(self) -> RawFd { let fd = self.0; - mem::forget(self); - fd - } -} - -impl Drop for PtyMaster { - fn drop(&mut self) { - // On drop, we ignore errors like EINTR and EIO because there's no clear - // way to handle them, we can't return anything, and (on FreeBSD at - // least) the file descriptor is deallocated in these cases. However, - // we must panic on EBADF, because it is always an error to close an - // invalid file descriptor. That frequently indicates a double-close - // condition, which can cause confusing errors for future I/O - // operations. - let e = unistd::close(self.0); - if e == Err(Errno::EBADF) { - panic!("Closing an invalid file descriptor!"); - }; + fd.into_raw_fd() } } impl io::Read for PtyMaster { fn read(&mut self, buf: &mut [u8]) -> io::Result { - unistd::read(self.0, buf).map_err(io::Error::from) + unistd::read(self.0.as_raw_fd(), buf).map_err(io::Error::from) } } impl io::Write for PtyMaster { fn write(&mut self, buf: &[u8]) -> io::Result { - unistd::write(self.0, buf).map_err(io::Error::from) + unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from) } fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -96,13 +76,13 @@ impl io::Write for PtyMaster { impl io::Read for &PtyMaster { fn read(&mut self, buf: &mut [u8]) -> io::Result { - unistd::read(self.0, buf).map_err(io::Error::from) + unistd::read(self.0.as_raw_fd(), buf).map_err(io::Error::from) } } impl io::Write for &PtyMaster { fn write(&mut self, buf: &[u8]) -> io::Result { - unistd::write(self.0, buf).map_err(io::Error::from) + unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from) } fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -164,7 +144,7 @@ pub fn posix_openpt(flags: fcntl::OFlag) -> Result { return Err(Errno::last()); } - Ok(PtyMaster(fd)) + Ok(PtyMaster(unsafe { OwnedFd::from_raw_fd(fd) })) } /// Get the name of the slave pseudoterminal (see @@ -308,8 +288,8 @@ pub fn openpty< unsafe { Ok(OpenptyResult { - master: master.assume_init(), - slave: slave.assume_init(), + master: OwnedFd::from_raw_fd(master.assume_init()), + slave: OwnedFd::from_raw_fd(slave.assume_init()), }) } } @@ -364,7 +344,7 @@ pub unsafe fn forkpty<'a, 'b, T: Into>, U: Into Result { +pub fn tcgetattr(fd: &Fd) -> Result { let mut termios = mem::MaybeUninit::uninit(); - let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) }; + let res = unsafe { + libc::tcgetattr(fd.as_fd().as_raw_fd(), termios.as_mut_ptr()) + }; Errno::result(res)?; @@ -1159,18 +1161,26 @@ pub fn tcgetattr(fd: RawFd) -> Result { /// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change /// takes affect at a time specified by `actions`. Note that this function may return success if /// *any* of the parameters were successfully set, not only if all were set successfully. -pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> { +pub fn tcsetattr( + fd: &Fd, + actions: SetArg, + termios: &Termios, +) -> Result<()> { let inner_termios = termios.get_libc_termios(); Errno::result(unsafe { - libc::tcsetattr(fd, actions as c_int, &*inner_termios) + libc::tcsetattr( + fd.as_fd().as_raw_fd(), + actions as c_int, + &*inner_termios, + ) }) .map(drop) } /// Block until all output data is written (see /// [tcdrain(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)). -pub fn tcdrain(fd: RawFd) -> Result<()> { - Errno::result(unsafe { libc::tcdrain(fd) }).map(drop) +pub fn tcdrain(fd: &Fd) -> Result<()> { + Errno::result(unsafe { libc::tcdrain(fd.as_fd().as_raw_fd()) }).map(drop) } /// Suspend or resume the transmission or reception of data (see @@ -1178,8 +1188,11 @@ pub fn tcdrain(fd: RawFd) -> Result<()> { /// /// `tcflow()` suspends of resumes the transmission or reception of data for the given port /// depending on the value of `action`. -pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> { - Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop) +pub fn tcflow(fd: &Fd, action: FlowArg) -> Result<()> { + Errno::result(unsafe { + libc::tcflow(fd.as_fd().as_raw_fd(), action as c_int) + }) + .map(drop) } /// Discard data in the output or input queue (see @@ -1187,8 +1200,11 @@ pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> { /// /// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both /// depending on the value of `action`. -pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> { - Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop) +pub fn tcflush(fd: &Fd, action: FlushArg) -> Result<()> { + Errno::result(unsafe { + libc::tcflush(fd.as_fd().as_raw_fd(), action as c_int) + }) + .map(drop) } /// Send a break for a specific duration (see @@ -1196,16 +1212,19 @@ pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> { /// /// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream /// of zero-valued bits for an implementation-defined duration. -pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> { - Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop) +pub fn tcsendbreak(fd: &Fd, duration: c_int) -> Result<()> { + Errno::result(unsafe { + libc::tcsendbreak(fd.as_fd().as_raw_fd(), duration) + }) + .map(drop) } feature! { #![feature = "process"] /// Get the session controlled by the given terminal (see /// [tcgetsid(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)). -pub fn tcgetsid(fd: RawFd) -> Result { - let res = unsafe { libc::tcgetsid(fd) }; +pub fn tcgetsid(fd: &Fd) -> Result { + let res = unsafe { libc::tcgetsid(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(Pid::from_raw) } diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs index aaf00084fa..cf55b10cd8 100644 --- a/test/sys/test_termios.rs +++ b/test/sys/test_termios.rs @@ -1,17 +1,17 @@ -use std::os::unix::prelude::*; +use std::os::unix::io::{AsFd, AsRawFd}; use tempfile::tempfile; use nix::errno::Errno; use nix::fcntl; use nix::pty::openpty; use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags}; -use nix::unistd::{close, read, write}; +use nix::unistd::{read, write}; -/// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s -fn write_all(f: RawFd, buf: &[u8]) { +/// Helper function analogous to `std::io::Write::write_all`, but for `Fd`s +fn write_all(f: &Fd, buf: &[u8]) { let mut len = 0; while len < buf.len() { - len += write(f, &buf[len..]).unwrap(); + len += write(f.as_fd().as_raw_fd(), &buf[len..]).unwrap(); } } @@ -22,25 +22,14 @@ fn test_tcgetattr_pty() { let _m = crate::PTSNAME_MTX.lock(); let pty = openpty(None, None).expect("openpty failed"); - termios::tcgetattr(pty.slave).unwrap(); - close(pty.master).expect("closing the master failed"); - close(pty.slave).expect("closing the slave failed"); + termios::tcgetattr(&pty.slave).unwrap(); } // Test tcgetattr on something that isn't a terminal #[test] fn test_tcgetattr_enotty() { let file = tempfile().unwrap(); - assert_eq!( - termios::tcgetattr(file.as_raw_fd()).err(), - Some(Errno::ENOTTY) - ); -} - -// Test tcgetattr on an invalid file descriptor -#[test] -fn test_tcgetattr_ebadf() { - assert_eq!(termios::tcgetattr(-1).err(), Some(Errno::EBADF)); + assert_eq!(termios::tcgetattr(&file).err(), Some(Errno::ENOTTY)); } // Test modifying output flags @@ -52,12 +41,7 @@ fn test_output_flags() { // Open one pty to get attributes for the second one let mut termios = { let pty = openpty(None, None).expect("openpty failed"); - assert!(pty.master > 0); - assert!(pty.slave > 0); - let termios = tcgetattr(pty.slave).expect("tcgetattr failed"); - close(pty.master).unwrap(); - close(pty.slave).unwrap(); - termios + tcgetattr(&pty.slave).expect("tcgetattr failed") }; // Make sure postprocessing '\r' isn't specified by default or this test is useless. @@ -73,19 +57,15 @@ fn test_output_flags() { // Open a pty let pty = openpty(None, &termios).unwrap(); - assert!(pty.master > 0); - assert!(pty.slave > 0); // Write into the master let string = "foofoofoo\r"; - write_all(pty.master, string.as_bytes()); + write_all(&pty.master, string.as_bytes()); // Read from the slave verifying that the output has been properly transformed let mut buf = [0u8; 10]; - crate::read_exact(pty.slave, &mut buf); + crate::read_exact(&pty.slave, &mut buf); let transformed_string = "foofoofoo\n"; - close(pty.master).unwrap(); - close(pty.slave).unwrap(); assert_eq!(&buf, transformed_string.as_bytes()); } @@ -98,12 +78,7 @@ fn test_local_flags() { // Open one pty to get attributes for the second one let mut termios = { let pty = openpty(None, None).unwrap(); - assert!(pty.master > 0); - assert!(pty.slave > 0); - let termios = tcgetattr(pty.slave).unwrap(); - close(pty.master).unwrap(); - close(pty.slave).unwrap(); - termios + tcgetattr(&pty.slave).unwrap() }; // Make sure echo is specified by default or this test is useless. @@ -114,23 +89,19 @@ fn test_local_flags() { // Open a new pty with our modified termios settings let pty = openpty(None, &termios).unwrap(); - assert!(pty.master > 0); - assert!(pty.slave > 0); // Set the master is in nonblocking mode or reading will never return. - let flags = fcntl::fcntl(pty.master, fcntl::F_GETFL).unwrap(); + let flags = fcntl::fcntl(pty.master.as_raw_fd(), fcntl::F_GETFL).unwrap(); let new_flags = fcntl::OFlag::from_bits_truncate(flags) | fcntl::OFlag::O_NONBLOCK; - fcntl::fcntl(pty.master, fcntl::F_SETFL(new_flags)).unwrap(); + fcntl::fcntl(pty.master.as_raw_fd(), fcntl::F_SETFL(new_flags)).unwrap(); // Write into the master let string = "foofoofoo\r"; - write_all(pty.master, string.as_bytes()); + write_all(&pty.master, string.as_bytes()); // Try to read from the master, which should not have anything as echoing was disabled. let mut buf = [0u8; 10]; - let read = read(pty.master, &mut buf).unwrap_err(); - close(pty.master).unwrap(); - close(pty.slave).unwrap(); + let read = read(pty.master.as_raw_fd(), &mut buf).unwrap_err(); assert_eq!(read, Errno::EAGAIN); } diff --git a/test/test.rs b/test/test.rs index 6b42aad950..b139ec3a44 100644 --- a/test/test.rs +++ b/test/test.rs @@ -66,16 +66,16 @@ mod test_unistd; use nix::unistd::{chdir, getcwd, read}; use parking_lot::{Mutex, RwLock, RwLockWriteGuard}; -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsFd, AsRawFd}; use std::path::PathBuf; -/// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s -fn read_exact(f: RawFd, buf: &mut [u8]) { +/// Helper function analogous to `std::io::Read::read_exact`, but for `Fd`s +fn read_exact(f: &Fd, buf: &mut [u8]) { let mut len = 0; while len < buf.len() { // get_mut would be better than split_at_mut, but it requires nightly let (_, remaining) = buf.split_at_mut(len); - len += read(f, remaining).unwrap(); + len += read(f.as_fd().as_raw_fd(), remaining).unwrap(); } } diff --git a/test/test_pty.rs b/test/test_pty.rs index 5c27e2d632..e1286e553c 100644 --- a/test/test_pty.rs +++ b/test/test_pty.rs @@ -2,28 +2,13 @@ use std::fs::File; use std::io::{Read, Write}; use std::os::unix::prelude::*; use std::path::Path; -use tempfile::tempfile; use libc::{_exit, STDOUT_FILENO}; use nix::fcntl::{open, OFlag}; use nix::pty::*; use nix::sys::stat; use nix::sys::termios::*; -use nix::unistd::{close, pause, write}; - -/// Regression test for Issue #659 -/// This is the correct way to explicitly close a `PtyMaster` -#[test] -fn test_explicit_close() { - let mut f = { - let m = posix_openpt(OFlag::O_RDWR).unwrap(); - close(m.into_raw_fd()).unwrap(); - tempfile().unwrap() - }; - // This should work. But if there's been a double close, then it will - // return EBADF - f.write_all(b"whatever").unwrap(); -} +use nix::unistd::{pause, write}; /// Test equivalence of `ptsname` and `ptsname_r` #[test] @@ -50,7 +35,6 @@ fn test_ptsname_copy() { // Open a new PTTY master let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); - assert!(master_fd.as_raw_fd() > 0); // Get the name of the slave let slave_name1 = unsafe { ptsname(&master_fd) }.unwrap(); @@ -67,7 +51,6 @@ fn test_ptsname_copy() { fn test_ptsname_r_copy() { // Open a new PTTY master let master_fd = posix_openpt(OFlag::O_RDWR).unwrap(); - assert!(master_fd.as_raw_fd() > 0); // Get the name of the slave let slave_name1 = ptsname_r(&master_fd).unwrap(); @@ -84,11 +67,9 @@ fn test_ptsname_unique() { // Open a new PTTY master let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap(); - assert!(master1_fd.as_raw_fd() > 0); // Open a second PTTY master let master2_fd = posix_openpt(OFlag::O_RDWR).unwrap(); - assert!(master2_fd.as_raw_fd() > 0); // Get the name of the slave let slave_name1 = unsafe { ptsname(&master1_fd) }.unwrap(); @@ -147,16 +128,14 @@ fn open_ptty_pair() -> (PtyMaster, File) { /// /// This uses a common `open_ptty_pair` because much of these functions aren't useful by /// themselves. So for this test we perform the basic act of getting a file handle for a -/// master/slave PTTY pair, then just sanity-check the raw values. +/// master/slave PTTY pair. #[test] fn test_open_ptty_pair() { - let (master, slave) = open_ptty_pair(); - assert!(master.as_raw_fd() > 0); - assert!(slave.as_raw_fd() > 0); + let (_, _) = open_ptty_pair(); } /// Put the terminal in raw mode. -fn make_raw(fd: RawFd) { +fn make_raw(fd: &Fd) { let mut termios = tcgetattr(fd).unwrap(); cfmakeraw(&mut termios); tcsetattr(fd, SetArg::TCSANOW, &termios).unwrap(); @@ -166,7 +145,7 @@ fn make_raw(fd: RawFd) { #[test] fn test_read_ptty_pair() { let (mut master, mut slave) = open_ptty_pair(); - make_raw(slave.as_raw_fd()); + make_raw(&slave); let mut buf = [0u8; 5]; slave.write_all(b"hello").unwrap(); @@ -183,7 +162,7 @@ fn test_read_ptty_pair() { #[test] fn test_write_ptty_pair() { let (mut master, mut slave) = open_ptty_pair(); - make_raw(slave.as_raw_fd()); + make_raw(&slave); let mut buf = [0u8; 5]; master.write_all(b"adios").unwrap(); @@ -202,33 +181,28 @@ fn test_openpty() { let _m = crate::PTSNAME_MTX.lock(); let pty = openpty(None, None).unwrap(); - assert!(pty.master > 0); - assert!(pty.slave > 0); // Writing to one should be readable on the other one let string = "foofoofoo\n"; let mut buf = [0u8; 10]; - write(pty.master, string.as_bytes()).unwrap(); - crate::read_exact(pty.slave, &mut buf); + write(pty.master.as_raw_fd(), string.as_bytes()).unwrap(); + crate::read_exact(&pty.slave, &mut buf); assert_eq!(&buf, string.as_bytes()); // Read the echo as well let echoed_string = "foofoofoo\r\n"; let mut buf = [0u8; 11]; - crate::read_exact(pty.master, &mut buf); + crate::read_exact(&pty.master, &mut buf); assert_eq!(&buf, echoed_string.as_bytes()); let string2 = "barbarbarbar\n"; let echoed_string2 = "barbarbarbar\r\n"; let mut buf = [0u8; 14]; - write(pty.slave, string2.as_bytes()).unwrap(); - crate::read_exact(pty.master, &mut buf); + write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap(); + crate::read_exact(&pty.master, &mut buf); assert_eq!(&buf, echoed_string2.as_bytes()); - - close(pty.master).unwrap(); - close(pty.slave).unwrap(); } #[test] @@ -239,44 +213,34 @@ fn test_openpty_with_termios() { // Open one pty to get attributes for the second one let mut termios = { let pty = openpty(None, None).unwrap(); - assert!(pty.master > 0); - assert!(pty.slave > 0); - let termios = tcgetattr(pty.slave).unwrap(); - close(pty.master).unwrap(); - close(pty.slave).unwrap(); - termios + tcgetattr(&pty.slave).unwrap() }; // Make sure newlines are not transformed so the data is preserved when sent. termios.output_flags.remove(OutputFlags::ONLCR); let pty = openpty(None, &termios).unwrap(); // Must be valid file descriptors - assert!(pty.master > 0); - assert!(pty.slave > 0); // Writing to one should be readable on the other one let string = "foofoofoo\n"; let mut buf = [0u8; 10]; - write(pty.master, string.as_bytes()).unwrap(); - crate::read_exact(pty.slave, &mut buf); + write(pty.master.as_raw_fd(), string.as_bytes()).unwrap(); + crate::read_exact(&pty.slave, &mut buf); assert_eq!(&buf, string.as_bytes()); // read the echo as well let echoed_string = "foofoofoo\n"; - crate::read_exact(pty.master, &mut buf); + crate::read_exact(&pty.master, &mut buf); assert_eq!(&buf, echoed_string.as_bytes()); let string2 = "barbarbarbar\n"; let echoed_string2 = "barbarbarbar\n"; let mut buf = [0u8; 13]; - write(pty.slave, string2.as_bytes()).unwrap(); - crate::read_exact(pty.master, &mut buf); + write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap(); + crate::read_exact(&pty.master, &mut buf); assert_eq!(&buf, echoed_string2.as_bytes()); - - close(pty.master).unwrap(); - close(pty.slave).unwrap(); } #[test] @@ -303,11 +267,10 @@ fn test_forkpty() { Parent { child } => { let mut buf = [0u8; 10]; assert!(child.as_raw() > 0); - crate::read_exact(pty.master, &mut buf); + crate::read_exact(&pty.master, &mut buf); kill(child, SIGTERM).unwrap(); wait().unwrap(); // keep other tests using generic wait from getting our child assert_eq!(&buf, echoed_string.as_bytes()); - close(pty.master).unwrap(); } } } diff --git a/test/test_ptymaster_drop.rs b/test/test_ptymaster_drop.rs deleted file mode 100644 index ffbaa56977..0000000000 --- a/test/test_ptymaster_drop.rs +++ /dev/null @@ -1,20 +0,0 @@ -#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] -mod t { - use nix::fcntl::OFlag; - use nix::pty::*; - use nix::unistd::close; - use std::os::unix::io::AsRawFd; - - /// Regression test for Issue #659 - /// - /// `PtyMaster` should panic rather than double close the file descriptor - /// This must run in its own test process because it deliberately creates a - /// race condition. - #[test] - #[should_panic(expected = "Closing an invalid file descriptor!")] - fn test_double_close() { - let m = posix_openpt(OFlag::O_RDWR).unwrap(); - close(m.as_raw_fd()).unwrap(); - drop(m); // should panic here - } -} diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 6619262e93..1d50c5fa48 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -555,16 +555,13 @@ fn test_lseek() { const CONTENTS: &[u8] = b"abcdef123456"; let mut tmp = tempfile().unwrap(); tmp.write_all(CONTENTS).unwrap(); - let tmpfd = tmp.into_raw_fd(); let offset: off_t = 5; - lseek(tmpfd, offset, Whence::SeekSet).unwrap(); + lseek(tmp.as_raw_fd(), offset, Whence::SeekSet).unwrap(); let mut buf = [0u8; 7]; - crate::read_exact(tmpfd, &mut buf); + crate::read_exact(&tmp, &mut buf); assert_eq!(b"f123456", &buf); - - close(tmpfd).unwrap(); } #[cfg(any(target_os = "linux", target_os = "android"))] @@ -573,15 +570,12 @@ fn test_lseek64() { const CONTENTS: &[u8] = b"abcdef123456"; let mut tmp = tempfile().unwrap(); tmp.write_all(CONTENTS).unwrap(); - let tmpfd = tmp.into_raw_fd(); - lseek64(tmpfd, 5, Whence::SeekSet).unwrap(); + lseek64(tmp.as_raw_fd(), 5, Whence::SeekSet).unwrap(); let mut buf = [0u8; 7]; - crate::read_exact(tmpfd, &mut buf); + crate::read_exact(&tmp, &mut buf); assert_eq!(b"f123456", &buf); - - close(tmpfd).unwrap(); } cfg_if! { From f5dffcc7f089b3f33db0a2f771d56f330609b7e4 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Fri, 9 Dec 2022 11:02:30 +0800 Subject: [PATCH 246/358] refactor: take AsFd by value --- src/kmod.rs | 2 +- src/sys/mman.rs | 2 +- src/sys/statfs.rs | 2 +- src/sys/termios.rs | 14 +++++++------- test/sys/test_termios.rs | 2 +- test/test.rs | 2 +- test/test_pty.rs | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/kmod.rs b/src/kmod.rs index d7146612d5..d3725c3f8a 100644 --- a/src/kmod.rs +++ b/src/kmod.rs @@ -80,7 +80,7 @@ libc_bitflags!( /// /// See [`man init_module(2)`](https://man7.org/linux/man-pages/man2/init_module.2.html) for more information. pub fn finit_module( - fd: &Fd, + fd: Fd, param_values: &CStr, flags: ModuleInitFlags, ) -> Result<()> { diff --git a/src/sys/mman.rs b/src/sys/mman.rs index deef7005b5..e689e06e04 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -421,7 +421,7 @@ pub unsafe fn mmap( length: NonZeroUsize, prot: ProtFlags, flags: MapFlags, - f: Option<&F>, + f: Option, offset: off_t, ) -> Result<*mut c_void> { let ptr = diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 721d45cb21..5111df2e6e 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -740,7 +740,7 @@ pub fn statfs(path: &P) -> Result { /// # Arguments /// /// `fd` - File descriptor of any open file within the file system to describe -pub fn fstatfs(fd: &Fd) -> Result { +pub fn fstatfs(fd: Fd) -> Result { unsafe { let mut stat = mem::MaybeUninit::::uninit(); Errno::result(LIBC_FSTATFS(fd.as_fd().as_raw_fd(), stat.as_mut_ptr())) diff --git a/src/sys/termios.rs b/src/sys/termios.rs index 4cc635bc21..b0286f51f1 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -1143,7 +1143,7 @@ pub fn cfmakesane(termios: &mut Termios) { /// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying /// this structure *will not* reconfigure the port, instead the modifications should be done to /// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`. -pub fn tcgetattr(fd: &Fd) -> Result { +pub fn tcgetattr(fd: Fd) -> Result { let mut termios = mem::MaybeUninit::uninit(); let res = unsafe { @@ -1162,7 +1162,7 @@ pub fn tcgetattr(fd: &Fd) -> Result { /// takes affect at a time specified by `actions`. Note that this function may return success if /// *any* of the parameters were successfully set, not only if all were set successfully. pub fn tcsetattr( - fd: &Fd, + fd: Fd, actions: SetArg, termios: &Termios, ) -> Result<()> { @@ -1179,7 +1179,7 @@ pub fn tcsetattr( /// Block until all output data is written (see /// [tcdrain(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)). -pub fn tcdrain(fd: &Fd) -> Result<()> { +pub fn tcdrain(fd: Fd) -> Result<()> { Errno::result(unsafe { libc::tcdrain(fd.as_fd().as_raw_fd()) }).map(drop) } @@ -1188,7 +1188,7 @@ pub fn tcdrain(fd: &Fd) -> Result<()> { /// /// `tcflow()` suspends of resumes the transmission or reception of data for the given port /// depending on the value of `action`. -pub fn tcflow(fd: &Fd, action: FlowArg) -> Result<()> { +pub fn tcflow(fd: Fd, action: FlowArg) -> Result<()> { Errno::result(unsafe { libc::tcflow(fd.as_fd().as_raw_fd(), action as c_int) }) @@ -1200,7 +1200,7 @@ pub fn tcflow(fd: &Fd, action: FlowArg) -> Result<()> { /// /// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both /// depending on the value of `action`. -pub fn tcflush(fd: &Fd, action: FlushArg) -> Result<()> { +pub fn tcflush(fd: Fd, action: FlushArg) -> Result<()> { Errno::result(unsafe { libc::tcflush(fd.as_fd().as_raw_fd(), action as c_int) }) @@ -1212,7 +1212,7 @@ pub fn tcflush(fd: &Fd, action: FlushArg) -> Result<()> { /// /// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream /// of zero-valued bits for an implementation-defined duration. -pub fn tcsendbreak(fd: &Fd, duration: c_int) -> Result<()> { +pub fn tcsendbreak(fd: Fd, duration: c_int) -> Result<()> { Errno::result(unsafe { libc::tcsendbreak(fd.as_fd().as_raw_fd(), duration) }) @@ -1223,7 +1223,7 @@ feature! { #![feature = "process"] /// Get the session controlled by the given terminal (see /// [tcgetsid(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)). -pub fn tcgetsid(fd: &Fd) -> Result { +pub fn tcgetsid(fd: Fd) -> Result { let res = unsafe { libc::tcgetsid(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(Pid::from_raw) diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs index cf55b10cd8..83919378a7 100644 --- a/test/sys/test_termios.rs +++ b/test/sys/test_termios.rs @@ -8,7 +8,7 @@ use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags}; use nix::unistd::{read, write}; /// Helper function analogous to `std::io::Write::write_all`, but for `Fd`s -fn write_all(f: &Fd, buf: &[u8]) { +fn write_all(f: Fd, buf: &[u8]) { let mut len = 0; while len < buf.len() { len += write(f.as_fd().as_raw_fd(), &buf[len..]).unwrap(); diff --git a/test/test.rs b/test/test.rs index b139ec3a44..efd5fd2a6f 100644 --- a/test/test.rs +++ b/test/test.rs @@ -70,7 +70,7 @@ use std::os::unix::io::{AsFd, AsRawFd}; use std::path::PathBuf; /// Helper function analogous to `std::io::Read::read_exact`, but for `Fd`s -fn read_exact(f: &Fd, buf: &mut [u8]) { +fn read_exact(f: Fd, buf: &mut [u8]) { let mut len = 0; while len < buf.len() { // get_mut would be better than split_at_mut, but it requires nightly diff --git a/test/test_pty.rs b/test/test_pty.rs index e1286e553c..9ee94470ff 100644 --- a/test/test_pty.rs +++ b/test/test_pty.rs @@ -135,7 +135,7 @@ fn test_open_ptty_pair() { } /// Put the terminal in raw mode. -fn make_raw(fd: &Fd) { +fn make_raw(fd: Fd) { let mut termios = tcgetattr(fd).unwrap(); cfmakeraw(&mut termios); tcsetattr(fd, SetArg::TCSANOW, &termios).unwrap(); From fc59f20e19d3371bef7f0001b08c4cd4b298a5dd Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Fri, 9 Dec 2022 11:08:17 +0800 Subject: [PATCH 247/358] fix --- test/test_pty.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_pty.rs b/test/test_pty.rs index 9ee94470ff..4cc6620c3c 100644 --- a/test/test_pty.rs +++ b/test/test_pty.rs @@ -136,9 +136,9 @@ fn test_open_ptty_pair() { /// Put the terminal in raw mode. fn make_raw(fd: Fd) { - let mut termios = tcgetattr(fd).unwrap(); + let mut termios = tcgetattr(&fd).unwrap(); cfmakeraw(&mut termios); - tcsetattr(fd, SetArg::TCSANOW, &termios).unwrap(); + tcsetattr(&fd, SetArg::TCSANOW, &termios).unwrap(); } /// Test `io::Read` on the PTTY master From a0e39af194726b0ff77c5f50242b8754a542f6d6 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Fri, 9 Dec 2022 11:17:49 +0800 Subject: [PATCH 248/358] feat: I/O safety for 'sys/statvfs' --- src/sys/statvfs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sys/statvfs.rs b/src/sys/statvfs.rs index 8de369f421..c2c86624c8 100644 --- a/src/sys/statvfs.rs +++ b/src/sys/statvfs.rs @@ -3,7 +3,7 @@ //! See [the man pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html) //! for more details. use std::mem; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsFd, AsRawFd}; use libc::{self, c_ulong}; @@ -146,11 +146,11 @@ pub fn statvfs(path: &P) -> Result { } /// Return a `Statvfs` object with information about `fd` -pub fn fstatvfs(fd: &T) -> Result { +pub fn fstatvfs(fd: Fd) -> Result { unsafe { Errno::clear(); let mut stat = mem::MaybeUninit::::uninit(); - Errno::result(libc::fstatvfs(fd.as_raw_fd(), stat.as_mut_ptr())) + Errno::result(libc::fstatvfs(fd.as_fd().as_raw_fd(), stat.as_mut_ptr())) .map(|_| Statvfs(stat.assume_init())) } } From 8772cde9b84e0ab9103f9a8c97d6be7455d7873f Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Fri, 9 Dec 2022 11:33:35 +0800 Subject: [PATCH 249/358] feat: I/O safety for 'sys/uid' & 'sched' --- src/sched.rs | 6 +++--- src/sys/uio.rs | 28 ++++++++++++++-------------- test/sys/test_uio.rs | 29 ++++++++++++++++++----------- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/sched.rs b/src/sched.rs index d5b1233cf3..0515e30f29 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -16,7 +16,7 @@ mod sched_linux_like { use libc::{self, c_int, c_void}; use std::mem; use std::option::Option; - use std::os::unix::io::RawFd; + use std::os::unix::io::{AsFd, AsRawFd}; // For some functions taking with a parameter of type CloneFlags, // only a subset of these flags have an effect. @@ -136,8 +136,8 @@ mod sched_linux_like { /// 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()) }; + pub fn setns(fd: Fd, nstype: CloneFlags) -> Result<()> { + let res = unsafe { libc::setns(fd.as_fd().as_raw_fd(), nstype.bits()) }; Errno::result(res).map(drop) } diff --git a/src/sys/uio.rs b/src/sys/uio.rs index 7248bd0c04..ce0fb54ddb 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -4,12 +4,12 @@ use crate::errno::Errno; use crate::Result; use libc::{self, c_int, c_void, off_t, size_t}; use std::io::{IoSlice, IoSliceMut}; -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsFd, AsRawFd}; /// 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: &[IoSlice<'_>]) -> Result { +pub fn writev(fd: Fd, iov: &[IoSlice<'_>]) -> Result { // SAFETY: to quote the documentation for `IoSlice`: // // [IoSlice] is semantically a wrapper around a &[u8], but is @@ -18,7 +18,7 @@ pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result { // // Because it is ABI compatible, a pointer cast here is valid let res = unsafe { - libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) + libc::writev(fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; Errno::result(res).map(|r| r as usize) @@ -27,10 +27,10 @@ pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result { /// 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 [IoSliceMut<'_>]) -> Result { +pub fn readv(fd: Fd, iov: &mut [IoSliceMut<'_>]) -> Result { // SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec let res = unsafe { - libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) + libc::readv(fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len() as c_int) }; Errno::result(res).map(|r| r as usize) @@ -44,14 +44,14 @@ pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result { /// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result { +pub fn pwritev(fd: Fd, iov: &[IoSlice<'_>], offset: off_t) -> Result { #[cfg(target_env = "uclibc")] let offset = offset as libc::off64_t; // uclibc doesn't use off_t // SAFETY: same as in writev() let res = unsafe { libc::pwritev( - fd, + fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset, @@ -70,8 +70,8 @@ pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result { /// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn preadv( - fd: RawFd, +pub fn preadv( + fd: Fd, iov: &mut [IoSliceMut<'_>], offset: off_t, ) -> Result { @@ -81,7 +81,7 @@ pub fn preadv( // SAFETY: same as in readv() let res = unsafe { libc::preadv( - fd, + fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset, @@ -95,10 +95,10 @@ pub fn preadv( /// /// 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 { +pub fn pwrite(fd: Fd, buf: &[u8], offset: off_t) -> Result { let res = unsafe { libc::pwrite( - fd, + fd.as_fd().as_raw_fd(), buf.as_ptr() as *const c_void, buf.len() as size_t, offset, @@ -112,10 +112,10 @@ pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result { /// /// 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 { +pub fn pread(fd: Fd, buf: &mut [u8], offset: off_t) -> Result { let res = unsafe { libc::pread( - fd, + fd.as_fd().as_raw_fd(), buf.as_mut_ptr() as *mut c_void, buf.len() as size_t, offset, diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs index 0f4b8a6568..fc09465f19 100644 --- a/test/sys/test_uio.rs +++ b/test/sys/test_uio.rs @@ -4,7 +4,7 @@ use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; use std::fs::OpenOptions; use std::io::IoSlice; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{FromRawFd, OwnedFd}; use std::{cmp, iter}; #[cfg(not(target_os = "redox"))] @@ -40,12 +40,16 @@ fn test_writev() { iovecs.push(IoSlice::new(b)); consumed += slice_len; } - let pipe_res = pipe(); - let (reader, writer) = pipe_res.expect("Couldn't create pipe"); + let (reader, writer) = pipe().expect("Couldn't create pipe"); // FileDesc will close its filedesc (reader). let mut read_buf: Vec = iter::repeat(0u8).take(128 * 16).collect(); + + // Temporary workaround to cope with the existing RawFd pipe(2), should be + // removed when pipe(2) becomes I/O-safe. + let writer = unsafe { OwnedFd::from_raw_fd(writer) }; + // Blocking io, should write all data. - let write_res = writev(writer, &iovecs); + let write_res = writev(&writer, &iovecs); let written = write_res.expect("couldn't write"); // Check whether we written all data assert_eq!(to_write.len(), written); @@ -55,7 +59,6 @@ fn test_writev() { assert_eq!(read, written); // Check equality of written and read data assert_eq!(&to_write, &read_buf); - close(writer).expect("closed writer"); close(reader).expect("closed reader"); } @@ -88,7 +91,12 @@ fn test_readv() { let (reader, writer) = pipe().expect("couldn't create pipe"); // Blocking io, should write all data. write(writer, &to_write).expect("write failed"); - let read = readv(reader, &mut iovecs[..]).expect("read failed"); + + // Temporary workaround to cope with the existing RawFd pipe(2), should be + // removed when pipe(2) becomes I/O-safe. + let reader = unsafe { OwnedFd::from_raw_fd(reader) }; + + let read = readv(&reader, &mut iovecs[..]).expect("read failed"); // Check whether we've read all data assert_eq!(to_write.len(), read); // Cccumulate data from iovecs @@ -100,7 +108,6 @@ fn test_readv() { assert_eq!(read_buf.len(), to_write.len()); // Check equality of written and read data assert_eq!(&read_buf, &to_write); - close(reader).expect("couldn't close reader"); close(writer).expect("couldn't close writer"); } @@ -111,7 +118,7 @@ fn test_pwrite() { let mut file = tempfile().unwrap(); let buf = [1u8; 8]; - assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8)); + assert_eq!(Ok(8), pwrite(&file, &buf, 8)); let mut file_content = Vec::new(); file.read_to_end(&mut file_content).unwrap(); let mut expected = vec![0u8; 8]; @@ -137,7 +144,7 @@ fn test_pread() { file.write_all(&file_content).unwrap(); let mut buf = [0u8; 16]; - assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16)); + assert_eq!(Ok(16), pread(&file, &mut buf, 16)); let expected: Vec<_> = (16..32).collect(); assert_eq!(&buf[..], &expected[..]); } @@ -168,7 +175,7 @@ fn test_pwritev() { .open(path) .unwrap(); - let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap(); + let written = pwritev(&file, &iovecs, 100).ok().unwrap(); assert_eq!(written, to_write.len()); // Read the data back and make sure it matches @@ -206,7 +213,7 @@ fn test_preadv() { .iter_mut() .map(|buf| IoSliceMut::new(&mut buf[..])) .collect(); - assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100)); + assert_eq!(Ok(100), preadv(&file, &mut iovecs, 100)); } let all = buffers.concat(); From ab5c032e42b4296603263140276f5202b6ea538b Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Fri, 9 Dec 2022 11:50:45 +0800 Subject: [PATCH 250/358] feat: I/O safety for 'sys/sendfile' --- src/sys/sendfile.rs | 62 ++++++++++++++++++++++++++----------------- test/test_sendfile.rs | 31 ++++++++++++++-------- 2 files changed, 58 insertions(+), 35 deletions(-) diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs index fb293a4e74..9f3c333f97 100644 --- a/src/sys/sendfile.rs +++ b/src/sys/sendfile.rs @@ -1,7 +1,7 @@ //! Send data from a file to a socket, bypassing userland. use cfg_if::cfg_if; -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsFd, AsRawFd}; use std::ptr; use libc::{self, off_t}; @@ -23,16 +23,23 @@ use crate::Result; /// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn sendfile( - out_fd: RawFd, - in_fd: RawFd, +pub fn sendfile( + out_fd: F1, + in_fd: F2, offset: Option<&mut off_t>, count: usize, ) -> Result { let offset = offset .map(|offset| offset as *mut _) .unwrap_or(ptr::null_mut()); - let ret = unsafe { libc::sendfile(out_fd, in_fd, offset, count) }; + let ret = unsafe { + libc::sendfile( + out_fd.as_fd().as_raw_fd(), + in_fd.as_fd().as_raw_fd(), + offset, + count, + ) + }; Errno::result(ret).map(|r| r as usize) } @@ -50,16 +57,23 @@ pub fn sendfile( /// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) #[cfg(target_os = "linux")] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn sendfile64( - out_fd: RawFd, - in_fd: RawFd, +pub fn sendfile64( + out_fd: F1, + in_fd: F2, offset: Option<&mut libc::off64_t>, count: usize, ) -> Result { let offset = offset .map(|offset| offset as *mut _) .unwrap_or(ptr::null_mut()); - let ret = unsafe { libc::sendfile64(out_fd, in_fd, offset, count) }; + let ret = unsafe { + libc::sendfile64( + out_fd.as_fd().as_raw_fd(), + in_fd.as_fd().as_raw_fd(), + offset, + count, + ) + }; Errno::result(ret).map(|r| r as usize) } @@ -156,9 +170,9 @@ cfg_if! { /// For more information, see /// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2) #[allow(clippy::too_many_arguments)] - pub fn sendfile( - in_fd: RawFd, - out_sock: RawFd, + pub fn sendfile( + in_fd: F1, + out_sock: F2, offset: off_t, count: Option, headers: Option<&[&[u8]]>, @@ -175,8 +189,8 @@ cfg_if! { let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); let return_code = unsafe { - libc::sendfile(in_fd, - out_sock, + libc::sendfile(in_fd.as_fd().as_raw_fd(), + out_sock.as_fd().as_raw_fd(), offset, count.unwrap_or(0), hdtr_ptr as *mut libc::sf_hdtr, @@ -206,9 +220,9 @@ cfg_if! { /// /// For more information, see /// [the sendfile(2) man page.](https://leaf.dragonflybsd.org/cgi/web-man?command=sendfile§ion=2) - pub fn sendfile( - in_fd: RawFd, - out_sock: RawFd, + pub fn sendfile( + in_fd: F1, + out_sock: F2, offset: off_t, count: Option, headers: Option<&[&[u8]]>, @@ -218,8 +232,8 @@ cfg_if! { let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); let return_code = unsafe { - libc::sendfile(in_fd, - out_sock, + libc::sendfile(in_fd.as_fd().as_raw_fd(), + out_sock.as_fd().as_raw_fd(), offset, count.unwrap_or(0), hdtr_ptr as *mut libc::sf_hdtr, @@ -252,9 +266,9 @@ cfg_if! { /// /// For more information, see /// [the sendfile(2) man page.](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html) - pub fn sendfile( - in_fd: RawFd, - out_sock: RawFd, + pub fn sendfile( + in_fd: F1, + out_sock: F2, offset: off_t, count: Option, headers: Option<&[&[u8]]>, @@ -264,8 +278,8 @@ cfg_if! { let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers)); let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr); let return_code = unsafe { - libc::sendfile(in_fd, - out_sock, + libc::sendfile(in_fd.as_fd().as_raw_fd(), + out_sock.as_fd().as_raw_fd(), offset, &mut len as *mut off_t, hdtr_ptr as *mut libc::sf_hdtr, diff --git a/test/test_sendfile.rs b/test/test_sendfile.rs index f73a3b56c3..c6ac6e6fa1 100644 --- a/test/test_sendfile.rs +++ b/test/test_sendfile.rs @@ -1,5 +1,6 @@ use std::io::prelude::*; -use std::os::unix::prelude::*; +#[cfg(any(target_os = "android", target_os = "linux"))] +use std::os::unix::io::{FromRawFd, OwnedFd}; use libc::off_t; use nix::sys::sendfile::*; @@ -23,7 +24,12 @@ fn test_sendfile_linux() { let (rd, wr) = pipe().unwrap(); let mut offset: off_t = 5; - let res = sendfile(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap(); + // The construct of this `OwnedFd` is a temporary workaround, when `pipe(2)` + // becomes I/O-safe: + // pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> + // then it is no longer needed. + let wr = unsafe { OwnedFd::from_raw_fd(wr) }; + let res = sendfile(&wr, &tmp, Some(&mut offset), 2).unwrap(); assert_eq!(2, res); @@ -33,7 +39,6 @@ fn test_sendfile_linux() { assert_eq!(7, offset); close(rd).unwrap(); - close(wr).unwrap(); } #[cfg(target_os = "linux")] @@ -45,7 +50,12 @@ fn test_sendfile64_linux() { let (rd, wr) = pipe().unwrap(); let mut offset: libc::off64_t = 5; - let res = sendfile64(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap(); + // The construct of this `OwnedFd` is a temporary workaround, when `pipe(2)` + // becomes I/O-safe: + // pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> + // then it is no longer needed. + let wr = unsafe { OwnedFd::from_raw_fd(wr) }; + let res = sendfile64(&wr, &tmp, Some(&mut offset), 2).unwrap(); assert_eq!(2, res); @@ -55,7 +65,6 @@ fn test_sendfile64_linux() { assert_eq!(7, offset); close(rd).unwrap(); - close(wr).unwrap(); } #[cfg(target_os = "freebsd")] @@ -83,8 +92,8 @@ fn test_sendfile_freebsd() { // Call the test method let (res, bytes_written) = sendfile( - tmp.as_raw_fd(), - wr.as_raw_fd(), + &tmp, + &wr, body_offset as off_t, None, Some(headers.as_slice()), @@ -134,8 +143,8 @@ fn test_sendfile_dragonfly() { // Call the test method let (res, bytes_written) = sendfile( - tmp.as_raw_fd(), - wr.as_raw_fd(), + &tmp, + &wr, body_offset as off_t, None, Some(headers.as_slice()), @@ -183,8 +192,8 @@ fn test_sendfile_darwin() { // Call the test method let (res, bytes_written) = sendfile( - tmp.as_raw_fd(), - wr.as_raw_fd(), + &tmp, + &wr, body_offset as off_t, None, Some(headers.as_slice()), From 9d743300aedaa81b49c6d71a4bcfb6ef354d3f52 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Fri, 9 Dec 2022 11:56:00 +0800 Subject: [PATCH 251/358] feat: I/O safety for 'sys/inotify' --- src/sys/inotify.rs | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/sys/inotify.rs b/src/sys/inotify.rs index 84356ec70f..2398c16e0b 100644 --- a/src/sys/inotify.rs +++ b/src/sys/inotify.rs @@ -32,7 +32,7 @@ use libc::{c_char, c_int}; use std::ffi::{CStr, OsStr, OsString}; use std::mem::{size_of, MaybeUninit}; use std::os::unix::ffi::OsStrExt; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd}; use std::ptr; libc_bitflags! { @@ -101,9 +101,9 @@ libc_bitflags! { /// An inotify instance. This is also a file descriptor, you can feed it to /// other interfaces consuming file descriptors, epoll for example. -#[derive(Debug, Clone, Copy)] +#[derive(Debug)] pub struct Inotify { - fd: RawFd, + fd: OwnedFd, } /// This object is returned when you create a new watch on an inotify instance. @@ -143,7 +143,7 @@ impl Inotify { pub fn init(flags: InitFlags) -> Result { let res = Errno::result(unsafe { libc::inotify_init1(flags.bits()) }); - res.map(|fd| Inotify { fd }) + res.map(|fd| Inotify { fd: unsafe { OwnedFd::from_raw_fd(fd) } }) } /// Adds a new watch on the target file or directory. @@ -152,12 +152,12 @@ impl Inotify { /// /// For more information see, [inotify_add_watch(2)](https://man7.org/linux/man-pages/man2/inotify_add_watch.2.html). pub fn add_watch( - self, + &self, path: &P, mask: AddWatchFlags, ) -> Result { let res = path.with_nix_path(|cstr| unsafe { - libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits()) + libc::inotify_add_watch(self.fd.as_raw_fd(), cstr.as_ptr(), mask.bits()) })?; Errno::result(res).map(|wd| WatchDescriptor { wd }) @@ -169,7 +169,7 @@ impl Inotify { /// Returns an EINVAL error if the watch descriptor is invalid. /// /// For more information see, [inotify_rm_watch(2)](https://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html). - pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> { + pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> { cfg_if! { if #[cfg(target_os = "linux")] { let arg = wd.wd; @@ -177,7 +177,7 @@ impl Inotify { let arg = wd.wd as u32; } } - let res = unsafe { libc::inotify_rm_watch(self.fd, arg) }; + let res = unsafe { libc::inotify_rm_watch(self.fd.as_raw_fd(), arg) }; Errno::result(res).map(drop) } @@ -188,14 +188,14 @@ impl Inotify { /// /// Returns as many events as available. If the call was non blocking and no /// events could be read then the EAGAIN error is returned. - pub fn read_events(self) -> Result> { + pub fn read_events(&self) -> Result> { let header_size = size_of::(); const BUFSIZ: usize = 4096; let mut buffer = [0u8; BUFSIZ]; let mut events = Vec::new(); let mut offset = 0; - let nread = read(self.fd, &mut buffer)?; + let nread = read(self.fd.as_raw_fd(), &mut buffer)?; while (nread - offset) >= header_size { let event = unsafe { @@ -235,14 +235,8 @@ impl Inotify { } } -impl AsRawFd for Inotify { - fn as_raw_fd(&self) -> RawFd { - self.fd - } -} - impl FromRawFd for Inotify { unsafe fn from_raw_fd(fd: RawFd) -> Self { - Inotify { fd } + Inotify { fd: OwnedFd::from_raw_fd(fd) } } } From f592678301e30fa51b0149ca37f42b5c7ea5657e Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Fri, 9 Dec 2022 15:33:27 +0800 Subject: [PATCH 252/358] feat: I/O safety for 'sys/timerfd' --- src/sys/timerfd.rs | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs index a35fc927f4..90a05a8ccd 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -33,24 +33,28 @@ pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags}; use crate::unistd::read; use crate::{errno::Errno, Result}; use libc::c_int; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd}; /// A timerfd instance. This is also a file descriptor, you can feed it to -/// other interfaces consuming file descriptors, epoll for example. +/// other interfaces taking file descriptors as arguments, [`epoll`] for example. +/// +/// [`epoll`]: crate::sys::epoll #[derive(Debug)] pub struct TimerFd { - fd: RawFd, + fd: OwnedFd, } -impl AsRawFd for TimerFd { - fn as_raw_fd(&self) -> RawFd { - self.fd +impl AsFd for TimerFd { + fn as_fd(&self) -> BorrowedFd<'_> { + self.fd.as_fd() } } impl FromRawFd for TimerFd { unsafe fn from_raw_fd(fd: RawFd) -> Self { - TimerFd { fd } + TimerFd { + fd: OwnedFd::from_raw_fd(fd), + } } } @@ -97,7 +101,9 @@ impl TimerFd { Errno::result(unsafe { libc::timerfd_create(clockid as i32, flags.bits()) }) - .map(|fd| Self { fd }) + .map(|fd| Self { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + }) } /// Sets a new alarm on the timer. @@ -145,7 +151,7 @@ impl TimerFd { let timerspec: TimerSpec = expiration.into(); Errno::result(unsafe { libc::timerfd_settime( - self.fd, + self.fd.as_fd().as_raw_fd(), flags.bits(), timerspec.as_ref(), std::ptr::null_mut(), @@ -159,7 +165,10 @@ impl TimerFd { pub fn get(&self) -> Result> { let mut timerspec = TimerSpec::none(); Errno::result(unsafe { - libc::timerfd_gettime(self.fd, timerspec.as_mut()) + libc::timerfd_gettime( + self.fd.as_fd().as_raw_fd(), + timerspec.as_mut(), + ) }) .map(|_| { if timerspec.as_ref().it_interval.tv_sec == 0 @@ -179,7 +188,7 @@ impl TimerFd { pub fn unset(&self) -> Result<()> { Errno::result(unsafe { libc::timerfd_settime( - self.fd, + self.fd.as_fd().as_raw_fd(), TimerSetTimeFlags::empty().bits(), TimerSpec::none().as_ref(), std::ptr::null_mut(), @@ -192,7 +201,7 @@ impl TimerFd { /// /// Note: If the alarm is unset, then you will wait forever. pub fn wait(&self) -> Result<()> { - while let Err(e) = read(self.fd, &mut [0u8; 8]) { + while let Err(e) = read(self.fd.as_fd().as_raw_fd(), &mut [0u8; 8]) { if e != Errno::EINTR { return Err(e); } @@ -201,14 +210,3 @@ impl TimerFd { Ok(()) } } - -impl Drop for TimerFd { - fn drop(&mut self) { - if !std::thread::panicking() { - let result = Errno::result(unsafe { libc::close(self.fd) }); - if let Err(Errno::EBADF) = result { - panic!("close of TimerFd encountered EBADF"); - } - } - } -} From c5cc9ddb0aa5cec59da932b67f1b167023edebec Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Fri, 9 Dec 2022 13:21:04 -0800 Subject: [PATCH 253/358] Formatting only changes for #1928 and #1863 Signed-off-by: Alex Saveau --- src/fcntl.rs | 126 +++-- src/sys/epoll.rs | 62 ++- src/unistd.rs | 1273 ++++++++++++++++++++++++++++++++-------------- 3 files changed, 1026 insertions(+), 435 deletions(-) diff --git a/src/fcntl.rs b/src/fcntl.rs index 65bbd4ca7a..1e24f603f6 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -193,9 +193,13 @@ feature! { // The conversion is not identical on all operating systems. #[allow(clippy::useless_conversion)] -pub fn open(path: &P, oflag: OFlag, mode: Mode) -> Result { - let fd = path.with_nix_path(|cstr| { - unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) } +pub fn open( + path: &P, + oflag: OFlag, + mode: Mode, +) -> Result { + let fd = path.with_nix_path(|cstr| unsafe { + libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) })?; Errno::result(fd) @@ -210,8 +214,8 @@ pub fn openat( oflag: OFlag, mode: Mode, ) -> Result { - let fd = path.with_nix_path(|cstr| { - unsafe { libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) } + let fd = path.with_nix_path(|cstr| unsafe { + libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) })?; Errno::result(fd) } @@ -303,7 +307,10 @@ fn readlink_maybe_at( }) } -fn inner_readlink(dirfd: Option, path: &P) -> Result { +fn inner_readlink( + dirfd: Option, + path: &P, +) -> Result { let mut v = Vec::with_capacity(libc::PATH_MAX as usize); { @@ -387,7 +394,10 @@ pub fn readlink(path: &P) -> Result { } #[cfg(not(target_os = "redox"))] -pub fn readlinkat(dirfd: RawFd, path: &P) -> Result { +pub fn readlinkat( + dirfd: RawFd, + path: &P, +) -> Result { inner_readlink(Some(dirfd), path) } @@ -450,9 +460,17 @@ pub enum FcntlArg<'a> { F_OFD_SETLKW(&'a libc::flock), #[cfg(any(target_os = "linux", target_os = "android"))] F_OFD_GETLK(&'a mut libc::flock), - #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "freebsd" + ))] F_ADD_SEALS(SealFlag), - #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "freebsd" + ))] F_GET_SEALS, #[cfg(any(target_os = "macos", target_os = "ios"))] F_FULLFSYNC, @@ -481,7 +499,9 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result { let res = unsafe { match arg { F_DUPFD(rawfd) => libc::fcntl(fd, libc::F_DUPFD, rawfd), - F_DUPFD_CLOEXEC(rawfd) => libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, rawfd), + F_DUPFD_CLOEXEC(rawfd) => { + libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, rawfd) + } F_GETFD => libc::fcntl(fd, libc::F_GETFD), F_SETFD(flag) => libc::fcntl(fd, libc::F_SETFD, flag.bits()), F_GETFL => libc::fcntl(fd, libc::F_GETFL), @@ -498,9 +518,19 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result { F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock), #[cfg(any(target_os = "android", target_os = "linux"))] F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock), - #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] - F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()), - #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "freebsd" + ))] + F_ADD_SEALS(flag) => { + libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()) + } + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "freebsd" + ))] F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS), #[cfg(any(target_os = "macos", target_os = "ios"))] F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC), @@ -535,8 +565,12 @@ pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> { LockShared => libc::flock(fd, libc::LOCK_SH), LockExclusive => libc::flock(fd, libc::LOCK_EX), Unlock => libc::flock(fd, libc::LOCK_UN), - LockSharedNonblock => libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB), - LockExclusiveNonblock => libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB), + LockSharedNonblock => { + libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB) + } + LockExclusiveNonblock => { + libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB) + } UnlockNonblock => libc::flock(fd, libc::LOCK_UN | libc::LOCK_NB), } }; @@ -632,12 +666,19 @@ pub fn splice( .map(|offset| offset as *mut libc::loff_t) .unwrap_or(ptr::null_mut()); - let ret = unsafe { libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) }; + let ret = unsafe { + libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) + }; Errno::result(ret).map(|r| r as usize) } #[cfg(any(target_os = "linux", target_os = "android"))] -pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Result { +pub fn tee( + fd_in: RawFd, + fd_out: RawFd, + len: usize, + flags: SpliceFFlags, +) -> Result { let ret = unsafe { libc::tee(fd_in, fd_out, len, flags.bits()) }; Errno::result(ret).map(|r| r as usize) } @@ -646,9 +687,8 @@ pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Resu pub fn vmsplice( fd: RawFd, iov: &[std::io::IoSlice<'_>], - flags: SpliceFFlags - ) -> Result -{ + flags: SpliceFFlags, +) -> Result { let ret = unsafe { libc::vmsplice( fd, @@ -778,14 +818,19 @@ impl SpacectlRange { /// ``` #[cfg(target_os = "freebsd")] pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result { - let mut rqsr = libc::spacectl_range{r_offset: range.0, r_len: range.1}; - let res = unsafe { libc::fspacectl( + let mut rqsr = libc::spacectl_range { + r_offset: range.0, + r_len: range.1, + }; + let res = unsafe { + libc::fspacectl( fd, libc::SPACECTL_DEALLOC, // Only one command is supported ATM &rqsr, - 0, // No flags are currently supported - &mut rqsr - )}; + 0, // No flags are currently supported + &mut rqsr, + ) + }; Errno::result(res).map(|_| SpacectlRange(rqsr.r_offset, rqsr.r_len)) } @@ -820,18 +865,25 @@ pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result { /// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef"); /// ``` #[cfg(target_os = "freebsd")] -pub fn fspacectl_all(fd: RawFd, offset: libc::off_t, len: libc::off_t) - -> Result<()> -{ - let mut rqsr = libc::spacectl_range{r_offset: offset, r_len: len}; +pub fn fspacectl_all( + fd: RawFd, + offset: libc::off_t, + len: libc::off_t, +) -> Result<()> { + let mut rqsr = libc::spacectl_range { + r_offset: offset, + r_len: len, + }; while rqsr.r_len > 0 { - let res = unsafe { libc::fspacectl( + let res = unsafe { + libc::fspacectl( fd, libc::SPACECTL_DEALLOC, // Only one command is supported ATM &rqsr, - 0, // No flags are currently supported - &mut rqsr - )}; + 0, // No flags are currently supported + &mut rqsr, + ) + }; Errno::result(res)?; } Ok(()) @@ -848,8 +900,8 @@ pub fn fspacectl_all(fd: RawFd, offset: libc::off_t, len: libc::off_t) ))] mod posix_fadvise { use crate::errno::Errno; - use std::os::unix::io::RawFd; use crate::Result; + use std::os::unix::io::RawFd; #[cfg(feature = "fs")] libc_enum! { @@ -894,7 +946,11 @@ mod posix_fadvise { target_os = "wasi", target_os = "freebsd" ))] -pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<()> { +pub fn posix_fallocate( + fd: RawFd, + offset: libc::off_t, + len: libc::off_t, +) -> Result<()> { let res = unsafe { libc::posix_fallocate(fd, offset, len) }; match Errno::result(res) { Err(err) => Err(err), diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 02c25d4d04..9fdb1495bc 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -2,7 +2,7 @@ use crate::errno::Errno; use crate::Result; use libc::{self, c_int}; use std::mem; -use std::os::unix::io::{FromRawFd,RawFd, OwnedFd, AsFd, AsRawFd}; +use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd}; libc_bitflags!( pub struct EpollFlags: c_int { @@ -78,22 +78,22 @@ impl EpollEvent { /// # fn main() -> nix::Result<()> { /// const DATA: u64 = 17; /// const MILLIS: u64 = 100; -/// +/// /// // Create epoll /// let epoll = Epoll::new(EpollCreateFlags::empty())?; -/// +/// /// // Create eventfd & Add event /// let eventfd = unsafe { OwnedFd::from_raw_fd(eventfd(0, EfdFlags::empty())?) }; /// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?; -/// +/// /// // Arm eventfd & Time wait /// write(eventfd.as_raw_fd(), &1u64.to_ne_bytes())?; /// let now = Instant::now(); -/// +/// /// // Wait on event /// let mut events = [EpollEvent::empty()]; /// epoll.wait(&mut events, MILLIS as isize)?; -/// +/// /// // Assert data correct & timeout didn't occur /// assert_eq!(events[0].data(), DATA); /// assert!(now.elapsed() < Duration::from_millis(MILLIS)); @@ -104,7 +104,7 @@ impl EpollEvent { pub struct Epoll(pub OwnedFd); impl Epoll { /// Creates a new epoll instance and returns a file descriptor referring to that instance. - /// + /// /// [`epoll_create1`](https://man7.org/linux/man-pages/man2/epoll_create1.2.html). pub fn new(flags: EpollCreateFlags) -> Result { let res = unsafe { libc::epoll_create1(flags.bits()) }; @@ -113,30 +113,38 @@ impl Epoll { Ok(Self(owned_fd)) } /// Add an entry to the interest list of the epoll file descriptor for - /// specified in events. - /// + /// specified in events. + /// /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_ADD`. pub fn add(&self, fd: Fd, mut event: EpollEvent) -> Result<()> { - self.epoll_ctl(EpollOp::EpollCtlAdd,fd,&mut event) + self.epoll_ctl(EpollOp::EpollCtlAdd, fd, &mut event) } /// Remove (deregister) the target file descriptor `fd` from the interest list. - /// + /// /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_DEL` . pub fn delete(&self, fd: Fd) -> Result<()> { - self.epoll_ctl(EpollOp::EpollCtlDel,fd,None) + self.epoll_ctl(EpollOp::EpollCtlDel, fd, None) } /// Change the settings associated with `fd` in the interest list to the new settings specified /// in `event`. - /// + /// /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_MOD`. - pub fn modify(&self,fd: Fd, event: &mut EpollEvent) -> Result<()> { - self.epoll_ctl(EpollOp::EpollCtlMod,fd,event) + pub fn modify( + &self, + fd: Fd, + event: &mut EpollEvent, + ) -> Result<()> { + self.epoll_ctl(EpollOp::EpollCtlMod, fd, event) } /// Waits for I/O events, blocking the calling thread if no events are currently available. /// (This can be thought of as fetching items from the ready list of the epoll instance.) - /// + /// /// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html) - pub fn wait(&self, events: &mut [EpollEvent], timeout: isize) -> Result { + pub fn wait( + &self, + events: &mut [EpollEvent], + timeout: isize, + ) -> Result { let res = unsafe { libc::epoll_wait( self.0.as_raw_fd(), @@ -145,15 +153,15 @@ impl Epoll { timeout as c_int, ) }; - + Errno::result(res).map(|r| r as usize) } /// This system call is used to add, modify, or remove entries in the interest list of the epoll /// instance referred to by `self`. It requests that the operation `op` be performed for the /// target file descriptor, `fd`. - /// + /// /// When possible prefer [`Epoll::add`], [`Epoll::delete`] and [`Epoll::modify`]. - /// + /// /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) fn epoll_ctl<'a, Fd: AsFd, T>( &self, @@ -165,9 +173,17 @@ impl Epoll { T: Into>, { let event: Option<&mut EpollEvent> = event.into(); - let ptr = event.map(|x|&mut x.event as *mut libc::epoll_event).unwrap_or(std::ptr::null_mut()); + let ptr = event + .map(|x| &mut x.event as *mut libc::epoll_event) + .unwrap_or(std::ptr::null_mut()); unsafe { - Errno::result(libc::epoll_ctl(self.0.as_raw_fd(), op as c_int, fd.as_fd().as_raw_fd(), ptr)).map(drop) + Errno::result(libc::epoll_ctl( + self.0.as_raw_fd(), + op as c_int, + fd.as_fd().as_raw_fd(), + ptr, + )) + .map(drop) } } } @@ -231,4 +247,4 @@ pub fn epoll_wait( }; Errno::result(res).map(|r| r as usize) -} \ No newline at end of file +} diff --git a/src/unistd.rs b/src/unistd.rs index 1bfeb7b94f..ae1cca9542 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -217,7 +217,6 @@ impl fmt::Display for Pid { } } - /// Represents the successful result of calling `fork` /// /// When `fork` is called, the process continues execution in the parent process @@ -230,7 +229,6 @@ pub enum ForkResult { } impl ForkResult { - /// Return `true` if this is the child process of the `fork()` #[inline] pub fn is_child(self) -> bool { @@ -478,9 +476,8 @@ fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result { /// pages for additional details on possible failure cases. #[inline] pub fn chdir(path: &P) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::chdir(cstr.as_ptr()) } - })?; + let res = + path.with_nix_path(|cstr| unsafe { libc::chdir(cstr.as_ptr()) })?; Errno::result(res).map(drop) } @@ -527,8 +524,8 @@ pub fn fchdir(dirfd: RawFd) -> Result<()> { /// ``` #[inline] pub fn mkdir(path: &P, mode: Mode) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) } + let res = path.with_nix_path(|cstr| unsafe { + libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) })?; Errno::result(res).map(drop) @@ -566,8 +563,8 @@ pub fn mkdir(path: &P, mode: Mode) -> Result<()> { #[inline] #[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet pub fn mkfifo(path: &P, mode: Mode) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) } + let res = path.with_nix_path(|cstr| unsafe { + libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) })?; Errno::result(res).map(drop) @@ -591,7 +588,11 @@ pub fn mkfifo(path: &P, mode: Mode) -> Result<()> { target_os = "android", target_os = "redox" )))] -pub fn mkfifoat(dirfd: Option, path: &P, mode: Mode) -> Result<()> { +pub fn mkfifoat( + dirfd: Option, + path: &P, + mode: Mode, +) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t) })?; @@ -612,19 +613,17 @@ pub fn mkfifoat(dirfd: Option, path: &P, mode: Mode) pub fn symlinkat( path1: &P1, dirfd: Option, - path2: &P2) -> Result<()> { - let res = - path1.with_nix_path(|path1| { - path2.with_nix_path(|path2| { - unsafe { - libc::symlinkat( - path1.as_ptr(), - dirfd.unwrap_or(libc::AT_FDCWD), - path2.as_ptr() - ) - } - }) - })??; + path2: &P2, +) -> Result<()> { + let res = path1.with_nix_path(|path1| { + path2.with_nix_path(|path2| unsafe { + libc::symlinkat( + path1.as_ptr(), + dirfd.unwrap_or(libc::AT_FDCWD), + path2.as_ptr(), + ) + }) + })??; Errno::result(res).map(drop) } } @@ -674,7 +673,9 @@ pub fn getcwd() -> Result { // To safely handle this we start with a reasonable size (512 bytes) // and double the buffer size upon every error if !libc::getcwd(ptr, buf.capacity()).is_null() { - let len = CStr::from_ptr(buf.as_ptr() as *const c_char).to_bytes().len(); + let len = CStr::from_ptr(buf.as_ptr() as *const c_char) + .to_bytes() + .len(); buf.set_len(len); buf.shrink_to_fit(); return Ok(PathBuf::from(OsString::from_vec(buf))); @@ -684,7 +685,7 @@ pub fn getcwd() -> Result { if error != Errno::ERANGE { return Err(error); } - } + } // Trigger the internal buffer resizing logic. reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?; @@ -699,10 +700,7 @@ feature! { /// Computes the raw UID and GID values to pass to a `*chown` call. // The cast is not unnecessary on all platforms. #[allow(clippy::unnecessary_cast)] -fn chown_raw_ids( - owner: Option, - group: Option, -) -> (uid_t, gid_t) { +fn chown_raw_ids(owner: Option, group: Option) -> (uid_t, gid_t) { // According to the POSIX specification, -1 is used to indicate that owner and group // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap // around to get -1. @@ -792,8 +790,13 @@ pub fn fchownat( }; let res = path.with_nix_path(|cstr| unsafe { let (uid, gid) = chown_raw_ids(owner, group); - libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid, - atflag.bits() as libc::c_int) + libc::fchownat( + at_rawfd(dirfd), + cstr.as_ptr(), + uid, + gid, + atflag.bits() as libc::c_int, + ) })?; Errno::result(res).map(drop) @@ -912,13 +915,15 @@ pub fn execvpe, SE: AsRef>( target_os = "freebsd" ))] #[inline] -pub fn fexecve ,SE: AsRef>(fd: RawFd, args: &[SA], env: &[SE]) -> Result { +pub fn fexecve, SE: AsRef>( + fd: RawFd, + args: &[SA], + env: &[SE], +) -> Result { let args_p = to_exec_array(args); let env_p = to_exec_array(env); - unsafe { - libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr()) - }; + unsafe { libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr()) }; Err(Errno::last()) } @@ -935,14 +940,25 @@ pub fn fexecve ,SE: AsRef>(fd: RawFd, args: &[SA], env: &[ /// is referenced as a file descriptor to the base directory plus a path. #[cfg(any(target_os = "android", target_os = "linux"))] #[inline] -pub fn execveat,SE: AsRef>(dirfd: RawFd, pathname: &CStr, args: &[SA], - env: &[SE], flags: super::fcntl::AtFlags) -> Result { +pub fn execveat, SE: AsRef>( + dirfd: RawFd, + pathname: &CStr, + args: &[SA], + env: &[SE], + flags: super::fcntl::AtFlags, +) -> Result { let args_p = to_exec_array(args); let env_p = to_exec_array(env); unsafe { - libc::syscall(libc::SYS_execveat, dirfd, pathname.as_ptr(), - args_p.as_ptr(), env_p.as_ptr(), flags); + libc::syscall( + libc::SYS_execveat, + dirfd, + pathname.as_ptr(), + args_p.as_ptr(), + env_p.as_ptr(), + flags, + ); }; Err(Errno::last()) @@ -1157,7 +1173,11 @@ pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result { } #[cfg(any(target_os = "linux", target_os = "android"))] -pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result { +pub fn lseek64( + fd: RawFd, + offset: libc::off64_t, + whence: Whence, +) -> Result { let res = unsafe { libc::lseek64(fd, offset, whence as i32) }; Errno::result(res).map(|r| r as libc::off64_t) @@ -1211,9 +1231,8 @@ feature! { pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); - let res = unsafe { - libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) - }; + let res = + unsafe { libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) }; Errno::result(res)?; @@ -1283,27 +1302,22 @@ pub fn linkat( newpath: &P, flag: LinkatFlags, ) -> Result<()> { + let atflag = match flag { + LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW, + LinkatFlags::NoSymlinkFollow => AtFlags::empty(), + }; - let atflag = - match flag { - LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW, - LinkatFlags::NoSymlinkFollow => AtFlags::empty(), - }; - - let res = - oldpath.with_nix_path(|oldcstr| { - newpath.with_nix_path(|newcstr| { - unsafe { - libc::linkat( - at_rawfd(olddirfd), - oldcstr.as_ptr(), - at_rawfd(newdirfd), - newcstr.as_ptr(), - atflag.bits() as libc::c_int - ) - } - }) - })??; + let res = oldpath.with_nix_path(|oldcstr| { + newpath.with_nix_path(|newcstr| unsafe { + libc::linkat( + at_rawfd(olddirfd), + oldcstr.as_ptr(), + at_rawfd(newdirfd), + newcstr.as_ptr(), + atflag.bits() as libc::c_int, + ) + }) + })??; Errno::result(res).map(drop) } @@ -1339,15 +1353,16 @@ pub fn unlinkat( path: &P, flag: UnlinkatFlags, ) -> Result<()> { - let atflag = - match flag { - UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR, - UnlinkatFlags::NoRemoveDir => AtFlags::empty(), - }; - let res = path.with_nix_path(|cstr| { - unsafe { - libc::unlinkat(at_rawfd(dirfd), cstr.as_ptr(), atflag.bits() as libc::c_int) - } + let atflag = match flag { + UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR, + UnlinkatFlags::NoRemoveDir => AtFlags::empty(), + }; + let res = path.with_nix_path(|cstr| unsafe { + libc::unlinkat( + at_rawfd(dirfd), + cstr.as_ptr(), + atflag.bits() as libc::c_int, + ) })?; Errno::result(res).map(drop) } @@ -1562,27 +1577,31 @@ pub fn getgroups() -> Result> { // Now actually get the groups. We try multiple times in case the number of // groups has changed since the first call to getgroups() and the buffer is // now too small. - let mut groups = Vec::::with_capacity(Errno::result(ngroups)? as usize); + let mut groups = + Vec::::with_capacity(Errno::result(ngroups)? as usize); loop { // FIXME: On the platforms we currently support, the `Gid` struct has // the same representation in memory as a bare `gid_t`. This is not // necessarily the case on all Rust platforms, though. See RFC 1785. let ngroups = unsafe { - libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t) + libc::getgroups( + groups.capacity() as c_int, + groups.as_mut_ptr() as *mut gid_t, + ) }; match Errno::result(ngroups) { Ok(s) => { unsafe { groups.set_len(s as usize) }; return Ok(groups); - }, + } Err(Errno::EINVAL) => { // EINVAL indicates that the buffer size was too // small, resize it up to ngroups_max as limit. reserve_double_buffer_size(&mut groups, ngroups_max) .or(Err(Errno::EINVAL))?; - }, - Err(e) => return Err(e) + } + Err(e) => return Err(e), } } } @@ -1618,7 +1637,12 @@ pub fn getgroups() -> Result> { /// # /// # try_main().unwrap(); /// ``` -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))] +#[cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "haiku" +)))] pub fn setgroups(groups: &[Gid]) -> Result<()> { cfg_if! { if #[cfg(any(target_os = "dragonfly", @@ -1638,7 +1662,10 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { // same representation in memory as a bare `gid_t`. This is not necessarily // the case on all Rust platforms, though. See RFC 1785. let res = unsafe { - libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t) + libc::setgroups( + groups.len() as setgroups_ngroups_t, + groups.as_ptr() as *const gid_t, + ) }; Errno::result(res).map(drop) @@ -1664,10 +1691,12 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { /// and `setgroups()`. Additionally, while some implementations will return a /// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation /// will only ever return the complete list or else an error. -#[cfg(not(any(target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "redox")))] +#[cfg(not(any( + target_os = "illumos", + target_os = "ios", + target_os = "macos", + target_os = "redox" +)))] pub fn getgrouplist(user: &CStr, group: Gid) -> Result> { let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { Ok(Some(n)) => n as c_int, @@ -1686,10 +1715,12 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result> { loop { let mut ngroups = groups.capacity() as i32; let ret = unsafe { - libc::getgrouplist(user.as_ptr(), - gid as getgrouplist_group_t, - groups.as_mut_ptr() as *mut getgrouplist_group_t, - &mut ngroups) + libc::getgrouplist( + user.as_ptr(), + gid as getgrouplist_group_t, + groups.as_mut_ptr() as *mut getgrouplist_group_t, + &mut ngroups, + ) }; // BSD systems only return 0 or -1, Linux returns ngroups on success. @@ -1745,7 +1776,12 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result> { /// # /// # try_main().unwrap(); /// ``` -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))] +#[cfg(not(any( + target_os = "ios", + target_os = "macos", + target_os = "redox", + target_os = "haiku" +)))] pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { cfg_if! { if #[cfg(any(target_os = "ios", target_os = "macos"))] { @@ -1755,7 +1791,8 @@ pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { } } let gid: gid_t = group.into(); - let res = unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) }; + let res = + unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) }; Errno::result(res).map(drop) } @@ -1799,8 +1836,8 @@ pub mod alarm { //! //! Scheduling an alarm and waiting for the signal: //! -#![cfg_attr(target_os = "redox", doc = " ```rust,ignore")] -#![cfg_attr(not(target_os = "redox"), doc = " ```rust")] + #![cfg_attr(target_os = "redox", doc = " ```rust,ignore")] + #![cfg_attr(not(target_os = "redox"), doc = " ```rust")] //! use std::time::{Duration, Instant}; //! //! use nix::unistd::{alarm, pause}; @@ -1876,17 +1913,16 @@ feature! { #[cfg(not(any(target_os = "redox", target_os = "haiku")))] pub mod acct { - use crate::{Result, NixPath}; use crate::errno::Errno; + use crate::{NixPath, Result}; use std::ptr; /// Enable process accounting /// /// See also [acct(2)](https://linux.die.net/man/2/acct) pub fn enable(filename: &P) -> Result<()> { - let res = filename.with_nix_path(|cstr| { - unsafe { libc::acct(cstr.as_ptr()) } - })?; + let res = filename + .with_nix_path(|cstr| unsafe { libc::acct(cstr.as_ptr()) })?; Errno::result(res).map(drop) } @@ -1928,7 +1964,8 @@ feature! { /// ``` #[inline] pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { - let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?; + let mut path = + template.with_nix_path(|path| path.to_bytes_with_nul().to_owned())?; let p = path.as_mut_ptr() as *mut _; let fd = unsafe { libc::mkstemp(p) }; let last = path.pop(); // drop the trailing nul @@ -1962,8 +1999,14 @@ feature! { #[repr(i32)] #[non_exhaustive] pub enum PathconfVar { - #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux", - target_os = "netbsd", target_os = "openbsd", target_os = "redox"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox" + ))] /// Minimum number of bits needed to represent, as a signed integer value, /// the maximum size of a regular file allowed in the specified directory. #[cfg_attr(docsrs, doc(cfg(all())))] @@ -1987,42 +2030,86 @@ pub enum PathconfVar { /// Maximum number of bytes that is guaranteed to be atomic when writing to /// a pipe. PIPE_BUF = libc::_PC_PIPE_BUF, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "illumos", - target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_os = "redox", target_os = "solaris"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Symbolic links can be created. POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "linux", target_os = "openbsd", target_os = "redox"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd", + target_os = "redox" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Minimum number of bytes of storage actually allocated for any portion of /// a file. POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "linux", target_os = "openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Recommended increment for file transfer sizes between the /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values. POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "linux", target_os = "openbsd", target_os = "redox"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd", + target_os = "redox" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Maximum recommended file transfer size. POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "linux", target_os = "openbsd", target_os = "redox"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd", + target_os = "redox" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Minimum recommended file transfer size. POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "linux", target_os = "openbsd", target_os = "redox"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd", + target_os = "redox" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Recommended file transfer buffer alignment. POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "netbsd", - target_os = "openbsd", target_os = "redox", target_os = "solaris"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Maximum number of bytes in a symbolic link. SYMLINK_MAX = libc::_PC_SYMLINK_MAX, @@ -2036,23 +2123,45 @@ pub enum PathconfVar { /// This symbol shall be defined to be the value of a character that shall /// disable terminal special character handling. _POSIX_VDISABLE = libc::_PC_VDISABLE, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "openbsd", - target_os = "redox", target_os = "solaris"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Asynchronous input or output operations may be performed for the /// associated file. _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "openbsd", - target_os = "redox", target_os = "solaris"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Prioritized input or output operations may be performed for the /// associated file. _POSIX_PRIO_IO = libc::_PC_PRIO_IO, - #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "illumos", target_os = "linux", target_os = "netbsd", - target_os = "openbsd", target_os = "redox", target_os = "solaris"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Synchronized input or output operations may be performed for the /// associated file. @@ -2060,7 +2169,7 @@ pub enum PathconfVar { #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The resolution in nanoseconds for all file timestamps. - _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION + _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION, } /// Like `pathconf`, but works with file descriptors instead of paths (see @@ -2116,12 +2225,13 @@ pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result> { /// - `Ok(None)`: the variable has no limit (for limit variables) or is /// unsupported (for option variables) /// - `Err(x)`: an error occurred -pub fn pathconf(path: &P, var: PathconfVar) -> Result> { - let raw = path.with_nix_path(|cstr| { - unsafe { - Errno::clear(); - libc::pathconf(cstr.as_ptr(), var as c_int) - } +pub fn pathconf( + path: &P, + var: PathconfVar, +) -> Result> { + let raw = path.with_nix_path(|cstr| unsafe { + Errno::clear(); + libc::pathconf(cstr.as_ptr(), var as c_int) })?; if raw == -1 { if errno::errno() == 0 { @@ -2168,9 +2278,15 @@ pub enum SysconfVar { #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] AIO_MAX = libc::_SC_AIO_MAX, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum amount by which a process can decrease its asynchronous I/O /// priority level from its own scheduling priority. @@ -2215,9 +2331,17 @@ pub enum SysconfVar { #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Maximum length of a host name (not including the terminating null) as /// returned from the `gethostname` function @@ -2258,14 +2382,28 @@ pub enum SysconfVar { /// A value one greater than the maximum value that the system may assign to /// a newly-created file descriptor. OPEN_MAX = libc::_SC_OPEN_MAX, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Advisory Information option. _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports barriers. _POSIX_BARRIERS = libc::_SC_BARRIERS, @@ -2273,15 +2411,31 @@ pub enum SysconfVar { #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports clock selection. _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Process CPU-Time Clocks option. _POSIX_CPUTIME = libc::_SC_CPUTIME, @@ -2289,9 +2443,16 @@ pub enum SysconfVar { #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_FSYNC = libc::_SC_FSYNC, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd", target_os = "solaris"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the IPv6 option. _POSIX_IPV6 = libc::_SC_IPV6, @@ -2323,9 +2484,17 @@ pub enum SysconfVar { #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "illumos", target_os = "ios", target_os="linux", - target_os = "macos", target_os="openbsd", target_os = "solaris"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Prioritized Input and Output option. _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO, @@ -2333,27 +2502,56 @@ pub enum SysconfVar { #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd", target_os = "solaris"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Raw Sockets option. _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports read-write locks. _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS, - #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os = "openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports realtime signals. _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd", target_os = "solaris"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Regular Expression Handling option. _POSIX_REGEXP = libc::_SC_REGEXP, @@ -2369,31 +2567,59 @@ pub enum SysconfVar { #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the POSIX shell. _POSIX_SHELL = libc::_SC_SHELL, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Spawn option. _POSIX_SPAWN = libc::_SC_SPAWN, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports spin locks. _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Process Sporadic Server option. _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER, - #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX, /// The implementation supports the Synchronized Input and Output option. @@ -2408,8 +2634,13 @@ pub enum SysconfVar { #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE, - #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", - target_os="netbsd", target_os="openbsd"))] + #[cfg(any( + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Thread CPU-Time Clocks option. _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME, @@ -2426,18 +2657,32 @@ pub enum SysconfVar { #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Thread Process-Shared Synchronization /// option. _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED, - #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "linux", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Robust Mutex Priority Inheritance option. _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT, - #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "linux", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Robust Mutex Priority Protection option. _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT, @@ -2445,8 +2690,14 @@ pub enum SysconfVar { #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Thread Sporadic Server option. _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER, @@ -2454,8 +2705,14 @@ pub enum SysconfVar { #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREADS = libc::_SC_THREADS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports timeouts. _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS, @@ -2463,44 +2720,90 @@ pub enum SysconfVar { #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TIMERS = libc::_SC_TIMERS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace option. _POSIX_TRACE = libc::_SC_TRACE, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace Event Filter option. _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER, - #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace Inherit option. _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace Log option. _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG, - #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX, - #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX, - #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Typed Memory Objects option. _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS, @@ -2508,31 +2811,55 @@ pub enum SysconfVar { /// to which the implementation conforms. For implementations conforming to /// POSIX.1-2008, the value shall be 200809L. _POSIX_VERSION = libc::_SC_VERSION, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation provides a C-language compilation environment with /// 32-bit `int`, `long`, `pointer`, and `off_t` types. _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation provides a C-language compilation environment with /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at /// least 64 bits. _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation provides a C-language compilation environment with /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types. _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation provides a C-language compilation environment with an /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types @@ -2563,40 +2890,76 @@ pub enum SysconfVar { #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Batch Environment Services and Utilities /// option. _POSIX2_PBS = libc::_SC_2_PBS, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Batch Accounting option. _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Batch Checkpoint/Restart option. _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Locate Batch Job Request option. _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Batch Job Message Request option. _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Track Batch Job Request option. _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK, @@ -2632,28 +2995,52 @@ pub enum SysconfVar { PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX, #[cfg(not(target_os = "haiku"))] RE_DUP_MAX = libc::_SC_RE_DUP_MAX, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] RTSIG_MAX = libc::_SC_RTSIG_MAX, #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX, - #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os = "openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX, STREAM_MAX = libc::_SC_STREAM_MAX, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="netbsd", - target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX, #[cfg(not(target_os = "redox"))] @@ -2661,33 +3048,63 @@ pub enum SysconfVar { TIMER_MAX = libc::_SC_TIMER_MAX, TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX, TZNAME_MAX = libc::_SC_TZNAME_MAX, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the X/Open Encryption Option Group. _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Issue 4, Version 2 Enhanced /// Internationalization Option Group. _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the X/Open Realtime Option Group. _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the X/Open Realtime Threads Option Group. _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS, @@ -2696,36 +3113,54 @@ pub enum SysconfVar { #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] _XOPEN_SHM = libc::_SC_XOPEN_SHM, - #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios", - target_os="linux", target_os = "macos", target_os="openbsd"))] + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the XSI STREAMS Option Group. _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the XSI option _XOPEN_UNIX = libc::_SC_XOPEN_UNIX, - #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd", - target_os = "ios", target_os="linux", target_os = "macos", - target_os="openbsd"))] + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd" + ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Integer value indicating version of the X/Open Portability Guide to /// which the implementation conforms. _XOPEN_VERSION = libc::_SC_XOPEN_VERSION, /// The number of pages of physical memory. Note that it is possible for /// the product of this value to overflow. - #[cfg(any(target_os="android", target_os="linux"))] + #[cfg(any(target_os = "android", target_os = "linux"))] _PHYS_PAGES = libc::_SC_PHYS_PAGES, /// The number of currently available pages of physical memory. - #[cfg(any(target_os="android", target_os="linux"))] + #[cfg(any(target_os = "android", target_os = "linux"))] _AVPHYS_PAGES = libc::_SC_AVPHYS_PAGES, /// The number of processors configured. - #[cfg(any(target_os="android", target_os="linux"))] + #[cfg(any(target_os = "android", target_os = "linux"))] _NPROCESSORS_CONF = libc::_SC_NPROCESSORS_CONF, /// The number of processors currently online (available). - #[cfg(any(target_os="android", target_os="linux"))] + #[cfg(any(target_os = "android", target_os = "linux"))] _NPROCESSORS_ONLN = libc::_SC_NPROCESSORS_ONLN, } @@ -2797,9 +3232,9 @@ mod setres { feature! { #![feature = "user"] - use crate::Result; + use super::{Gid, Uid}; use crate::errno::Errno; - use super::{Uid, Gid}; + use crate::Result; /// Sets the real, effective, and saved uid. /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html)) @@ -2812,7 +3247,8 @@ mod setres { /// Err is returned if the user doesn't have permission to set this UID. #[inline] pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> { - let res = unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) }; + let res = + unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) }; Errno::result(res).map(drop) } @@ -2828,7 +3264,8 @@ mod setres { /// Err is returned if the user doesn't have permission to set this GID. #[inline] pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> { - let res = unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) }; + let res = + unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) }; Errno::result(res).map(drop) } @@ -2846,16 +3283,16 @@ mod getres { feature! { #![feature = "user"] - use crate::Result; + use super::{Gid, Uid}; use crate::errno::Errno; - use super::{Uid, Gid}; + use crate::Result; /// Real, effective and saved user IDs. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct ResUid { pub real: Uid, pub effective: Uid, - pub saved: Uid + pub saved: Uid, } /// Real, effective and saved group IDs. @@ -2863,7 +3300,7 @@ mod getres { pub struct ResGid { pub real: Gid, pub effective: Gid, - pub saved: Gid + pub saved: Gid, } /// Gets the real, effective, and saved user IDs. @@ -2882,7 +3319,11 @@ mod getres { let mut suid = libc::uid_t::max_value(); let res = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) }; - Errno::result(res).map(|_| ResUid{ real: Uid(ruid), effective: Uid(euid), saved: Uid(suid) }) + Errno::result(res).map(|_| ResUid { + real: Uid(ruid), + effective: Uid(euid), + saved: Uid(suid), + }) } /// Gets the real, effective, and saved group IDs. @@ -2901,7 +3342,11 @@ mod getres { let mut sgid = libc::gid_t::max_value(); let res = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) }; - Errno::result(res).map(|_| ResGid { real: Gid(rgid), effective: Gid(egid), saved: Gid(sgid) } ) + Errno::result(res).map(|_| ResGid { + real: Gid(rgid), + effective: Gid(egid), + saved: Gid(sgid), + }) } } } @@ -2945,11 +3390,19 @@ pub fn access(path: &P, amode: AccessFlags) -> Result<()> { /// [faccessat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html) // redox: does not appear to support the *at family of syscalls. #[cfg(not(target_os = "redox"))] -pub fn faccessat(dirfd: Option, path: &P, mode: AccessFlags, flags: AtFlags) -> Result<()> { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::faccessat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits(), flags.bits()) - } +pub fn faccessat( + dirfd: Option, + path: &P, + mode: AccessFlags, + flags: AtFlags, +) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::faccessat( + at_rawfd(dirfd), + cstr.as_ptr(), + mode.bits(), + flags.bits(), + ) })?; Errno::result(res).map(drop) } @@ -3002,32 +3455,38 @@ pub struct User { /// Path to shell pub shell: PathBuf, /// Login class - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[cfg(not(any( + target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + )))] #[cfg_attr(docsrs, doc(cfg(all())))] pub class: CString, /// Last password change - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[cfg(not(any( + target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + )))] #[cfg_attr(docsrs, doc(cfg(all())))] pub change: libc::time_t, /// Expiration time of account - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[cfg(not(any( + target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + )))] #[cfg_attr(docsrs, doc(cfg(all())))] - pub expire: libc::time_t + pub expire: libc::time_t, } #[cfg(not(target_os = "redox"))] //RedoxFS does not support passwd @@ -3035,35 +3494,71 @@ impl From<&libc::passwd> for User { fn from(pw: &libc::passwd) -> User { unsafe { User { - name: if pw.pw_name.is_null() { Default::default() } else { CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned() }, - passwd: if pw.pw_passwd.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes()).unwrap() }, - #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] - gecos: if pw.pw_gecos.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes()).unwrap() }, - dir: if pw.pw_dir.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_dir).to_bytes())) }, - shell: if pw.pw_shell.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_shell).to_bytes())) }, + name: if pw.pw_name.is_null() { + Default::default() + } else { + CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned() + }, + passwd: if pw.pw_passwd.is_null() { + Default::default() + } else { + CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes()) + .unwrap() + }, + #[cfg(not(all( + target_os = "android", + target_pointer_width = "32" + )))] + gecos: if pw.pw_gecos.is_null() { + Default::default() + } else { + CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes()) + .unwrap() + }, + dir: if pw.pw_dir.is_null() { + Default::default() + } else { + PathBuf::from(OsStr::from_bytes( + CStr::from_ptr(pw.pw_dir).to_bytes(), + )) + }, + shell: if pw.pw_shell.is_null() { + Default::default() + } else { + PathBuf::from(OsStr::from_bytes( + CStr::from_ptr(pw.pw_shell).to_bytes(), + )) + }, uid: Uid::from_raw(pw.pw_uid), gid: Gid::from_raw(pw.pw_gid), - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes()).unwrap(), - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[cfg(not(any( + target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + )))] + class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes()) + .unwrap(), + #[cfg(not(any( + target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + )))] change: pw.pw_change, - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] - expire: pw.pw_expire + #[cfg(not(any( + target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + )))] + expire: pw.pw_expire, } } } @@ -3087,32 +3582,41 @@ impl From for libc::passwd { Self { pw_name: name, pw_passwd: u.passwd.into_raw(), - #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] + #[cfg(not(all( + target_os = "android", + target_pointer_width = "32" + )))] pw_gecos: u.gecos.into_raw(), pw_dir: dir, pw_shell: shell, pw_uid: u.uid.0, pw_gid: u.gid.0, - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[cfg(not(any( + target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + )))] pw_class: u.class.into_raw(), - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[cfg(not(any( + target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + )))] pw_change: u.change, - #[cfg(not(any(target_os = "android", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris")))] + #[cfg(not(any( + target_os = "android", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "linux", + target_os = "solaris" + )))] pw_expire: u.expire, #[cfg(target_os = "illumos")] pw_age: CString::new("").unwrap().into_raw(), @@ -3128,10 +3632,12 @@ impl From for libc::passwd { impl User { fn from_anything(f: F) -> Result> where - F: Fn(*mut libc::passwd, - *mut c_char, - libc::size_t, - *mut *mut libc::passwd) -> libc::c_int + F: Fn( + *mut libc::passwd, + *mut c_char, + libc::size_t, + *mut *mut libc::passwd, + ) -> libc::c_int, { let buflimit = 1048576; let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) { @@ -3144,7 +3650,12 @@ impl User { let mut res = ptr::null_mut(); loop { - let error = f(pwd.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res); + let error = f( + pwd.as_mut_ptr(), + cbuf.as_mut_ptr(), + cbuf.capacity(), + &mut res, + ); if error == 0 { if res.is_null() { return Ok(None); @@ -3175,8 +3686,8 @@ impl User { /// assert_eq!(res.name, "root"); /// ``` pub fn from_uid(uid: Uid) -> Result> { - User::from_anything(|pwd, cbuf, cap, res| { - unsafe { libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) } + User::from_anything(|pwd, cbuf, cap, res| unsafe { + libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) }) } @@ -3198,8 +3709,8 @@ impl User { Ok(c_str) => c_str, Err(_nul_error) => return Ok(None), }; - User::from_anything(|pwd, cbuf, cap, res| { - unsafe { libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) } + User::from_anything(|pwd, cbuf, cap, res| unsafe { + libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) }) } } @@ -3215,7 +3726,7 @@ pub struct Group { /// Group ID pub gid: Gid, /// List of Group members - pub mem: Vec + pub mem: Vec, } #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd @@ -3224,9 +3735,10 @@ impl From<&libc::group> for Group { unsafe { Group { name: CStr::from_ptr(gr.gr_name).to_string_lossy().into_owned(), - passwd: CString::new(CStr::from_ptr(gr.gr_passwd).to_bytes()).unwrap(), + passwd: CString::new(CStr::from_ptr(gr.gr_passwd).to_bytes()) + .unwrap(), gid: Gid::from_raw(gr.gr_gid), - mem: Group::members(gr.gr_mem) + mem: Group::members(gr.gr_mem), } } } @@ -3252,10 +3764,12 @@ impl Group { fn from_anything(f: F) -> Result> where - F: Fn(*mut libc::group, - *mut c_char, - libc::size_t, - *mut *mut libc::group) -> libc::c_int + F: Fn( + *mut libc::group, + *mut c_char, + libc::size_t, + *mut *mut libc::group, + ) -> libc::c_int, { let buflimit = 1048576; let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) { @@ -3268,7 +3782,12 @@ impl Group { let mut res = ptr::null_mut(); loop { - let error = f(grp.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res); + let error = f( + grp.as_mut_ptr(), + cbuf.as_mut_ptr(), + cbuf.capacity(), + &mut res, + ); if error == 0 { if res.is_null() { return Ok(None); @@ -3301,8 +3820,8 @@ impl Group { /// assert!(res.name == "root"); /// ``` pub fn from_gid(gid: Gid) -> Result> { - Group::from_anything(|grp, cbuf, cap, res| { - unsafe { libc::getgrgid_r(gid.0, grp, cbuf, cap, res) } + Group::from_anything(|grp, cbuf, cap, res| unsafe { + libc::getgrgid_r(gid.0, grp, cbuf, cap, res) }) } @@ -3326,8 +3845,8 @@ impl Group { Ok(c_str) => c_str, Err(_nul_error) => return Ok(None), }; - Group::from_anything(|grp, cbuf, cap, res| { - unsafe { libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) } + Group::from_anything(|grp, cbuf, cap, res| unsafe { + libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) }) } } From 147ed3f610287c061e88c5eddf66b2173f87c81f Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sat, 10 Dec 2022 11:33:09 +0000 Subject: [PATCH 254/358] signalfd optional file descriptor --- CHANGELOG.md | 2 ++ src/sys/signalfd.rs | 33 ++++++++++++++------------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c75e875ea0..3006435dfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - With I/O-safe type applied in `pty::OpenptyResult` and `pty::ForkptyResult`, users no longer need to manually close the file descriptors in these types. ([#1921](https://github.com/nix-rust/nix/pull/1921)) +- The `fd` argument to `sys::signalfd::signalfd` is now of type `Option`. + ([#1874](https://github.com/nix-rust/nix/pull/1874)) ### Fixed ### Removed diff --git a/src/sys/signalfd.rs b/src/sys/signalfd.rs index 095e590850..a53c86119d 100644 --- a/src/sys/signalfd.rs +++ b/src/sys/signalfd.rs @@ -17,12 +17,11 @@ //! signal handlers. use crate::errno::Errno; pub use crate::sys::signal::{self, SigSet}; -use crate::unistd; use crate::Result; pub use libc::signalfd_siginfo as siginfo; use std::mem; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, RawFd, FromRawFd, OwnedFd, AsFd, BorrowedFd}; libc_bitflags! { pub struct SfdFlags: libc::c_int { @@ -31,7 +30,6 @@ libc_bitflags! { } } -pub const SIGNALFD_NEW: RawFd = -1; #[deprecated(since = "0.23.0", note = "use mem::size_of::() instead")] pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::(); @@ -46,13 +44,14 @@ pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::(); /// signalfd (the default handler will be invoked instead). /// /// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html) -pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result { +pub fn signalfd(fd: Option, mask: &SigSet, flags: SfdFlags) -> Result { + let raw_fd = fd.map_or(-1, |x|x.as_fd().as_raw_fd()); unsafe { Errno::result(libc::signalfd( - fd as libc::c_int, + raw_fd, mask.as_ref(), flags.bits(), - )) + )).map(|raw_fd|FromRawFd::from_raw_fd(raw_fd)) } } @@ -82,8 +81,8 @@ pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result { /// Err(err) => (), // some error happend /// } /// ``` -#[derive(Debug, Eq, Hash, PartialEq)] -pub struct SignalFd(RawFd); +#[derive(Debug)] +pub struct SignalFd(OwnedFd); impl SignalFd { pub fn new(mask: &SigSet) -> Result { @@ -91,13 +90,13 @@ impl SignalFd { } pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result { - let fd = signalfd(SIGNALFD_NEW, mask, flags)?; + let fd = signalfd(None::, mask, flags)?; Ok(SignalFd(fd)) } pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> { - signalfd(self.0, mask, SfdFlags::empty()).map(drop) + signalfd(Some(self.0.as_fd()), mask, SfdFlags::empty()).map(drop) } pub fn read_signal(&mut self) -> Result> { @@ -105,7 +104,7 @@ impl SignalFd { let size = mem::size_of_val(&buffer); let res = Errno::result(unsafe { - libc::read(self.0, buffer.as_mut_ptr() as *mut libc::c_void, size) + libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr() as *mut libc::c_void, size) }) .map(|r| r as usize); match res { @@ -117,18 +116,14 @@ impl SignalFd { } } -impl Drop for SignalFd { - fn drop(&mut self) { - let e = unistd::close(self.0); - if !std::thread::panicking() && e == Err(Errno::EBADF) { - panic!("Closing an invalid file descriptor!"); - }; +impl AsFd for SignalFd { + fn as_fd(&self) -> BorrowedFd { + self.0.as_fd() } } - impl AsRawFd for SignalFd { fn as_raw_fd(&self) -> RawFd { - self.0 + self.0.as_raw_fd() } } From 9797e0c9f4288a3b7652c5fe6532f7379dfb9b8c Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 10 Dec 2022 11:46:04 -0700 Subject: [PATCH 255/358] Deprecate the signalfd function. The SignalFd type is just as capable and easier to use. --- CHANGELOG.md | 5 +++-- src/sys/signalfd.rs | 9 +++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3006435dfc..3597db8fd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,8 +19,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). - With I/O-safe type applied in `pty::OpenptyResult` and `pty::ForkptyResult`, users no longer need to manually close the file descriptors in these types. ([#1921](https://github.com/nix-rust/nix/pull/1921)) -- The `fd` argument to `sys::signalfd::signalfd` is now of type `Option`. - ([#1874](https://github.com/nix-rust/nix/pull/1874)) ### Fixed ### Removed @@ -29,6 +27,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1855](https://github.com/nix-rust/nix/pull/1855)) - Removed deprecated net APIs. ([#1861](https://github.com/nix-rust/nix/pull/1861)) +- `nix::sys::signalfd::signalfd` is deprecated. Use + `nix::sys::signalfd::SignalFd` instead. + ([#1938](https://github.com/nix-rust/nix/pull/1938)) ## [0.26.1] - 2022-11-29 ### Fixed diff --git a/src/sys/signalfd.rs b/src/sys/signalfd.rs index a53c86119d..2b80ea643f 100644 --- a/src/sys/signalfd.rs +++ b/src/sys/signalfd.rs @@ -44,7 +44,12 @@ pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::(); /// signalfd (the default handler will be invoked instead). /// /// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html) +#[deprecated(since = "0.27.0", note = "Use SignalFd instead")] pub fn signalfd(fd: Option, mask: &SigSet, flags: SfdFlags) -> Result { + _signalfd(fd, mask, flags) +} + +fn _signalfd(fd: Option, mask: &SigSet, flags: SfdFlags) -> Result { let raw_fd = fd.map_or(-1, |x|x.as_fd().as_raw_fd()); unsafe { Errno::result(libc::signalfd( @@ -90,13 +95,13 @@ impl SignalFd { } pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result { - let fd = signalfd(None::, mask, flags)?; + let fd = _signalfd(None::, mask, flags)?; Ok(SignalFd(fd)) } pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> { - signalfd(Some(self.0.as_fd()), mask, SfdFlags::empty()).map(drop) + _signalfd(Some(self.0.as_fd()), mask, SfdFlags::empty()).map(drop) } pub fn read_signal(&mut self) -> Result> { From 27d1844952386a52f190935f8fde1cc967f1e01f Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sun, 11 Dec 2022 12:19:58 +0800 Subject: [PATCH 256/358] feat: I/O safety for 'sys/memfd' & 'sys/event' & 'sys/eventfd' --- src/sys/epoll.rs | 2 +- src/sys/event.rs | 16 ++++++++-------- src/sys/eventfd.rs | 6 +++--- src/sys/memfd.rs | 6 +++--- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 9fdb1495bc..36f9c17d0e 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -83,7 +83,7 @@ impl EpollEvent { /// let epoll = Epoll::new(EpollCreateFlags::empty())?; /// /// // Create eventfd & Add event -/// let eventfd = unsafe { OwnedFd::from_raw_fd(eventfd(0, EfdFlags::empty())?) }; +/// let eventfd = eventfd(0, EfdFlags::empty())?; /// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?; /// /// // Arm eventfd & Time wait diff --git a/src/sys/event.rs b/src/sys/event.rs index d8ad628ea2..f21ba17324 100644 --- a/src/sys/event.rs +++ b/src/sys/event.rs @@ -8,7 +8,7 @@ use libc::{c_int, c_long, intptr_t, time_t, timespec, uintptr_t}; use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t}; use std::convert::TryInto; use std::mem; -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd}; use std::ptr; // Redefine kevent in terms of programmer-friendly enums and bitfields. @@ -207,10 +207,10 @@ libc_bitflags!( } ); -pub fn kqueue() -> Result { +pub fn kqueue() -> Result { let res = unsafe { libc::kqueue() }; - Errno::result(res) + Errno::result(res).map(|fd| unsafe { OwnedFd::from_raw_fd(fd) }) } // KEvent can't derive Send because on some operating systems, udata is defined @@ -267,8 +267,8 @@ impl KEvent { } } -pub fn kevent( - kq: RawFd, +pub fn kevent( + kq: Fd, changelist: &[KEvent], eventlist: &mut [KEvent], timeout_ms: usize, @@ -293,15 +293,15 @@ type type_of_nchanges = c_int; #[cfg(target_os = "netbsd")] type type_of_nchanges = size_t; -pub fn kevent_ts( - kq: RawFd, +pub fn kevent_ts( + kq: Fd, changelist: &[KEvent], eventlist: &mut [KEvent], timeout_opt: Option, ) -> Result { let res = unsafe { libc::kevent( - kq, + kq.as_fd().as_raw_fd(), changelist.as_ptr() as *const libc::kevent, changelist.len() as type_of_nchanges, eventlist.as_mut_ptr() as *mut libc::kevent, diff --git a/src/sys/eventfd.rs b/src/sys/eventfd.rs index cd906720cd..f1723519cf 100644 --- a/src/sys/eventfd.rs +++ b/src/sys/eventfd.rs @@ -1,6 +1,6 @@ use crate::errno::Errno; use crate::Result; -use std::os::unix::io::RawFd; +use std::os::unix::io::{FromRawFd, OwnedFd}; libc_bitflags! { pub struct EfdFlags: libc::c_int { @@ -10,8 +10,8 @@ libc_bitflags! { } } -pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result { +pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result { let res = unsafe { libc::eventfd(initval, flags.bits()) }; - Errno::result(res).map(|r| r as RawFd) + Errno::result(res).map(|r| unsafe { OwnedFd::from_raw_fd(r) }) } diff --git a/src/sys/memfd.rs b/src/sys/memfd.rs index ad9345e89d..f349a743ed 100644 --- a/src/sys/memfd.rs +++ b/src/sys/memfd.rs @@ -1,7 +1,7 @@ //! Interfaces for managing memory-backed files. use cfg_if::cfg_if; -use std::os::unix::io::RawFd; +use std::os::unix::io::{FromRawFd, OwnedFd, RawFd}; use crate::errno::Errno; use crate::Result; @@ -40,7 +40,7 @@ libc_bitflags!( /// For more information, see [`memfd_create(2)`]. /// /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html -pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result { +pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result { let res = unsafe { cfg_if! { if #[cfg(all( @@ -60,5 +60,5 @@ pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result { } }; - Errno::result(res).map(|r| r as RawFd) + Errno::result(res).map(|r| unsafe { OwnedFd::from_raw_fd(r as RawFd) }) } From c6e6d9201bbad2d0fea141c412611c95025b61ae Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sun, 11 Dec 2022 13:24:12 +0800 Subject: [PATCH 257/358] feat: I/O safety for 'sys/wait' --- src/sys/wait.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sys/wait.rs b/src/sys/wait.rs index b6524e8661..f7a63ffcd2 100644 --- a/src/sys/wait.rs +++ b/src/sys/wait.rs @@ -10,7 +10,7 @@ use std::convert::TryFrom; target_os = "android", all(target_os = "linux", not(target_env = "uclibc")), ))] -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsRawFd, BorrowedFd}; libc_bitflags!( /// Controls the behavior of [`waitpid`]. @@ -343,8 +343,8 @@ pub fn wait() -> Result { target_os = "haiku", all(target_os = "linux", not(target_env = "uclibc")), ))] -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Id { +#[derive(Debug)] +pub enum Id<'fd> { /// Wait for any child All, /// Wait for the child whose process ID matches the given PID @@ -355,7 +355,11 @@ pub enum Id { PGid(Pid), /// Wait for the child referred to by the given PID file descriptor #[cfg(any(target_os = "android", target_os = "linux"))] - PIDFd(RawFd), + PIDFd(BorrowedFd<'fd>), + /// A helper variant to resolve the unused parameter (`'fd`) problem on platforms + /// other than Linux and Android. + #[doc(hidden)] + _Unreachable(std::marker::PhantomData<&'fd std::convert::Infallible>), } /// Wait for a process to change status @@ -373,7 +377,8 @@ pub fn waitid(id: Id, flags: WaitPidFlag) -> Result { Id::Pid(pid) => (libc::P_PID, pid.as_raw() as libc::id_t), Id::PGid(pid) => (libc::P_PGID, pid.as_raw() as libc::id_t), #[cfg(any(target_os = "android", target_os = "linux"))] - Id::PIDFd(fd) => (libc::P_PIDFD, fd as libc::id_t), + Id::PIDFd(fd) => (libc::P_PIDFD, fd.as_raw_fd() as libc::id_t), + Id::_Unreachable(_) => unreachable!("This variant could never be constructed"), }; let siginfo = unsafe { From 47ecc9a1d0f26ef35f333d3f17304fa6e832d3f5 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Sun, 11 Dec 2022 14:04:13 +0800 Subject: [PATCH 258/358] feat: I/O safety for 'sys/poll' --- src/poll.rs | 52 +++++++++++++++++++++++++++++++++++++++-------- test/test_poll.rs | 22 +++++++++----------- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/poll.rs b/src/poll.rs index 6f227fee9e..9181bf7f30 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -1,5 +1,5 @@ //! Wait for events to trigger on specific file descriptors -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd}; use crate::errno::Errno; use crate::Result; @@ -14,20 +14,36 @@ use crate::Result; /// retrieved by calling [`revents()`](#method.revents) on the `PollFd`. #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct PollFd { +pub struct PollFd<'fd> { pollfd: libc::pollfd, + _fd: std::marker::PhantomData>, } -impl PollFd { +impl<'fd> PollFd<'fd> { /// Creates a new `PollFd` specifying the events of interest /// for a given file descriptor. - pub const fn new(fd: RawFd, events: PollFlags) -> PollFd { + // + // Different from other I/O-safe interfaces, here, we have to take `AsFd` + // by reference to prevent the case where the `fd` is closed but it is + // still in use. For example: + // + // ```rust + // let (reader, _) = pipe().unwrap(); + // + // // If `PollFd::new()` takes `AsFd` by value, then `reader` will be consumed, + // // but the file descriptor of `reader` will still be in use. + // let pollfd = PollFd::new(reader, flag); + // + // // Do something with `pollfd`, which uses the CLOSED fd. + // ``` + pub fn new(fd: &'fd Fd, events: PollFlags) -> PollFd<'fd> { PollFd { pollfd: libc::pollfd { - fd, + fd: fd.as_fd().as_raw_fd(), events: events.bits(), revents: PollFlags::empty().bits(), }, + _fd: std::marker::PhantomData, } } @@ -68,9 +84,29 @@ impl PollFd { } } -impl AsRawFd for PollFd { - fn as_raw_fd(&self) -> RawFd { - self.pollfd.fd +impl<'fd> AsFd for PollFd<'fd> { + fn as_fd(&self) -> BorrowedFd<'_> { + // Safety: + // + // BorrowedFd::borrow_raw(RawFd) requires that the raw fd being passed + // must remain open for the duration of the returned BorrowedFd, this is + // guaranteed as the returned BorrowedFd has the lifetime parameter same + // as `self`: + // "fn as_fd<'self>(&'self self) -> BorrowedFd<'self>" + // which means that `self` (PollFd) is guaranteed to outlive the returned + // BorrowedFd. (Lifetime: PollFd > BorrowedFd) + // + // And the lifetime parameter of PollFd::new(fd, ...) ensures that `fd` + // (an owned file descriptor) must outlive the returned PollFd: + // "pub fn new(fd: &'fd Fd, events: PollFlags) -> PollFd<'fd>" + // (Lifetime: Owned fd > PollFd) + // + // With two above relationships, we can conclude that the `Owned file + // descriptor` will outlive the returned BorrowedFd, + // (Lifetime: Owned fd > BorrowedFd) + // i.e., the raw fd being passed will remain valid for the lifetime of + // the returned BorrowedFd. + unsafe { BorrowedFd::borrow_raw(self.pollfd.fd) } } } diff --git a/test/test_poll.rs b/test/test_poll.rs index 53964e26bb..045ccd3df1 100644 --- a/test/test_poll.rs +++ b/test/test_poll.rs @@ -1,8 +1,9 @@ use nix::{ errno::Errno, poll::{poll, PollFd, PollFlags}, - unistd::{pipe, write}, + unistd::{close, pipe, write}, }; +use std::os::unix::io::{BorrowedFd, FromRawFd, OwnedFd}; macro_rules! loop_while_eintr { ($poll_expr: expr) => { @@ -19,7 +20,8 @@ macro_rules! loop_while_eintr { #[test] fn test_poll() { let (r, w) = pipe().unwrap(); - let mut fds = [PollFd::new(r, PollFlags::POLLIN)]; + let r = unsafe { OwnedFd::from_raw_fd(r) }; + let mut fds = [PollFd::new(&r, PollFlags::POLLIN)]; // Poll an idle pipe. Should timeout let nfds = loop_while_eintr!(poll(&mut fds, 100)); @@ -32,6 +34,7 @@ fn test_poll() { let nfds = poll(&mut fds, 100).unwrap(); assert_eq!(nfds, 1); assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); + close(w).unwrap(); } // ppoll(2) is the same as poll except for how it handles timeouts and signals. @@ -51,7 +54,8 @@ fn test_ppoll() { let timeout = TimeSpec::milliseconds(1); let (r, w) = pipe().unwrap(); - let mut fds = [PollFd::new(r, PollFlags::POLLIN)]; + let r = unsafe { OwnedFd::from_raw_fd(r) }; + let mut fds = [PollFd::new(&r, PollFlags::POLLIN)]; // Poll an idle pipe. Should timeout let sigset = SigSet::empty(); @@ -65,19 +69,13 @@ fn test_ppoll() { let nfds = ppoll(&mut fds, Some(timeout), None).unwrap(); assert_eq!(nfds, 1); assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN)); -} - -#[test] -fn test_pollfd_fd() { - use std::os::unix::io::AsRawFd; - - let pfd = PollFd::new(0x1234, PollFlags::empty()); - assert_eq!(pfd.as_raw_fd(), 0x1234); + close(w).unwrap(); } #[test] fn test_pollfd_events() { - let mut pfd = PollFd::new(-1, PollFlags::POLLIN); + let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; + let mut pfd = PollFd::new(&fd_zero, PollFlags::POLLIN); assert_eq!(pfd.events(), PollFlags::POLLIN); pfd.set_events(PollFlags::POLLOUT); assert_eq!(pfd.events(), PollFlags::POLLOUT); From 2be852de8e5ccb4ec6933836d7d76fa6bde62763 Mon Sep 17 00:00:00 2001 From: Steve Lau Date: Mon, 12 Dec 2022 14:18:49 +0800 Subject: [PATCH 259/358] feat: I/O safety for 'sys/select' --- src/sys/select.rs | 313 ++++++++++++++++++++++++++-------------- test/sys/test_select.rs | 31 ++-- 2 files changed, 222 insertions(+), 122 deletions(-) diff --git a/src/sys/select.rs b/src/sys/select.rs index 7a94cff87e..0e2193b130 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -7,7 +7,7 @@ use std::convert::TryFrom; use std::iter::FusedIterator; use std::mem; use std::ops::Range; -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; use std::ptr::{null, null_mut}; pub use libc::FD_SETSIZE; @@ -15,7 +15,10 @@ 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); +pub struct FdSet<'fd> { + set: libc::fd_set, + _fd: std::marker::PhantomData>, +} fn assert_fd_valid(fd: RawFd) { assert!( @@ -24,37 +27,40 @@ fn assert_fd_valid(fd: RawFd) { ); } -impl FdSet { +impl<'fd> FdSet<'fd> { /// Create an empty `FdSet` - pub fn new() -> FdSet { + pub fn new() -> FdSet<'fd> { let mut fdset = mem::MaybeUninit::uninit(); unsafe { libc::FD_ZERO(fdset.as_mut_ptr()); - FdSet(fdset.assume_init()) + Self { + set: fdset.assume_init(), + _fd: std::marker::PhantomData, + } } } /// Add a file descriptor to an `FdSet` - pub fn insert(&mut self, fd: RawFd) { - assert_fd_valid(fd); - unsafe { libc::FD_SET(fd, &mut self.0) }; + pub fn insert(&mut self, fd: &'fd Fd) { + assert_fd_valid(fd.as_fd().as_raw_fd()); + unsafe { libc::FD_SET(fd.as_fd().as_raw_fd(), &mut self.set) }; } /// Remove a file descriptor from an `FdSet` - pub fn remove(&mut self, fd: RawFd) { - assert_fd_valid(fd); - unsafe { libc::FD_CLR(fd, &mut self.0) }; + pub fn remove(&mut self, fd: &'fd Fd) { + assert_fd_valid(fd.as_fd().as_raw_fd()); + unsafe { libc::FD_CLR(fd.as_fd().as_raw_fd(), &mut self.set) }; } /// Test an `FdSet` for the presence of a certain file descriptor. - pub fn contains(&self, fd: RawFd) -> bool { - assert_fd_valid(fd); - unsafe { libc::FD_ISSET(fd, &self.0) } + pub fn contains(&self, fd: &'fd Fd) -> bool { + assert_fd_valid(fd.as_fd().as_raw_fd()); + unsafe { libc::FD_ISSET(fd.as_fd().as_raw_fd(), &self.set) } } /// Remove all file descriptors from this `FdSet`. pub fn clear(&mut self) { - unsafe { libc::FD_ZERO(&mut self.0) }; + unsafe { libc::FD_ZERO(&mut self.set) }; } /// Finds the highest file descriptor in the set. @@ -66,15 +72,18 @@ impl FdSet { /// # Example /// /// ``` + /// # use std::os::unix::io::{AsRawFd, BorrowedFd}; /// # use nix::sys::select::FdSet; + /// let fd_four = unsafe {BorrowedFd::borrow_raw(4)}; + /// let fd_nine = unsafe {BorrowedFd::borrow_raw(9)}; /// let mut set = FdSet::new(); - /// set.insert(4); - /// set.insert(9); - /// assert_eq!(set.highest(), Some(9)); + /// set.insert(&fd_four); + /// set.insert(&fd_nine); + /// assert_eq!(set.highest().map(|borrowed_fd|borrowed_fd.as_raw_fd()), Some(9)); /// ``` /// /// [`select`]: fn.select.html - pub fn highest(&self) -> Option { + pub fn highest(&self) -> Option> { self.fds(None).next_back() } @@ -88,11 +97,13 @@ impl FdSet { /// /// ``` /// # use nix::sys::select::FdSet; - /// # use std::os::unix::io::RawFd; + /// # use std::os::unix::io::{AsRawFd, BorrowedFd, RawFd}; /// let mut set = FdSet::new(); - /// set.insert(4); - /// set.insert(9); - /// let fds: Vec = set.fds(None).collect(); + /// let fd_four = unsafe {BorrowedFd::borrow_raw(4)}; + /// let fd_nine = unsafe {BorrowedFd::borrow_raw(9)}; + /// set.insert(&fd_four); + /// set.insert(&fd_nine); + /// let fds: Vec = set.fds(None).map(|borrowed_fd|borrowed_fd.as_raw_fd()).collect(); /// assert_eq!(fds, vec![4, 9]); /// ``` #[inline] @@ -104,7 +115,7 @@ impl FdSet { } } -impl Default for FdSet { +impl<'fd> Default for FdSet<'fd> { fn default() -> Self { Self::new() } @@ -112,18 +123,19 @@ impl Default for FdSet { /// Iterator over `FdSet`. #[derive(Debug)] -pub struct Fds<'a> { - set: &'a FdSet, +pub struct Fds<'a, 'fd> { + set: &'a FdSet<'fd>, range: Range, } -impl<'a> Iterator for Fds<'a> { - type Item = RawFd; +impl<'a, 'fd> Iterator for Fds<'a, 'fd> { + type Item = BorrowedFd<'fd>; - fn next(&mut self) -> Option { + fn next(&mut self) -> Option { for i in &mut self.range { - if self.set.contains(i as RawFd) { - return Some(i as RawFd); + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + if self.set.contains(&borrowed_i) { + return Some(borrowed_i); } } None @@ -136,19 +148,20 @@ impl<'a> Iterator for Fds<'a> { } } -impl<'a> DoubleEndedIterator for Fds<'a> { +impl<'a, 'fd> DoubleEndedIterator for Fds<'a, 'fd> { #[inline] - fn next_back(&mut self) -> Option { + fn next_back(&mut self) -> Option> { while let Some(i) = self.range.next_back() { - if self.set.contains(i as RawFd) { - return Some(i as RawFd); + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + if self.set.contains(&borrowed_i) { + return Some(borrowed_i); } } None } } -impl<'a> FusedIterator for Fds<'a> {} +impl<'a, 'fd> FusedIterator for Fds<'a, 'fd> {} /// Monitors file descriptors for readiness /// @@ -173,7 +186,7 @@ impl<'a> FusedIterator for Fds<'a> {} /// [select(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html) /// /// [`FdSet::highest`]: struct.FdSet.html#method.highest -pub fn select<'a, N, R, W, E, T>( +pub fn select<'a, 'fd, N, R, W, E, T>( nfds: N, readfds: R, writefds: W, @@ -181,10 +194,11 @@ pub fn select<'a, N, R, W, E, T>( timeout: T, ) -> Result where + 'fd: 'a, N: Into>, - R: Into>, - W: Into>, - E: Into>, + R: Into>>, + W: Into>>, + E: Into>>, T: Into>, { let mut readfds = readfds.into(); @@ -197,7 +211,11 @@ where .iter_mut() .chain(writefds.iter_mut()) .chain(errorfds.iter_mut()) - .map(|set| set.highest().unwrap_or(-1)) + .map(|set| { + set.highest() + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .unwrap_or(-1) + }) .max() .unwrap_or(-1) + 1 @@ -256,17 +274,18 @@ use crate::sys::signal::SigSet; /// [The new pselect() system call](https://lwn.net/Articles/176911/) /// /// [`FdSet::highest`]: struct.FdSet.html#method.highest -pub fn pselect<'a, N, R, W, E, T, S>(nfds: N, +pub fn pselect<'a, 'fd, N, R, W, E, T, S>(nfds: N, readfds: R, writefds: W, errorfds: E, timeout: T, sigmask: S) -> Result where + 'fd: 'a, N: Into>, - R: Into>, - W: Into>, - E: Into>, + R: Into>>, + W: Into>>, + E: Into>>, T: Into>, S: Into>, { @@ -280,7 +299,7 @@ where readfds.iter_mut() .chain(writefds.iter_mut()) .chain(errorfds.iter_mut()) - .map(|set| set.highest().unwrap_or(-1)) + .map(|set| set.highest().map(|borrowed_fd|borrowed_fd.as_raw_fd()).unwrap_or(-1)) .max() .unwrap_or(-1) + 1 }); @@ -303,20 +322,22 @@ where mod tests { use super::*; use crate::sys::time::{TimeVal, TimeValLike}; - use crate::unistd::{pipe, write}; - use std::os::unix::io::RawFd; + use crate::unistd::{close, pipe, write}; + use std::os::unix::io::{FromRawFd, OwnedFd, RawFd}; #[test] fn fdset_insert() { let mut fd_set = FdSet::new(); for i in 0..FD_SETSIZE { - assert!(!fd_set.contains(i as RawFd)); + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + assert!(!fd_set.contains(&borrowed_i)); } - fd_set.insert(7); + let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; + fd_set.insert(&fd_seven); - assert!(fd_set.contains(7)); + assert!(fd_set.contains(&fd_seven)); } #[test] @@ -324,107 +345,183 @@ mod tests { let mut fd_set = FdSet::new(); for i in 0..FD_SETSIZE { - assert!(!fd_set.contains(i as RawFd)); + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + assert!(!fd_set.contains(&borrowed_i)); } - fd_set.insert(7); - fd_set.remove(7); + let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; + fd_set.insert(&fd_seven); + fd_set.remove(&fd_seven); for i in 0..FD_SETSIZE { - assert!(!fd_set.contains(i as RawFd)); + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + assert!(!fd_set.contains(&borrowed_i)); } } #[test] + #[allow(non_snake_case)] fn fdset_clear() { let mut fd_set = FdSet::new(); - fd_set.insert(1); - fd_set.insert((FD_SETSIZE / 2) as RawFd); - fd_set.insert((FD_SETSIZE - 1) as RawFd); + let fd_one = unsafe { BorrowedFd::borrow_raw(1) }; + let fd_FD_SETSIZE_devided_by_two = + unsafe { BorrowedFd::borrow_raw((FD_SETSIZE / 2) as RawFd) }; + let fd_FD_SETSIZE_minus_one = + unsafe { BorrowedFd::borrow_raw((FD_SETSIZE - 1) as RawFd) }; + fd_set.insert(&fd_one); + fd_set.insert(&fd_FD_SETSIZE_devided_by_two); + fd_set.insert(&fd_FD_SETSIZE_minus_one); fd_set.clear(); for i in 0..FD_SETSIZE { - assert!(!fd_set.contains(i as RawFd)); + let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) }; + assert!(!fd_set.contains(&borrowed_i)); } } #[test] fn fdset_highest() { let mut set = FdSet::new(); - assert_eq!(set.highest(), None); - set.insert(0); - assert_eq!(set.highest(), Some(0)); - set.insert(90); - assert_eq!(set.highest(), Some(90)); - set.remove(0); - assert_eq!(set.highest(), Some(90)); - set.remove(90); - assert_eq!(set.highest(), None); - - set.insert(4); - set.insert(5); - set.insert(7); - assert_eq!(set.highest(), Some(7)); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + None + ); + let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; + let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) }; + set.insert(&fd_zero); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + Some(0) + ); + set.insert(&fd_ninety); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + Some(90) + ); + set.remove(&fd_zero); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + Some(90) + ); + set.remove(&fd_ninety); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + None + ); + + let fd_four = unsafe { BorrowedFd::borrow_raw(4) }; + let fd_five = unsafe { BorrowedFd::borrow_raw(5) }; + let fd_seven = unsafe { BorrowedFd::borrow_raw(7) }; + set.insert(&fd_four); + set.insert(&fd_five); + set.insert(&fd_seven); + assert_eq!( + set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()), + Some(7) + ); } #[test] fn fdset_fds() { let mut set = FdSet::new(); - assert_eq!(set.fds(None).collect::>(), vec![]); - set.insert(0); - assert_eq!(set.fds(None).collect::>(), vec![0]); - set.insert(90); - assert_eq!(set.fds(None).collect::>(), vec![0, 90]); + let fd_zero = unsafe { BorrowedFd::borrow_raw(0) }; + let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) }; + assert_eq!( + set.fds(None) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::>(), + vec![] + ); + set.insert(&fd_zero); + assert_eq!( + set.fds(None) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::>(), + vec![0] + ); + set.insert(&fd_ninety); + assert_eq!( + set.fds(None) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::>(), + vec![0, 90] + ); // highest limit - assert_eq!(set.fds(Some(89)).collect::>(), vec![0]); - assert_eq!(set.fds(Some(90)).collect::>(), vec![0, 90]); + assert_eq!( + set.fds(Some(89)) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::>(), + vec![0] + ); + assert_eq!( + set.fds(Some(90)) + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .collect::>(), + vec![0, 90] + ); } #[test] fn test_select() { let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); + let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; + let w1 = unsafe { OwnedFd::from_raw_fd(w1) }; let (r2, _w2) = pipe().unwrap(); + let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; + write(w1.as_raw_fd(), b"hi!").unwrap(); let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); + fd_set.insert(&r1); + fd_set.insert(&r2); let mut timeout = TimeVal::seconds(10); assert_eq!( 1, select(None, &mut fd_set, None, None, &mut timeout).unwrap() ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); + assert!(fd_set.contains(&r1)); + assert!(!fd_set.contains(&r2)); + close(_w2).unwrap(); } #[test] fn test_select_nfds() { let (r1, w1) = pipe().unwrap(); - write(w1, b"hi!").unwrap(); let (r2, _w2) = pipe().unwrap(); + let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; + let w1 = unsafe { OwnedFd::from_raw_fd(w1) }; + let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; + write(w1.as_raw_fd(), b"hi!").unwrap(); let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); + fd_set.insert(&r1); + fd_set.insert(&r2); let mut timeout = TimeVal::seconds(10); - assert_eq!( - 1, - select( - Some(fd_set.highest().unwrap() + 1), - &mut fd_set, - None, - None, - &mut timeout - ) - .unwrap() - ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); + { + assert_eq!( + 1, + select( + Some( + fd_set + .highest() + .map(|borrowed_fd| borrowed_fd.as_raw_fd()) + .unwrap() + + 1 + ), + &mut fd_set, + None, + None, + &mut timeout + ) + .unwrap() + ); + } + assert!(fd_set.contains(&r1)); + assert!(!fd_set.contains(&r2)); + close(_w2).unwrap(); } #[test] @@ -432,16 +529,17 @@ mod tests { let (r1, w1) = pipe().unwrap(); write(w1, b"hi!").unwrap(); let (r2, _w2) = pipe().unwrap(); - + let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; + let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); + fd_set.insert(&r1); + fd_set.insert(&r2); let mut timeout = TimeVal::seconds(10); assert_eq!( 1, select( - ::std::cmp::max(r1, r2) + 1, + std::cmp::max(r1.as_raw_fd(), r2.as_raw_fd()) + 1, &mut fd_set, None, None, @@ -449,7 +547,8 @@ mod tests { ) .unwrap() ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); + assert!(fd_set.contains(&r1)); + assert!(!fd_set.contains(&r2)); + close(_w2).unwrap(); } } diff --git a/test/sys/test_select.rs b/test/sys/test_select.rs index 40bda4d90a..79f75de3b4 100644 --- a/test/sys/test_select.rs +++ b/test/sys/test_select.rs @@ -2,6 +2,7 @@ use nix::sys::select::*; use nix::sys::signal::SigSet; use nix::sys::time::{TimeSpec, TimeValLike}; use nix::unistd::{pipe, write}; +use std::os::unix::io::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd}; #[test] pub fn test_pselect() { @@ -9,11 +10,13 @@ pub fn test_pselect() { let (r1, w1) = pipe().unwrap(); write(w1, b"hi!").unwrap(); + let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; let (r2, _w2) = pipe().unwrap(); + let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); + fd_set.insert(&r1); + fd_set.insert(&r2); let timeout = TimeSpec::seconds(10); let sigmask = SigSet::empty(); @@ -21,25 +24,27 @@ pub fn test_pselect() { 1, pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap() ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); + assert!(fd_set.contains(&r1)); + assert!(!fd_set.contains(&r2)); } #[test] pub fn test_pselect_nfds2() { let (r1, w1) = pipe().unwrap(); write(w1, b"hi!").unwrap(); + let r1 = unsafe { OwnedFd::from_raw_fd(r1) }; let (r2, _w2) = pipe().unwrap(); + let r2 = unsafe { OwnedFd::from_raw_fd(r2) }; let mut fd_set = FdSet::new(); - fd_set.insert(r1); - fd_set.insert(r2); + fd_set.insert(&r1); + fd_set.insert(&r2); let timeout = TimeSpec::seconds(10); assert_eq!( 1, pselect( - ::std::cmp::max(r1, r2) + 1, + std::cmp::max(r1.as_raw_fd(), r2.as_raw_fd()) + 1, &mut fd_set, None, None, @@ -48,8 +53,8 @@ pub fn test_pselect_nfds2() { ) .unwrap() ); - assert!(fd_set.contains(r1)); - assert!(!fd_set.contains(r2)); + assert!(fd_set.contains(&r1)); + assert!(!fd_set.contains(&r2)); } macro_rules! generate_fdset_bad_fd_tests { @@ -58,17 +63,13 @@ macro_rules! generate_fdset_bad_fd_tests { #[test] #[should_panic] fn $method() { - FdSet::new().$method($fd); + let bad_fd = unsafe{BorrowedFd::borrow_raw($fd)}; + FdSet::new().$method(&bad_fd); } )* } } -mod test_fdset_negative_fd { - use super::*; - generate_fdset_bad_fd_tests!(-1, insert, remove, contains); -} - mod test_fdset_too_large_fd { use super::*; use std::convert::TryInto; From 4871c1ae1f19353b57303e4b2ff164337a3dc1fd Mon Sep 17 00:00:00 2001 From: fpagliughi Date: Sun, 4 Dec 2022 19:55:40 -0500 Subject: [PATCH 260/358] Added CANbus socket family protocol constants. --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3597db8fd9..8ff4176c87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1867](https://github.com/nix-rust/nix/pull/1867)) - Added `nix::ucontext` module on `aarch64-unknown-linux-gnu`. (#[1662](https://github.com/nix-rust/nix/pull/1662)) +- Added `CanRaw` to `SockProtocol` and `CanBcm` as a separate `SocProtocol` constant. + ([#1912](https://github.com/nix-rust/nix/pull/1912)) ### Changed diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index a67a5ab34a..bcc28ae619 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -218,8 +218,21 @@ pub enum SockProtocol { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] EthAll = libc::ETH_P_ALL.to_be(), + /// The Controller Area Network raw socket protocol + /// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan)) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + CanRaw = libc::CAN_RAW, } +impl SockProtocol { + /// The Controller Area Network broadcast manager protocol + /// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan)) + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(non_upper_case_globals)] + pub const CanBcm: SockProtocol = SockProtocol::NetlinkUserSock; // Matches libc::CAN_BCM +} #[cfg(any(target_os = "linux"))] libc_bitflags! { /// Configuration flags for `SO_TIMESTAMPING` interface From 4d31ecf06be0d689d013f0c3f45d17fdac6709d4 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Tue, 13 Dec 2022 14:26:59 +0100 Subject: [PATCH 261/358] Rework vsock test We mainly provide VsockAddr, so let's try to test well that VsockAddr mapping to libc::sockaddr_vm is correct. Let's remove all interactions with the socket, since vsock may or may not be available in the environment. Testing socket(), bind(), listen(), connect(), etc. caused unexpected failures, and it's out of scope of this crate. So let's simplify the vsock test focussing on VsockAddr. This should work also on graviton, so let's try to re-enable it. Fixes #1934 Signed-off-by: Stefano Garzarella --- .cirrus.yml | 1 - test/sys/test_socket.rs | 68 ++++++++++++++++------------------------- 2 files changed, 27 insertions(+), 42 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 213696724e..1ffe4611f4 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -142,7 +142,6 @@ task: arm_container: image: rust:1.63.0 env: - RUSTFLAGS: --cfg graviton -D warnings TARGET: aarch64-unknown-linux-gnu - name: Linux x86_64 container: diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 2ab6c54f6e..0a8d0544cb 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -2040,57 +2040,43 @@ 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 nix::errno::Errno; - use nix::sys::socket::{ - bind, connect, listen, socket, AddressFamily, SockFlag, SockType, - VsockAddr, - }; - use nix::unistd::close; - use std::thread; + use nix::sys::socket::SockaddrLike; + use nix::sys::socket::{AddressFamily, VsockAddr}; + use std::mem; let port: u32 = 3000; - let s1 = socket( - AddressFamily::Vsock, - SockType::Stream, - SockFlag::empty(), - None, - ) - .expect("socket failed"); + let addr_local = VsockAddr::new(libc::VMADDR_CID_LOCAL, port); + assert_eq!(addr_local.cid(), libc::VMADDR_CID_LOCAL); + assert_eq!(addr_local.port(), port); - // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error. - let sockaddr_hv = VsockAddr::new(libc::VMADDR_CID_HYPERVISOR, port); - assert_eq!(bind(s1, &sockaddr_hv).err(), Some(Errno::EADDRNOTAVAIL)); + let addr_any = VsockAddr::new(libc::VMADDR_CID_ANY, libc::VMADDR_PORT_ANY); + assert_eq!(addr_any.cid(), libc::VMADDR_CID_ANY); + assert_eq!(addr_any.port(), libc::VMADDR_PORT_ANY); - let sockaddr_any = VsockAddr::new(libc::VMADDR_CID_ANY, port); - assert_eq!(bind(s1, &sockaddr_any), Ok(())); - listen(s1, 10).expect("listen failed"); + assert_ne!(addr_local, addr_any); + assert_ne!(calculate_hash(&addr_local), calculate_hash(&addr_any)); - let thr = thread::spawn(move || { - let cid: u32 = libc::VMADDR_CID_HOST; + let addr1 = VsockAddr::new(libc::VMADDR_CID_HOST, port); + let addr2 = VsockAddr::new(libc::VMADDR_CID_HOST, port); + assert_eq!(addr1, addr2); + assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); - let s2 = socket( - AddressFamily::Vsock, - SockType::Stream, - SockFlag::empty(), - None, + let addr3 = unsafe { + VsockAddr::from_raw( + addr2.as_ref() as *const libc::sockaddr_vm as *const libc::sockaddr, + Some(mem::size_of::().try_into().unwrap()), ) - .expect("socket failed"); - - let sockaddr_host = VsockAddr::new(cid, port); - - // The current implementation does not support loopback devices, so, - // for now, we expect a failure on the connect. - assert_ne!(connect(s2, &sockaddr_host), Ok(())); - - close(s2).unwrap(); - }); - - close(s1).unwrap(); - thr.join().unwrap(); + } + .unwrap(); + assert_eq!( + addr3.as_ref().svm_family, + AddressFamily::Vsock as libc::sa_family_t + ); + assert_eq!(addr3.as_ref().svm_cid, addr1.cid()); + assert_eq!(addr3.as_ref().svm_port, addr1.port()); } // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack From 2e0f533079ec479ff62abb42f275924a14eb037f Mon Sep 17 00:00:00 2001 From: Xiaobo Liu Date: Sun, 25 Dec 2022 10:07:17 +0800 Subject: [PATCH 262/358] fix: linux+mips+uclibc unreachable pattern Signed-off-by: Xiaobo Liu --- src/sys/signal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index baa5d79d54..efa35ebfd2 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -1066,7 +1066,7 @@ mod sigevent { SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))] SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, - #[cfg(all(target_os = "linux", target_env = "uclibc"))] + #[cfg(all(target_os = "linux", target_env = "uclibc", not(target_arch = "mips")))] SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))] SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined From 4994723da59c3656e25b2efdf699b5e0bbcc0adb Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sat, 31 Dec 2022 23:16:46 +0000 Subject: [PATCH 263/358] fix: clippy::size_of_ref --- src/sys/socket/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index bcc28ae619..00c905608a 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1292,7 +1292,7 @@ impl<'a> ControlMessage<'a> { } #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::AlgSetIv(iv) => { - mem::size_of_val(&iv) + iv.len() + mem::size_of::<&[u8]>() + iv.len() }, #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::AlgSetOp(op) => { From b7f8f93489417661f363e0b25601b408877d8274 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sun, 8 Jan 2023 18:09:55 +0000 Subject: [PATCH 264/358] feat: I/O safety `ftruncate` --- src/unistd.rs | 5 +++-- test/test_unistd.rs | 13 +++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index ae1cca9542..8cad67f4a4 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -35,6 +35,7 @@ use std::ffi::{CString, OsStr}; use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStringExt; use std::os::unix::io::RawFd; +use std::os::unix::io::{AsFd, AsRawFd}; use std::path::PathBuf; use std::{fmt, mem, ptr}; @@ -1255,8 +1256,8 @@ pub fn truncate(path: &P, len: off_t) -> Result<()> { /// /// See also /// [ftruncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html) -pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> { - Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop) +pub fn ftruncate(fd: Fd, len: off_t) -> Result<()> { + Errno::result(unsafe { libc::ftruncate(fd.as_fd().as_raw_fd(), len) }).map(drop) } pub fn isatty(fd: RawFd) -> Result { diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 1d50c5fa48..10284e4127 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -772,15 +772,12 @@ fn test_ftruncate() { let tempdir = tempdir().unwrap(); let path = tempdir.path().join("file"); - let tmpfd = { - let mut tmp = File::create(&path).unwrap(); - const CONTENTS: &[u8] = b"12345678"; - tmp.write_all(CONTENTS).unwrap(); - tmp.into_raw_fd() - }; + let mut file = File::create(&path).unwrap(); + const CONTENTS: &[u8] = b"12345678"; + file.write_all(CONTENTS).unwrap(); - ftruncate(tmpfd, 2).unwrap(); - close(tmpfd).unwrap(); + ftruncate(&file, 2).unwrap(); + drop(file); let metadata = fs::metadata(&path).unwrap(); assert_eq!(2, metadata.len()); From dbd5d1b4617e6832efc7a9927e30813f69f78f30 Mon Sep 17 00:00:00 2001 From: Jonathan Woollett-Light Date: Mon, 19 Dec 2022 17:18:58 +0000 Subject: [PATCH 265/358] docs: Target table --- README.md | 93 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 97ca145f1a..72f7486d2e 100644 --- a/README.md +++ b/README.md @@ -46,46 +46,59 @@ limitations. Support for platforms is split into three tiers: The following targets are supported by `nix`: -Tier 1: - * aarch64-apple-darwin - * aarch64-unknown-linux-gnu - * arm-unknown-linux-gnueabi - * armv7-unknown-linux-gnueabihf - * i686-unknown-freebsd - * i686-unknown-linux-gnu - * i686-unknown-linux-musl - * mips-unknown-linux-gnu - * mips64-unknown-linux-gnuabi64 - * mips64el-unknown-linux-gnuabi64 - * mipsel-unknown-linux-gnu - * powerpc64le-unknown-linux-gnu - * x86_64-unknown-freebsd - * x86_64-unknown-linux-gnu - * x86_64-unknown-linux-musl - -Tier 2: - * aarch64-apple-ios - * aarch64-linux-android - * arm-linux-androideabi - * arm-unknown-linux-musleabi - * armv7-linux-androideabi - * i686-linux-android - * powerpc-unknown-linux-gnu - * s390x-unknown-linux-gnu - * x86_64-apple-ios - * x86_64-linux-android - * x86_64-apple-darwin - * x86_64-unknown-illumos - * x86_64-unknown-netbsd - -Tier 3: - * armv7-unknown-linux-uclibceabihf - * x86_64-fuchsia - * x86_64-unknown-dragonfly - * x86_64-unknown-haiku - * x86_64-unknown-linux-gnux32 - * x86_64-unknown-openbsd - * x86_64-unknown-redox + + + + + + + + + + + +
Tier 1Tier 2Tier 3
+
    +
  • aarch64-apple-darwin
  • +
  • aarch64-unknown-linux-gnu
  • +
  • arm-unknown-linux-gnueabi
  • +
  • armv7-unknown-linux-gnueabihf
  • +
  • i686-unknown-freebsd
  • +
  • i686-unknown-linux-gnu
  • +
  • i686-unknown-linux-musl
  • +
  • mips-unknown-linux-gnu
  • +
  • mips64-unknown-linux-gnuabi64
  • +
  • mips64el-unknown-linux-gnuabi64
  • +
  • mipsel-unknown-linux-gnu
  • +
  • powerpc64le-unknown-linux-gnu
  • +
  • x86_64-unknown-freebsd
  • +
  • x86_64-unknown-linux-gnu
  • +
  • x86_64-unknown-linux-musl
  • +
+
+
    +
  • aarch64-apple-ios
  • +
  • aarch64-linux-android
  • +
  • arm-linux-androideabi
  • +
  • arm-unknown-linux-musleabi
  • +
  • armv7-linux-androideabi
  • +
  • i686-linux-android
  • +
  • powerpc-unknown-linux-gnu
  • +
  • s390x-unknown-linux-gnu
  • +
  • x86_64-apple-ios
  • +
  • x86_64-linux-android
  • +
  • x86_64-apple-darwin
  • +
  • x86_64-unknown-illumos
  • +
  • x86_64-unknown-netbsd
  • +
+
  • armv7-unknown-linux-uclibceabihf
  • +
  • x86_64-fuchsia
  • +
  • x86_64-unknown-dragonfly
  • +
  • x86_64-unknown-haiku
  • +
  • x86_64-unknown-linux-gnux32
  • +
  • x86_64-unknown-openbsd
  • +
  • x86_64-unknown-redox
  • +
    ## Minimum Supported Rust Version (MSRV) From 708a3c2b345502503e437ae3122e667d15a64c60 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Mon, 9 Jan 2023 01:34:16 +0000 Subject: [PATCH 266/358] fix: Update libc To include fix https://github.com/rust-lang/libc/commit/44cc30c6b68427d3628926868758d35fe561bbe6. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e0cfac14f7..18eae53589 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { git = "https://github.com/rust-lang/libc", rev = "15d27952bfa93e5e4f419c603f275486f15a050c", features = [ "extra_traits" ] } +libc = { git = "https://github.com/rust-lang/libc", rev = "44cc30c6b68427d3628926868758d35fe561bbe6", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } From 33643eff5a3b7c44c54330141d6ed71c8739fde4 Mon Sep 17 00:00:00 2001 From: David Collard Date: Tue, 10 Jan 2023 20:32:23 -0500 Subject: [PATCH 267/358] Added `mq_timedreceive` to `::nix::mqueue`. --- CHANGELOG.md | 2 ++ src/mqueue.rs | 26 ++++++++++++++++++++++++++ test/test_mq.rs | 37 ++++++++++++++++++++++++++++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ff4176c87..9fb4b2932b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1662](https://github.com/nix-rust/nix/pull/1662)) - Added `CanRaw` to `SockProtocol` and `CanBcm` as a separate `SocProtocol` constant. ([#1912](https://github.com/nix-rust/nix/pull/1912)) +- Added `mq_timedreceive` to `::nix::mqueue`. + ([#1966])(https://github.com/nix-rust/nix/pull/1966) ### Changed diff --git a/src/mqueue.rs b/src/mqueue.rs index 33599bf91d..ac183eb55a 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -197,6 +197,32 @@ pub fn mq_receive( Errno::result(res).map(|r| r as usize) } +feature! { + #![feature = "time"] + use crate::sys::time::TimeSpec; + /// Receive a message from a message queue with a timeout + /// + /// See also ['mq_timedreceive(2)'](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html) + pub fn mq_timedreceive( + mqdes: &MqdT, + message: &mut [u8], + msg_prio: &mut u32, + abstime: &TimeSpec, + ) -> Result { + let len = message.len() as size_t; + let res = unsafe { + libc::mq_timedreceive( + mqdes.0, + message.as_mut_ptr() as *mut c_char, + len, + msg_prio as *mut u32, + abstime.as_ref(), + ) + }; + Errno::result(res).map(|r| r as usize) + } +} + /// Send a message to a message queue /// /// See also [`mq_send(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html) diff --git a/test/test_mq.rs b/test/test_mq.rs index 7b48e7ac78..f232434e12 100644 --- a/test/test_mq.rs +++ b/test/test_mq.rs @@ -3,9 +3,13 @@ use std::ffi::CString; use std::str; use nix::errno::Errno; -use nix::mqueue::{mq_attr_member_t, mq_close, mq_open, mq_receive, mq_send}; +use nix::mqueue::{ + mq_attr_member_t, mq_close, mq_open, mq_receive, mq_send, mq_timedreceive, +}; use nix::mqueue::{MQ_OFlag, MqAttr}; use nix::sys::stat::Mode; +use nix::sys::time::{TimeSpec, TimeValLike}; +use nix::time::{clock_gettime, ClockId}; // Defined as a macro such that the error source is reported as the caller's location. macro_rules! assert_attr_eq { @@ -55,6 +59,37 @@ fn test_mq_send_and_receive() { assert_eq!(msg_to_send, str::from_utf8(&buf[0..len]).unwrap()); } +#[test] +fn test_mq_timedreceive() { + const MSG_SIZE: mq_attr_member_t = 32; + let attr = MqAttr::new(0, 10, MSG_SIZE, 0); + let mq_name = &CString::new(b"/a_nix_test_queue".as_ref()).unwrap(); + + let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; + let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; + let r0 = mq_open(mq_name, oflag0, mode, Some(&attr)); + if let Err(Errno::ENOSYS) = r0 { + println!("message queues not supported or module not loaded?"); + return; + }; + let mqd0 = r0.unwrap(); + let msg_to_send = "msg_1"; + mq_send(&mqd0, msg_to_send.as_bytes(), 1).unwrap(); + + let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY; + let mqd1 = mq_open(mq_name, oflag1, mode, Some(&attr)).unwrap(); + let mut buf = [0u8; 32]; + let mut prio = 0u32; + let abstime = + clock_gettime(ClockId::CLOCK_REALTIME).unwrap() + TimeSpec::seconds(1); + let len = mq_timedreceive(&mqd1, &mut buf, &mut prio, &abstime).unwrap(); + assert_eq!(prio, 1); + + mq_close(mqd1).unwrap(); + mq_close(mqd0).unwrap(); + assert_eq!(msg_to_send, str::from_utf8(&buf[0..len]).unwrap()); +} + #[test] fn test_mq_getattr() { use nix::mqueue::mq_getattr; From cfe689a11e963fb07ee08bf8277cece9d9ea382a Mon Sep 17 00:00:00 2001 From: Aaron Drew Date: Tue, 10 Jan 2023 13:53:16 +1100 Subject: [PATCH 268/358] Fix endian swap on SocketAddrV6. flowinfo and scope_id should not be byte swapped. --- CHANGELOG.md | 3 +++ src/sys/socket/addr.rs | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ff4176c87..2bb1de9af7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1921](https://github.com/nix-rust/nix/pull/1921)) ### Fixed +- Fix `SockaddrIn6` bug that was swapping flowinfo and scope_id byte ordering. + ([#1964](https://github.com/nix-rust/nix/pull/1964)) + ### Removed - Removed deprecated IoVec API. diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 4e36ca4700..aad407a7f0 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1182,8 +1182,8 @@ impl From for net::SocketAddrV6 { net::SocketAddrV6::new( net::Ipv6Addr::from(addr.0.sin6_addr.s6_addr), u16::from_be(addr.0.sin6_port), - u32::from_be(addr.0.sin6_flowinfo), - u32::from_be(addr.0.sin6_scope_id), + addr.0.sin6_flowinfo, + addr.0.sin6_scope_id, ) } } @@ -2525,6 +2525,18 @@ mod tests { SockaddrIn6::size() as usize ); } + + #[test] + // Ensure that we can convert to-and-from std::net variants without change. + fn to_and_from() { + let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; + let mut nix_sin6 = SockaddrIn6::from_str(s).unwrap(); + nix_sin6.0.sin6_flowinfo = 0x12345678; + nix_sin6.0.sin6_scope_id = 0x9abcdef0; + + let std_sin6 : std::net::SocketAddrV6 = nix_sin6.into(); + assert_eq!(nix_sin6, std_sin6.into()); + } } mod sockaddr_storage { From 2c4452304ddf38b59c00acd63a451dcf1668bc79 Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Fri, 13 Jan 2023 20:57:28 -0500 Subject: [PATCH 269/358] if_nameindex: add illumos target --- src/net/if_.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/net/if_.rs b/src/net/if_.rs index b2423bc673..ec46260714 100644 --- a/src/net/if_.rs +++ b/src/net/if_.rs @@ -334,6 +334,7 @@ libc_bitflags!( target_os = "macos", target_os = "netbsd", target_os = "openbsd", + target_os = "illumos", ))] #[cfg_attr(docsrs, doc(cfg(all())))] mod if_nameindex { @@ -465,5 +466,6 @@ mod if_nameindex { target_os = "macos", target_os = "netbsd", target_os = "openbsd", + target_os = "illumos", ))] pub use if_nameindex::*; From 61bd3e2a8f0cefaef4799fd6049f264244752de6 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 11 Jan 2023 13:13:44 +0100 Subject: [PATCH 270/358] Added LOCAL_PEERPID/LocalPeerPid sockopt for macos --- src/sys/socket/sockopt.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index dd24208f31..cea623ae15 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -492,6 +492,15 @@ sockopt_impl!( libc::LOCAL_PEERCRED, super::XuCred ); +#[cfg(any(target_os = "macos"))] +sockopt_impl!( + /// Get the PID of the peer process of a connected unix domain socket. + LocalPeerPid, + GetOnly, + 0, + libc::LOCAL_PEERPID, + libc::c_int +); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!( /// Return the credentials of the foreign process connected to this socket. From 34788b179b14b5c5c8e7bb7df168089fc854c499 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sat, 14 Jan 2023 19:49:42 +0100 Subject: [PATCH 271/358] Added changelog entry and test for LocalPeerPid --- CHANGELOG.md | 1 + test/sys/test_sockopt.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7da93bbf1..68edef38df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1912](https://github.com/nix-rust/nix/pull/1912)) - Added `mq_timedreceive` to `::nix::mqueue`. ([#1966])(https://github.com/nix-rust/nix/pull/1966) +- Added `LocalPeerPid` to `nix::sys::socket::sockopt` for macOS. ([#1967](https://github.com/nix-rust/nix/pull/1967)) ### Changed diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 34bef945e1..bf791688d6 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -54,6 +54,22 @@ pub fn test_local_peercred_stream() { assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); } +#[cfg(target_os = "macos")] +#[test] +pub fn test_local_peer_pid() { + use nix::sys::socket::socketpair; + + let (fd1, _fd2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::empty(), + ) + .unwrap(); + let pid = getsockopt(fd1, sockopt::LocalPeerPid).unwrap(); + assert_eq!(pid, std::process::id() as _); +} + #[cfg(target_os = "linux")] #[test] fn is_so_mark_functional() { From 91de7e61bedd08547dcaf14f4af4ed78d7d3ddb3 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 14 Jan 2023 11:57:47 -0700 Subject: [PATCH 272/358] Document the mount.linux module Also, deprecate a few flags that should not be used by userland. --- src/mount/linux.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/mount/linux.rs b/src/mount/linux.rs index cf6a60b017..5f19a5f1f7 100644 --- a/src/mount/linux.rs +++ b/src/mount/linux.rs @@ -1,9 +1,9 @@ -#![allow(missing_docs)] use crate::errno::Errno; use crate::{NixPath, Result}; use libc::{self, c_int, c_ulong}; libc_bitflags!( + /// Used with [`mount`]. pub struct MsFlags: c_ulong { /// Mount read-only MS_RDONLY; @@ -27,36 +27,80 @@ libc_bitflags!( MS_NODIRATIME; /// Linux 2.4.0 - Bind directory at different place MS_BIND; + /// Move an existing mount to a new location MS_MOVE; + /// Used to create a recursive bind mount. MS_REC; + /// Suppress the display of certain kernel warning messages. MS_SILENT; + /// VFS does not apply the umask MS_POSIXACL; + /// The resulting mount cannot subsequently be bind mounted. MS_UNBINDABLE; + /// Make this mount point private. MS_PRIVATE; + /// If this is a shared mount point that is a member of a peer group + /// that contains other members, convert it to a slave mount. MS_SLAVE; + /// Make this mount point shared. MS_SHARED; + /// When a file on this filesystem is accessed, update the file's + /// last access time (atime) only if the current value of atime is + /// less than or equal to the file's last modification time (mtime) or + /// last status change time (ctime). MS_RELATIME; + /// Mount request came from within the kernel + #[deprecated(since = "0.27.0", note = "Should only be used in-kernel")] MS_KERNMOUNT; + /// Update inode I_version field MS_I_VERSION; + /// Always update the last access time (atime) when files on this + /// filesystem are accessed. MS_STRICTATIME; + /// Reduce on-disk updates of inode timestamps (atime, mtime, ctime) by + /// maintaining these changes only in memory. MS_LAZYTIME; + #[deprecated(since = "0.27.0", note = "Should only be used in-kernel")] + #[allow(missing_docs)] // Not documented in Linux MS_ACTIVE; + #[deprecated(since = "0.27.0", note = "Should only be used in-kernel")] + #[allow(missing_docs)] // Not documented in Linux MS_NOUSER; + #[allow(missing_docs)] // Not documented in Linux; possibly kernel-only MS_RMT_MASK; + #[allow(missing_docs)] // Not documented in Linux; possibly kernel-only MS_MGC_VAL; + #[allow(missing_docs)] // Not documented in Linux; possibly kernel-only MS_MGC_MSK; } ); libc_bitflags!( + /// Used with [`umount2]. pub struct MntFlags: c_int { + /// Attempt to unmount even if still in use, aborting pending requests. MNT_FORCE; + /// Lazy unmount. Disconnect the file system immediately, but don't + /// actually unmount it until it ceases to be busy. MNT_DETACH; + /// Mark the mount point as expired. MNT_EXPIRE; + /// Don't dereference `target` if it is a symlink. UMOUNT_NOFOLLOW; } ); +/// Mount a file system. +/// +/// # Arguments +/// - `source` - Specifies the file system. e.g. `/dev/sd0`. +/// - `target` - Specifies the destination. e.g. `/mnt`. +/// - `fstype` - The file system type, e.g. `ext4`. +/// - `flags` - Optional flags controlling the mount. +/// - `data` - Optional file system specific data. +/// +/// # See Also +/// [`mount`](https://man7.org/linux/man-pages/man2/mount.2.html) pub fn mount< P1: ?Sized + NixPath, P2: ?Sized + NixPath, @@ -99,6 +143,7 @@ pub fn mount< Errno::result(res).map(drop) } +/// Unmount the file system mounted at `target`. pub fn umount(target: &P) -> Result<()> { let res = target.with_nix_path(|cstr| unsafe { libc::umount(cstr.as_ptr()) })?; @@ -106,6 +151,9 @@ pub fn umount(target: &P) -> Result<()> { Errno::result(res).map(drop) } +/// Unmount the file system mounted at `target`. +/// +/// See also [`umount`](https://man7.org/linux/man-pages/man2/umount.2.html) pub fn umount2(target: &P, flags: MntFlags) -> Result<()> { let res = target.with_nix_path(|cstr| unsafe { libc::umount2(cstr.as_ptr(), flags.bits) From 960199daf9f395096b08dc24aa0337cb5b93da81 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 15 Jan 2023 22:41:33 +0100 Subject: [PATCH 273/358] Try enabling LocalPeerPid for ios --- src/sys/socket/sockopt.rs | 2 +- test/sys/test_sockopt.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index cea623ae15..9021664997 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -492,7 +492,7 @@ sockopt_impl!( libc::LOCAL_PEERCRED, super::XuCred ); -#[cfg(any(target_os = "macos"))] +#[cfg(any(target_os = "macos", target_os = "ios"))] sockopt_impl!( /// Get the PID of the peer process of a connected unix domain socket. LocalPeerPid, diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index bf791688d6..a498bdfa2c 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -54,7 +54,7 @@ pub fn test_local_peercred_stream() { assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); } -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "ios", target_os = "macos"))] #[test] pub fn test_local_peer_pid() { use nix::sys::socket::socketpair; From 5f7bebf9a575d19368db064d0c9f73732d9f1464 Mon Sep 17 00:00:00 2001 From: "Alexis (Poliorcetics) Bourget" Date: Mon, 23 Jan 2023 16:26:56 +0100 Subject: [PATCH 274/358] Deps: update to memoffset 0.8 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 18eae53589..960d4f61b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ pin-utils = { version = "0.1.0", optional = true } static_assertions = "1" [target.'cfg(not(target_os = "redox"))'.dependencies] -memoffset = { version = "0.7", optional = true } +memoffset = { version = "0.8", optional = true } [features] default = [ From 09a85e2e68028a78443e8d1d082ab4e11d59a5d7 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Tue, 24 Jan 2023 10:49:35 -0500 Subject: [PATCH 275/358] Null-check `libc::group` members before converting This mirrors the approach used for the `From<&libc::passwd> for User` impl. --- src/unistd.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 8cad67f4a4..36ae480a16 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -3735,11 +3735,23 @@ impl From<&libc::group> for Group { fn from(gr: &libc::group) -> Group { unsafe { Group { - name: CStr::from_ptr(gr.gr_name).to_string_lossy().into_owned(), - passwd: CString::new(CStr::from_ptr(gr.gr_passwd).to_bytes()) - .unwrap(), + name: if gr.gr_name.is_null() { + Default::default() + } else { + CStr::from_ptr(gr.gr_name).to_string_lossy().into_owned() + }, + passwd: if gr.gr_passwd.is_null() { + Default::default() + } else { + CString::new(CStr::from_ptr(gr.gr_passwd).to_bytes()) + .unwrap() + }, gid: Gid::from_raw(gr.gr_gid), - mem: Group::members(gr.gr_mem), + mem: if gr.gr_mem.is_null() { + Default::default() + } else { + Group::members(gr.gr_mem) + }, } } } From 5c3907f61c4229fffb8ee8902231f6e168e3ad66 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Tue, 24 Jan 2023 11:02:56 -0500 Subject: [PATCH 276/358] Make `*::from_anything` methods unsafe The called function must uphold some invariants about initializing data in order for the calls to `from_anything` to be sound. --- src/unistd.rs | 62 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 8cad67f4a4..89edcbeffa 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -3631,7 +3631,12 @@ impl From for libc::passwd { #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd impl User { - fn from_anything(f: F) -> Result> + /// # Safety + /// + /// If `f` writes to its `*mut *mut libc::passwd` parameter, then it must + /// also initialize the value pointed to by its `*mut libc::group` + /// parameter. + unsafe fn from_anything(f: F) -> Result> where F: Fn( *mut libc::passwd, @@ -3661,7 +3666,9 @@ impl User { if res.is_null() { return Ok(None); } else { - let pwd = unsafe { pwd.assume_init() }; + // SAFETY: `f` guarantees that `pwd` is initialized if `res` + // is not null. + let pwd = pwd.assume_init(); return Ok(Some(User::from(&pwd))); } } else if Errno::last() == Errno::ERANGE { @@ -3687,9 +3694,13 @@ impl User { /// assert_eq!(res.name, "root"); /// ``` pub fn from_uid(uid: Uid) -> Result> { - User::from_anything(|pwd, cbuf, cap, res| unsafe { - libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) - }) + // SAFETY: `getpwuid_r` will write to `res` if it initializes the value + // at `pwd`. + unsafe { + User::from_anything(|pwd, cbuf, cap, res| { + libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) + }) + } } /// Get a user by name. @@ -3710,9 +3721,13 @@ impl User { Ok(c_str) => c_str, Err(_nul_error) => return Ok(None), }; - User::from_anything(|pwd, cbuf, cap, res| unsafe { - libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) - }) + // SAFETY: `getpwnam_r` will write to `res` if it initializes the value + // at `pwd`. + unsafe { + User::from_anything(|pwd, cbuf, cap, res| { + libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) + }) + } } } @@ -3763,7 +3778,12 @@ impl Group { ret } - fn from_anything(f: F) -> Result> + /// # Safety + /// + /// If `f` writes to its `*mut *mut libc::group` parameter, then it must + /// also initialize the value pointed to by its `*mut libc::group` + /// parameter. + unsafe fn from_anything(f: F) -> Result> where F: Fn( *mut libc::group, @@ -3793,7 +3813,9 @@ impl Group { if res.is_null() { return Ok(None); } else { - let grp = unsafe { grp.assume_init() }; + // SAFETY: `f` guarantees that `grp` is initialized if `res` + // is not null. + let grp = grp.assume_init(); return Ok(Some(Group::from(&grp))); } } else if Errno::last() == Errno::ERANGE { @@ -3821,9 +3843,13 @@ impl Group { /// assert!(res.name == "root"); /// ``` pub fn from_gid(gid: Gid) -> Result> { - Group::from_anything(|grp, cbuf, cap, res| unsafe { - libc::getgrgid_r(gid.0, grp, cbuf, cap, res) - }) + // SAFETY: `getgrgid_r` will write to `res` if it initializes the value + // at `grp`. + unsafe { + Group::from_anything(|grp, cbuf, cap, res| { + libc::getgrgid_r(gid.0, grp, cbuf, cap, res) + }) + } } /// Get a group by name. @@ -3846,9 +3872,13 @@ impl Group { Ok(c_str) => c_str, Err(_nul_error) => return Ok(None), }; - Group::from_anything(|grp, cbuf, cap, res| unsafe { - libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) - }) + // SAFETY: `getgrnam_r` will write to `res` if it initializes the value + // at `grp`. + unsafe { + Group::from_anything(|grp, cbuf, cap, res| { + libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) + }) + } } } } From 1d31d0d7f4a684e462a0f84ab13f6e72bda956b0 Mon Sep 17 00:00:00 2001 From: gco Date: Mon, 30 Jan 2023 23:44:35 -0800 Subject: [PATCH 277/358] setgroups type mismatches on Solaris #1986 --- src/unistd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index fc3c405d56..a10c17b552 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -1652,8 +1652,8 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { target_os = "ios", target_os = "macos", target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] { + target_os = "openbsd", + target_os = "solaris"))] { type setgroups_ngroups_t = c_int; } else { type setgroups_ngroups_t = size_t; From e458f5f093c18b590750e8fd8fd3baa8cdaaf52d Mon Sep 17 00:00:00 2001 From: Matteo Nardi Date: Wed, 1 Feb 2023 09:56:03 +0100 Subject: [PATCH 278/358] Enabled `AtFlags::AT_EACCESS` on all platforms but android and redox --- CHANGELOG.md | 2 ++ src/fcntl.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7da93bbf1..69de261dc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added `AT_EACCESS` to `AtFlags` on all platforms but android + ([#1995](https://github.com/nix-rust/nix/pull/1995)) - Add `PF_ROUTE` to `SockType` on macOS, iOS, all of the BSDs, Fuchsia, Haiku, Illumos. ([#1867](https://github.com/nix-rust/nix/pull/1867)) - Added `nix::ucontext` module on `aarch64-unknown-linux-gnu`. diff --git a/src/fcntl.rs b/src/fcntl.rs index 1e24f603f6..a9ef9ad1bc 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -35,7 +35,7 @@ libc_bitflags! { AT_NO_AUTOMOUNT; #[cfg(any(target_os = "android", target_os = "linux"))] AT_EMPTY_PATH; - #[cfg(any(target_os = "illumos", target_os = "solaris"))] + #[cfg(not(target_os = "android"))] AT_EACCESS; } } From 34f0eea7e3e4d6448efe2d9ffbb344f73d2e0fbe Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 11 Dec 2022 09:43:30 -0700 Subject: [PATCH 279/358] Rustier kqueue API * Prefer methods instead of functions. * Create a newtype for a kqueue. * Document everything. * Deprecate EVFILT_SENDFILE, because it was never fully implemented upstream. * Add support to the libc_enum! macro to be able to deprecate variants. --- CHANGELOG.md | 4 + src/macros.rs | 2 + src/sys/event.rs | 213 ++++++++++++++++++++++++++++++++++++++++------- src/sys/mod.rs | 1 - 4 files changed, 188 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68edef38df..c3d4e7a13f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). - With I/O-safe type applied in `pty::OpenptyResult` and `pty::ForkptyResult`, users no longer need to manually close the file descriptors in these types. ([#1921](https://github.com/nix-rust/nix/pull/1921)) +- `sys::event::{kevent, kevent_ts}` are deprecated in favor of + `sys::kevent::Kqueue::kevent`, and `sys::event::kqueue` is deprecated in + favor of `sys::kevent::Kqueue::new`. + ([#1943](https://github.com/nix-rust/nix/pull/1943)) ### Fixed - Fix `SockaddrIn6` bug that was swapping flowinfo and scope_id byte ordering. diff --git a/src/macros.rs b/src/macros.rs index 07d80f68cc..5d83a5ac3c 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -132,6 +132,8 @@ macro_rules! libc_enum { impl ::std::convert::TryFrom<$repr> for $BitFlags { type Error = $crate::Error; #[allow(unused_doc_comments)] + #[allow(deprecated)] + #[allow(unused_attributes)] fn try_from(x: $repr) -> $crate::Result { match x { $($try_froms)* diff --git a/src/sys/event.rs b/src/sys/event.rs index f21ba17324..5dcf121ae2 100644 --- a/src/sys/event.rs +++ b/src/sys/event.rs @@ -1,5 +1,7 @@ -/* TOOD: Implement for other kqueue based systems - */ +//! Kernel event notification mechanism +//! +//! # See Also +//! [kqueue(2)](https://www.freebsd.org/cgi/man.cgi?query=kqueue) use crate::{Errno, Result}; #[cfg(not(target_os = "netbsd"))] @@ -8,16 +10,74 @@ use libc::{c_int, c_long, intptr_t, time_t, timespec, uintptr_t}; use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t}; use std::convert::TryInto; use std::mem; -use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd}; use std::ptr; -// Redefine kevent in terms of programmer-friendly enums and bitfields. +/// A kernel event queue. Used to notify a process of various asynchronous +/// events. #[repr(C)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct KEvent { kevent: libc::kevent, } +/// A kernel event queue. +/// +/// Used by the kernel to notify the process of various types of asynchronous +/// events. +#[repr(transparent)] +#[derive(Debug)] +pub struct Kqueue(OwnedFd); + +impl Kqueue { + /// Create a new kernel event queue. + pub fn new() -> Result { + let res = unsafe { libc::kqueue() }; + + Errno::result(res).map(|fd| unsafe { Self(OwnedFd::from_raw_fd(fd)) }) + } + + /// Register new events with the kqueue, and return any pending events to + /// the user. + /// + /// This method will block until either the timeout expires, or a registered + /// event triggers a notification. + /// + /// # Arguments + /// - `changelist` - Any new kevents to register for notifications. + /// - `eventlist` - Storage space for the kernel to return notifications. + /// - `timeout` - An optional timeout. + /// + /// # Returns + /// Returns the number of events placed in the `eventlist`. If an error + /// occurs while processing an element of the `changelist` and there is + /// enough room in the `eventlist`, then the event will be placed in the + /// `eventlist` with `EV_ERROR` set in `flags` and the system error in + /// `data`. + pub fn kevent( + &self, + changelist: &[KEvent], + eventlist: &mut [KEvent], + timeout_opt: Option, + ) -> Result { + let res = unsafe { + libc::kevent( + self.0.as_raw_fd(), + changelist.as_ptr() as *const libc::kevent, + changelist.len() as type_of_nchanges, + eventlist.as_mut_ptr() as *mut libc::kevent, + eventlist.len() as type_of_nchanges, + if let Some(ref timeout) = timeout_opt { + timeout as *const timespec + } else { + ptr::null() + } + ) + }; + Errno::result(res).map(|r| r as usize) + } +} + #[cfg(any( target_os = "dragonfly", target_os = "freebsd", @@ -37,22 +97,34 @@ libc_enum! { #[cfg_attr(target_os = "netbsd", repr(u32))] #[cfg_attr(not(target_os = "netbsd"), repr(i16))] #[non_exhaustive] + /// Kqueue filter types. These are all the different types of event that a + /// kqueue can notify for. pub enum EventFilter { + /// Notifies on the completion of a POSIX AIO operation. EVFILT_AIO, - /// Returns whenever there is no remaining data in the write buffer #[cfg(target_os = "freebsd")] + /// Returns whenever there is no remaining data in the write buffer EVFILT_EMPTY, #[cfg(target_os = "dragonfly")] + /// Takes a descriptor as the identifier, and returns whenever one of + /// the specified exceptional conditions has occurred on the descriptor. EVFILT_EXCEPT, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos"))] + /// Establishes a file system monitor. EVFILT_FS, #[cfg(target_os = "freebsd")] + /// Notify for completion of a list of POSIX AIO operations. + /// # See Also + /// [lio_listio(2)](https://www.freebsd.org/cgi/man.cgi?query=lio_listio) EVFILT_LIO, #[cfg(any(target_os = "ios", target_os = "macos"))] + /// Mach portsets EVFILT_MACHPORT, + /// Notifies when a process performs one or more of the requested + /// events. EVFILT_PROC, /// Returns events associated with the process referenced by a given /// process descriptor, created by `pdfork()`. The events to monitor are: @@ -60,20 +132,31 @@ libc_enum! { /// - NOTE_EXIT: the process has exited. The exit status will be stored in data. #[cfg(target_os = "freebsd")] EVFILT_PROCDESC, + /// Takes a file descriptor as the identifier, and notifies whenever + /// there is data available to read. EVFILT_READ, - /// Returns whenever an asynchronous `sendfile()` call completes. #[cfg(target_os = "freebsd")] + #[doc(hidden)] + #[deprecated(since = "0.27.0", note = "Never fully implemented by the OS")] EVFILT_SENDFILE, + /// Takes a signal number to monitor as the identifier and notifies when + /// the given signal is delivered to the process. EVFILT_SIGNAL, + /// Establishes a timer and notifies when the timer expires. EVFILT_TIMER, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos"))] + /// Notifies only when explicitly requested by the user. EVFILT_USER, #[cfg(any(target_os = "ios", target_os = "macos"))] + /// Virtual memory events EVFILT_VM, + /// Notifies when a requested event happens on a specified file. EVFILT_VNODE, + /// Takes a file descriptor as the identifier, and notifies whenever + /// it is possible to write to the file without blocking. EVFILT_WRITE, } impl TryFrom @@ -86,131 +169,194 @@ libc_enum! { target_os = "macos", target_os = "openbsd" ))] +#[doc(hidden)] pub type type_of_event_flag = u16; #[cfg(any(target_os = "netbsd"))] +#[doc(hidden)] pub type type_of_event_flag = u32; libc_bitflags! { + /// Event flags. See the man page for details. + // There's no useful documentation we can write for the individual flags + // that wouldn't simply be repeating the man page. pub struct EventFlag: type_of_event_flag { + #[allow(missing_docs)] EV_ADD; + #[allow(missing_docs)] EV_CLEAR; + #[allow(missing_docs)] EV_DELETE; + #[allow(missing_docs)] EV_DISABLE; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[allow(missing_docs)] EV_DISPATCH; #[cfg(target_os = "freebsd")] + #[allow(missing_docs)] EV_DROP; + #[allow(missing_docs)] EV_ENABLE; + #[allow(missing_docs)] EV_EOF; + #[allow(missing_docs)] EV_ERROR; #[cfg(any(target_os = "macos", target_os = "ios"))] + #[allow(missing_docs)] EV_FLAG0; + #[allow(missing_docs)] EV_FLAG1; #[cfg(target_os = "dragonfly")] + #[allow(missing_docs)] EV_NODATA; + #[allow(missing_docs)] EV_ONESHOT; #[cfg(any(target_os = "macos", target_os = "ios"))] + #[allow(missing_docs)] EV_OOBAND; #[cfg(any(target_os = "macos", target_os = "ios"))] + #[allow(missing_docs)] EV_POLL; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] + #[allow(missing_docs)] EV_RECEIPT; } } libc_bitflags!( + /// Filter-specific flags. See the man page for details. + // There's no useful documentation we can write for the individual flags + // that wouldn't simply be repeating the man page. + #[allow(missing_docs)] pub struct FilterFlag: u32 { #[cfg(any(target_os = "macos", target_os = "ios"))] + #[allow(missing_docs)] NOTE_ABSOLUTE; + #[allow(missing_docs)] NOTE_ATTRIB; + #[allow(missing_docs)] NOTE_CHILD; + #[allow(missing_docs)] NOTE_DELETE; #[cfg(target_os = "openbsd")] + #[allow(missing_docs)] NOTE_EOF; + #[allow(missing_docs)] NOTE_EXEC; + #[allow(missing_docs)] NOTE_EXIT; #[cfg(any(target_os = "macos", target_os = "ios"))] + #[allow(missing_docs)] NOTE_EXITSTATUS; + #[allow(missing_docs)] NOTE_EXTEND; #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] + #[allow(missing_docs)] NOTE_FFAND; #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] + #[allow(missing_docs)] NOTE_FFCOPY; #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] + #[allow(missing_docs)] NOTE_FFCTRLMASK; #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] + #[allow(missing_docs)] NOTE_FFLAGSMASK; #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] + #[allow(missing_docs)] NOTE_FFNOP; #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] + #[allow(missing_docs)] NOTE_FFOR; + #[allow(missing_docs)] NOTE_FORK; + #[allow(missing_docs)] NOTE_LINK; + #[allow(missing_docs)] NOTE_LOWAT; #[cfg(target_os = "freebsd")] + #[allow(missing_docs)] NOTE_MSECONDS; #[cfg(any(target_os = "macos", target_os = "ios"))] + #[allow(missing_docs)] NOTE_NONE; #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] + #[allow(missing_docs)] NOTE_NSECONDS; #[cfg(target_os = "dragonfly")] + #[allow(missing_docs)] NOTE_OOB; + #[allow(missing_docs)] NOTE_PCTRLMASK; + #[allow(missing_docs)] NOTE_PDATAMASK; + #[allow(missing_docs)] NOTE_RENAME; + #[allow(missing_docs)] NOTE_REVOKE; #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] + #[allow(missing_docs)] NOTE_SECONDS; #[cfg(any(target_os = "macos", target_os = "ios"))] + #[allow(missing_docs)] NOTE_SIGNAL; + #[allow(missing_docs)] NOTE_TRACK; + #[allow(missing_docs)] NOTE_TRACKERR; #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] + #[allow(missing_docs)] NOTE_TRIGGER; #[cfg(target_os = "openbsd")] + #[allow(missing_docs)] NOTE_TRUNCATE; #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] + #[allow(missing_docs)] NOTE_USECONDS; #[cfg(any(target_os = "macos", target_os = "ios"))] + #[allow(missing_docs)] NOTE_VM_ERROR; #[cfg(any(target_os = "macos", target_os = "ios"))] + #[allow(missing_docs)] NOTE_VM_PRESSURE; #[cfg(any(target_os = "macos", target_os = "ios"))] + #[allow(missing_docs)] NOTE_VM_PRESSURE_SUDDEN_TERMINATE; #[cfg(any(target_os = "macos", target_os = "ios"))] + #[allow(missing_docs)] NOTE_VM_PRESSURE_TERMINATE; + #[allow(missing_docs)] NOTE_WRITE; } ); -pub fn kqueue() -> Result { - let res = unsafe { libc::kqueue() }; - - Errno::result(res).map(|fd| unsafe { OwnedFd::from_raw_fd(fd) }) +#[allow(missing_docs)] +#[deprecated(since = "0.27.0", note = "Use KEvent::new instead")] +pub fn kqueue() -> Result { + Kqueue::new() } // KEvent can't derive Send because on some operating systems, udata is defined @@ -220,6 +366,8 @@ unsafe impl Send for KEvent {} impl KEvent { #[allow(clippy::needless_update)] // Not needless on all platforms. + /// Construct a new `KEvent` suitable for submission to the kernel via the + /// `changelist` argument of [`Kqueue::kevent`]. pub fn new( ident: uintptr_t, filter: EventFilter, @@ -242,33 +390,46 @@ impl KEvent { } } + /// Value used to identify this event. The exact interpretation is + /// determined by the attached filter, but often is a raw file descriptor. pub fn ident(&self) -> uintptr_t { self.kevent.ident } + /// Identifies the kernel filter used to process this event. + /// + /// Will only return an error if the kernel reports an event via a filter + /// that is unknown to Nix. pub fn filter(&self) -> Result { self.kevent.filter.try_into() } + /// Flags control what the kernel will do when this event is added with + /// [`Kqueue::kevent`]. pub fn flags(&self) -> EventFlag { EventFlag::from_bits(self.kevent.flags).unwrap() } + /// Filter-specific flags. pub fn fflags(&self) -> FilterFlag { FilterFlag::from_bits(self.kevent.fflags).unwrap() } + /// Filter-specific data value. pub fn data(&self) -> intptr_t { self.kevent.data as intptr_t } + /// Opaque user-defined value passed through the kernel unchanged. pub fn udata(&self) -> intptr_t { self.kevent.udata as intptr_t } } -pub fn kevent( - kq: Fd, +#[allow(missing_docs)] +#[deprecated(since = "0.27.0", note = "Use Kqueue::kevent instead")] +pub fn kevent( + kq: &Kqueue, changelist: &[KEvent], eventlist: &mut [KEvent], timeout_ms: usize, @@ -279,7 +440,7 @@ pub fn kevent( tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long, }; - kevent_ts(kq, changelist, eventlist, Some(timeout)) + kq.kevent(changelist, eventlist, Some(timeout)) } #[cfg(any( @@ -293,30 +454,20 @@ type type_of_nchanges = c_int; #[cfg(target_os = "netbsd")] type type_of_nchanges = size_t; -pub fn kevent_ts( - kq: Fd, +#[allow(missing_docs)] +#[deprecated(since = "0.27.0", note = "Use Kqueue::kevent instead")] +pub fn kevent_ts( + kq: &Kqueue, changelist: &[KEvent], eventlist: &mut [KEvent], timeout_opt: Option, ) -> Result { - let res = unsafe { - libc::kevent( - kq.as_fd().as_raw_fd(), - changelist.as_ptr() as *const libc::kevent, - changelist.len() as type_of_nchanges, - eventlist.as_mut_ptr() as *mut libc::kevent, - eventlist.len() as type_of_nchanges, - if let Some(ref timeout) = timeout_opt { - timeout as *const timespec - } else { - ptr::null() - }, - ) - }; - - Errno::result(res).map(|r| r as usize) + kq.kevent(changelist, eventlist, timeout_opt) } +/// Modify an existing [`KEvent`]. +// Probably should deprecate. Would anybody ever use it over `KEvent::new`? +#[deprecated(since = "0.27.0", note = "Use Kqueue::kevent instead")] #[inline] pub fn ev_set( ev: &mut KEvent, diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 2065059de8..383f08df04 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -25,7 +25,6 @@ feature! { target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] - #[allow(missing_docs)] pub mod event; #[cfg(any(target_os = "android", target_os = "linux"))] From 7830042a6572bc1bb86429299ca1bc202c1a0710 Mon Sep 17 00:00:00 2001 From: Arvid Norlander Date: Sun, 19 Feb 2023 16:13:58 +0100 Subject: [PATCH 280/358] inotify: Add AsFd to allow using with epoll (issue #1998) --- src/sys/inotify.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sys/inotify.rs b/src/sys/inotify.rs index 2398c16e0b..e5fe930f49 100644 --- a/src/sys/inotify.rs +++ b/src/sys/inotify.rs @@ -32,7 +32,7 @@ use libc::{c_char, c_int}; use std::ffi::{CStr, OsStr, OsString}; use std::mem::{size_of, MaybeUninit}; use std::os::unix::ffi::OsStrExt; -use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd}; use std::ptr; libc_bitflags! { @@ -240,3 +240,9 @@ impl FromRawFd for Inotify { Inotify { fd: OwnedFd::from_raw_fd(fd) } } } + +impl AsFd for Inotify { + fn as_fd(&'_ self) -> BorrowedFd<'_> { + self.fd.as_fd() + } +} From f18ceb934038fe9139e928fd8ef3e037a61f72c1 Mon Sep 17 00:00:00 2001 From: Thomas de Queiroz Barros <38295417+thomasqueirozb@users.noreply.github.com> Date: Mon, 6 Mar 2023 00:57:19 -0300 Subject: [PATCH 281/358] Add more detail for ptrace documentation --- src/sys/ptrace/linux.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs index 9687e05d42..8c134cf7ee 100644 --- a/src/sys/ptrace/linux.rs +++ b/src/sys/ptrace/linux.rs @@ -269,7 +269,7 @@ unsafe fn ptrace_other( .map(|_| 0) } -/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`. +/// Set options, as with `ptrace(PTRACE_SETOPTIONS, ...)`. pub fn setoptions(pid: Pid, options: Options) -> Result<()> { let res = unsafe { libc::ptrace( @@ -282,17 +282,17 @@ pub fn setoptions(pid: Pid, options: Options) -> Result<()> { Errno::result(res).map(drop) } -/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)` +/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG, ...)` pub fn getevent(pid: Pid) -> Result { ptrace_get_data::(Request::PTRACE_GETEVENTMSG, pid) } -/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)` +/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO, ...)` pub fn getsiginfo(pid: Pid) -> Result { ptrace_get_data::(Request::PTRACE_GETSIGINFO, pid) } -/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)` +/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO, ...)` pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { let ret = unsafe { Errno::clear(); @@ -517,12 +517,14 @@ pub fn sysemu_step>>(pid: Pid, sig: T) -> Result<()> { } } -/// Reads a word from a processes memory at the given address +/// Reads a word from a processes memory at the given address, as with +/// ptrace(PTRACE_PEEKDATA, ...) pub fn read(pid: Pid, addr: AddressType) -> Result { ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut()) } -/// Writes a word into the processes memory at the given address +/// Writes a word into the processes memory at the given address, as with +/// ptrace(PTRACE_POKEDATA, ...) /// /// # Safety /// @@ -536,13 +538,13 @@ pub unsafe fn write( ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) } -/// Reads a word from a user area at `offset`. +/// Reads a word from a user area at `offset`, as with ptrace(PTRACE_PEEKUSER, ...). /// The user struct definition can be found in `/usr/include/sys/user.h`. pub fn read_user(pid: Pid, offset: AddressType) -> Result { ptrace_peek(Request::PTRACE_PEEKUSER, pid, offset, ptr::null_mut()) } -/// Writes a word to a user area at `offset`. +/// Writes a word to a user area at `offset`, as with ptrace(PTRACE_POKEUSER, ...). /// The user struct definition can be found in `/usr/include/sys/user.h`. /// /// # Safety From b878d0a7cba4a3f6f518710718198a603de9df1c Mon Sep 17 00:00:00 2001 From: Noa Date: Sat, 11 Mar 2023 00:15:32 -0600 Subject: [PATCH 282/358] Enable socket on redox --- Cargo.toml | 4 +--- src/sys/mod.rs | 1 - src/sys/socket/addr.rs | 29 +++++++++++++++-------- src/sys/socket/mod.rs | 50 ++++++++++++++++++++++----------------- src/sys/socket/sockopt.rs | 8 +++---- 5 files changed, 52 insertions(+), 40 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 960d4f61b3..02a7afb759 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,13 +27,11 @@ targets = [ ] [dependencies] -libc = { git = "https://github.com/rust-lang/libc", rev = "44cc30c6b68427d3628926868758d35fe561bbe6", features = [ "extra_traits" ] } +libc = { git = "https://github.com/rust-lang/libc", rev = "60bf6d7fa9d561820ea562751ee455ccf67d3015", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } static_assertions = "1" - -[target.'cfg(not(target_os = "redox"))'.dependencies] memoffset = { version = "0.8", optional = true } [features] diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 383f08df04..e74bb18a4c 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -138,7 +138,6 @@ feature! { pub mod signalfd; } -#[cfg(not(target_os = "redox"))] feature! { #![feature = "socket"] #[allow(missing_docs)] diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index aad407a7f0..4830974933 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -100,8 +100,10 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] Ax25 = libc::AF_AX25, /// IPX - Novell protocols + #[cfg(not(target_os = "redox"))] Ipx = libc::AF_IPX, /// AppleTalk + #[cfg(not(target_os = "redox"))] AppleTalk = libc::AF_APPLETALK, /// AX.25 packet layer protocol. /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) @@ -130,7 +132,7 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] Rose = libc::AF_ROSE, /// DECet protocol sockets. - #[cfg(not(target_os = "haiku"))] + #[cfg(not(any(target_os = "haiku", target_os = "redox")))] Decnet = libc::AF_DECnet, /// Reserved for "802.2LLC project"; never used. #[cfg(any(target_os = "android", target_os = "linux"))] @@ -162,7 +164,7 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] Rds = libc::AF_RDS, /// IBM SNA - #[cfg(not(target_os = "haiku"))] + #[cfg(not(any(target_os = "haiku", target_os = "redox")))] Sna = libc::AF_SNA, /// Socket interface over IrDA #[cfg(any(target_os = "android", target_os = "linux"))] @@ -202,7 +204,8 @@ pub enum AddressFamily { target_os = "illumos", target_os = "ios", target_os = "macos", - target_os = "solaris" + target_os = "solaris", + target_os = "redox", )))] #[cfg_attr(docsrs, doc(cfg(all())))] Bluetooth = libc::AF_BLUETOOTH, @@ -219,7 +222,8 @@ pub enum AddressFamily { #[cfg(not(any( target_os = "illumos", target_os = "solaris", - target_os = "haiku" + target_os = "haiku", + target_os = "redox", )))] #[cfg_attr(docsrs, doc(cfg(all())))] Isdn = libc::AF_ISDN, @@ -460,7 +464,8 @@ pub struct UnixAddr { target_os = "android", target_os = "fuchsia", target_os = "illumos", - target_os = "linux" + target_os = "linux", + target_os = "redox", ))] sun_len: u8, } @@ -624,7 +629,8 @@ impl UnixAddr { if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "illumos", - target_os = "linux" + target_os = "linux", + target_os = "redox", ))] { UnixAddr { sun, sun_len } @@ -690,7 +696,8 @@ impl UnixAddr { if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "illumos", - target_os = "linux" + target_os = "linux", + target_os = "redox", ))] { self.sun_len @@ -736,7 +743,8 @@ impl SockaddrLike for UnixAddr { if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "illumos", - target_os = "linux" + target_os = "linux", + target_os = "redox", ))] { let su_len = len.unwrap_or( mem::size_of::() as libc::socklen_t @@ -1221,7 +1229,7 @@ pub union SockaddrStorage { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] alg: AlgAddr, - #[cfg(feature = "net")] + #[cfg(all(feature = "net", not(target_os = "redox")))] #[cfg_attr(docsrs, doc(cfg(feature = "net")))] dl: LinkAddr, #[cfg(any(target_os = "android", target_os = "linux"))] @@ -2338,6 +2346,7 @@ mod tests { } } + #[cfg(not(target_os = "redox"))] mod link { #![allow(clippy::cast_ptr_alignment)] @@ -2534,7 +2543,7 @@ mod tests { nix_sin6.0.sin6_flowinfo = 0x12345678; nix_sin6.0.sin6_scope_id = 0x9abcdef0; - let std_sin6 : std::net::SocketAddrV6 = nix_sin6.into(); + let std_sin6: std::net::SocketAddrV6 = nix_sin6.into(); assert_eq!(nix_sin6, std_sin6.into()); } } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 00c905608a..ab7495ed24 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -4,19 +4,22 @@ #[cfg(target_os = "linux")] #[cfg(feature = "uio")] use crate::sys::time::TimeSpec; +#[cfg(not(target_os = "redox"))] #[cfg(feature = "uio")] use crate::sys::time::TimeVal; use crate::{errno::Errno, Result}; use cfg_if::cfg_if; +use libc::{self, c_int, c_void, size_t, socklen_t}; +#[cfg(all(feature = "uio", not(target_os = "redox")))] use libc::{ - self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR, - CMSG_LEN, CMSG_NXTHDR, + iovec, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, CMSG_SPACE, }; +#[cfg(not(target_os = "redox"))] use std::io::{IoSlice, IoSliceMut}; #[cfg(feature = "net")] use std::net; use std::os::unix::io::RawFd; -use std::{mem, ptr, slice}; +use std::{mem, ptr}; #[deny(missing_docs)] mod addr; @@ -38,14 +41,16 @@ pub use self::addr::{AddressFamily, UnixAddr}; #[cfg(not(any( target_os = "illumos", target_os = "solaris", - target_os = "haiku" + target_os = "haiku", + target_os = "redox", )))] #[cfg(feature = "net")] pub use self::addr::{LinkAddr, SockaddrIn, SockaddrIn6}; #[cfg(any( target_os = "illumos", target_os = "solaris", - target_os = "haiku" + target_os = "haiku", + target_os = "redox", ))] #[cfg(feature = "net")] pub use self::addr::{SockaddrIn, SockaddrIn6}; @@ -60,16 +65,12 @@ pub use crate::sys::socket::addr::sys_control::SysControlAddr; #[cfg(any(target_os = "android", target_os = "linux"))] pub use crate::sys::socket::addr::vsock::VsockAddr; -#[cfg(feature = "uio")] +#[cfg(all(feature = "uio", not(target_os = "redox")))] pub use libc::{cmsghdr, msghdr}; pub use libc::{sa_family_t, sockaddr, sockaddr_storage, sockaddr_un}; #[cfg(feature = "net")] pub use libc::{sockaddr_in, sockaddr_in6}; -// Needed by the cmsg_space macro -#[doc(hidden)] -pub use libc::{c_uint, CMSG_SPACE}; - #[cfg(feature = "net")] use crate::sys::socket::addr::{ipv4addr_to_libc, ipv6addr_to_libc}; @@ -92,10 +93,11 @@ pub enum SockType { /// entire packet with each input system call. SeqPacket = libc::SOCK_SEQPACKET, /// Provides raw network protocol access. + #[cfg(not(target_os = "redox"))] Raw = libc::SOCK_RAW, /// Provides a reliable datagram layer that does not /// guarantee ordering. - #[cfg(not(any(target_os = "haiku")))] + #[cfg(not(any(target_os = "haiku", target_os = "redox")))] Rdm = libc::SOCK_RDM, } // The TryFrom impl could've been derived using libc_enum!. But for @@ -109,8 +111,9 @@ impl TryFrom for SockType { libc::SOCK_STREAM => Ok(Self::Stream), libc::SOCK_DGRAM => Ok(Self::Datagram), libc::SOCK_SEQPACKET => Ok(Self::SeqPacket), + #[cfg(not(target_os = "redox"))] libc::SOCK_RAW => Ok(Self::Raw), - #[cfg(not(any(target_os = "haiku")))] + #[cfg(not(any(target_os = "haiku", target_os = "redox")))] libc::SOCK_RDM => Ok(Self::Rdm), _ => Err(Errno::EINVAL), } @@ -239,7 +242,7 @@ libc_bitflags! { /// /// For use with [`Timestamping`][sockopt::Timestamping]. /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - pub struct TimestampingFlag: c_uint { + pub struct TimestampingFlag: libc::c_uint { /// Report any software timestamps when available. SOF_TIMESTAMPING_SOFTWARE; /// Report hardware timestamps as generated by SOF_TIMESTAMPING_TX_HARDWARE when available. @@ -456,7 +459,7 @@ cfg_if! { /// Returns a list group identifiers (the first one being the effective GID) pub fn groups(&self) -> &[libc::gid_t] { unsafe { - slice::from_raw_parts( + std::slice::from_raw_parts( self.0.cmcred_groups.as_ptr() as *const libc::gid_t, self.0.cmcred_ngroups as _ ) @@ -549,6 +552,7 @@ impl Ipv6MembershipRequest { } } +#[cfg(not(target_os = "redox"))] feature! { #![feature = "uio"] @@ -578,18 +582,19 @@ feature! { macro_rules! cmsg_space { ( $( $x:ty ),* ) => { { - let mut space = 0; - $( - // CMSG_SPACE is always safe - space += unsafe { - $crate::sys::socket::CMSG_SPACE(::std::mem::size_of::<$x>() as $crate::sys::socket::c_uint) - } as usize; - )* + let space = 0 $(+ $crate::sys::socket::cmsg_space::<$x>())*; Vec::::with_capacity(space) } } } +#[inline] +#[doc(hidden)] +pub fn cmsg_space() -> usize { + // SAFETY: CMSG_SPACE is always safe + unsafe { libc::CMSG_SPACE(mem::size_of::() as libc::c_uint) as usize } +} + #[derive(Clone, Copy, Debug, Eq, PartialEq)] /// Contains outcome of sending or receiving a message /// @@ -984,7 +989,7 @@ impl ControlMessageOwned { ControlMessageOwned::Ipv6OrigDstAddr(dl) }, (_, _) => { - let sl = slice::from_raw_parts(p, len); + let sl = std::slice::from_raw_parts(p, len); let ucmsg = UnknownCmsg(*header, Vec::::from(sl)); ControlMessageOwned::Unknown(ucmsg) } @@ -2392,6 +2397,7 @@ pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> { #[cfg(test)] mod tests { + #[cfg(not(target_os = "redox"))] #[test] fn can_use_cmsg_space() { let _ = cmsg_space!(u8); diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 9021664997..a18b5905ae 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -544,13 +544,13 @@ cfg_if! { sockopt_impl!( /// The maximum segment size for outgoing TCP packets. TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); - } else { + } else if #[cfg(not(target_os = "redox"))] { sockopt_impl!( /// The maximum segment size for outgoing TCP packets. TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32); } } -#[cfg(not(any(target_os = "openbsd", target_os = "haiku")))] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "redox")))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -572,7 +572,7 @@ sockopt_impl!( libc::TCP_REPAIR, u32 ); -#[cfg(not(any(target_os = "openbsd", target_os = "haiku")))] +#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "redox")))] #[cfg(feature = "net")] sockopt_impl!( #[cfg_attr(docsrs, doc(cfg(feature = "net")))] @@ -693,7 +693,7 @@ sockopt_impl!( libc::SO_TIMESTAMPING, super::TimestampingFlag ); -#[cfg(not(target_os = "haiku"))] +#[cfg(not(any(target_os = "haiku", target_os = "redox")))] sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. ReceiveTimestamp, From 17b608aa0546fd4f06940d36108e831e42aef8d7 Mon Sep 17 00:00:00 2001 From: Noa Date: Thu, 9 Mar 2023 16:02:55 -0600 Subject: [PATCH 283/358] Enable select on redox --- src/sys/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sys/mod.rs b/src/sys/mod.rs index e74bb18a4c..9bba1c4e9e 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -110,7 +110,6 @@ feature! { pub mod resource; } -#[cfg(not(target_os = "redox"))] feature! { #![feature = "poll"] pub mod select; From 06eb8ffaadabebbc884ce6f6e90a8261866d9ca4 Mon Sep 17 00:00:00 2001 From: Todd Neal Date: Thu, 8 Dec 2022 03:58:34 +0000 Subject: [PATCH 284/358] fix: send ETH_P_ALL in htons format --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8bde843f1..e52344b973 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Fixed - Fix `SockaddrIn6` bug that was swapping flowinfo and scope_id byte ordering. ([#1964](https://github.com/nix-rust/nix/pull/1964)) +- Fix: send ETH_P_ALL in htons format + ([#1925](https://github.com/nix-rust/nix/pull/1925)) ### Removed diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 00c905608a..7128d86773 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -217,7 +217,7 @@ pub enum SockProtocol { // The protocol number is fed into the socket syscall in network byte order. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] - EthAll = libc::ETH_P_ALL.to_be(), + EthAll = (libc::ETH_P_ALL as u16).to_be() as i32, /// The Controller Area Network raw socket protocol /// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan)) #[cfg(target_os = "linux")] From fff2ca45b643636f87727cc8489a93e83b31a87e Mon Sep 17 00:00:00 2001 From: Noa Date: Mon, 3 Apr 2023 13:28:32 -0500 Subject: [PATCH 285/358] Add CHANGELOG entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8bde843f1..0520abc596 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). `sys::kevent::Kqueue::kevent`, and `sys::event::kqueue` is deprecated in favor of `sys::kevent::Kqueue::new`. ([#1943](https://github.com/nix-rust/nix/pull/1943)) +- `nix::socket` and `nix::select` are now available on Redox. + ([#2012](https://github.com/nix-rust/nix/pull/2012)) ### Fixed - Fix `SockaddrIn6` bug that was swapping flowinfo and scope_id byte ordering. From 7baaccdf347a03e60477e0e013f3acf0568e126a Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 2 Apr 2023 10:01:36 -0600 Subject: [PATCH 286/358] Fix aio_suspend in non-trivial cases aio_suspend would probably fail with EFAULT if the first operation in the list wasn't complete, due to an invalid pointer cast. Also, deprecate lio_listio, which has the same problem, and others besides. Fixes #1980 --- src/sys/aio.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sys/aio.rs b/src/sys/aio.rs index ee78d9c2f0..bd4c122916 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -1051,8 +1051,14 @@ pub fn aio_suspend( list: &[&dyn AsRef], timeout: Option, ) -> Result<()> { - let p = list as *const [&dyn AsRef] - as *const [*const libc::aiocb] as *const *const libc::aiocb; + // Note that this allocation could be eliminated by making the argument + // generic, and accepting arguments like &[AioWrite]. But that would + // prevent using aio_suspend to wait on a heterogeneous list of mixed + // operations. + let v = list.iter() + .map(|x| x.as_ref() as *const libc::aiocb) + .collect::>(); + let p = v.as_ptr(); let timep = match timeout { None => ptr::null::(), Some(x) => x.as_ref() as *const libc::timespec, @@ -1172,6 +1178,7 @@ pub fn aio_suspend( /// // notification, we know that all operations are complete. /// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); /// ``` +#[deprecated(since = "0.27.0", note = "https://github.com/nix-rust/nix/issues/2017")] pub fn lio_listio( mode: LioMode, list: &mut [Pin<&mut dyn AsMut>], From a17d0006f75488a3d8389b6b8689301d0b5aa867 Mon Sep 17 00:00:00 2001 From: Austin Keeley Date: Sun, 16 Apr 2023 09:32:35 -0400 Subject: [PATCH 287/358] Fixing link --- src/unistd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unistd.rs b/src/unistd.rs index a10c17b552..7230c3370f 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -3706,7 +3706,7 @@ impl User { /// Get a user by name. /// /// Internally, this function calls - /// [getpwnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html) + /// [getpwnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwnam_r.html) /// /// # Examples /// From 3d83e30be66bad99d6a85a1b92d791ae4c9a950e Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 16 Apr 2023 09:12:05 -0600 Subject: [PATCH 288/358] Quiet Clippy::manual_slice_size_calculation lints --- src/sys/ioctl/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sys/ioctl/mod.rs b/src/sys/ioctl/mod.rs index 98d6b5c99d..0b3fe3e769 100644 --- a/src/sys/ioctl/mod.rs +++ b/src/sys/ioctl/mod.rs @@ -712,7 +712,7 @@ macro_rules! ioctl_read_buf { pub unsafe fn $name(fd: $crate::libc::c_int, data: &mut [$ty]) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data)) } ) } @@ -751,7 +751,7 @@ macro_rules! ioctl_write_buf { pub unsafe fn $name(fd: $crate::libc::c_int, data: &[$ty]) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data)) } ) } @@ -780,7 +780,7 @@ macro_rules! ioctl_readwrite_buf { pub unsafe fn $name(fd: $crate::libc::c_int, data: &mut [$ty]) -> $crate::Result<$crate::libc::c_int> { - convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) + convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data)) } ) } From c7d03bc8cdfc0a7c345b38ac02fc75d2649d8efa Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 16 Apr 2023 09:25:02 -0600 Subject: [PATCH 289/358] Quiet a clippy::suspicious_doc_comments lint --- src/sys/ptrace/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/ptrace/mod.rs b/src/sys/ptrace/mod.rs index 2b121c0b4d..88648acabc 100644 --- a/src/sys/ptrace/mod.rs +++ b/src/sys/ptrace/mod.rs @@ -1,4 +1,4 @@ -///! Provides helpers for making ptrace system calls +//! Provides helpers for making ptrace system calls #[cfg(any(target_os = "android", target_os = "linux"))] mod linux; From 9407dd9aaab5d424a0f09d3ecfac57116d4dfcc9 Mon Sep 17 00:00:00 2001 From: Alex Touchet Date: Tue, 25 Apr 2023 20:15:00 -0700 Subject: [PATCH 290/358] Update to crates.io release of libc --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 02a7afb759..18b3a47d2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { git = "https://github.com/rust-lang/libc", rev = "60bf6d7fa9d561820ea562751ee455ccf67d3015", features = [ "extra_traits" ] } +libc = { version = "0.2.141", features = ["extra_traits"] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } From 2f60820c3d11e773826705b7204216aebbad5a6c Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sat, 29 Apr 2023 14:54:23 -0500 Subject: [PATCH 291/358] Remove 'static mut' usage in features::os::kernel_version. (re-commit for CI retry after rustix 0.37.18 release) --- src/features.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/features.rs b/src/features.rs index 39d17604e1..2f07a8fccd 100644 --- a/src/features.rs +++ b/src/features.rs @@ -6,6 +6,7 @@ mod os { use crate::sys::utsname::uname; use crate::Result; use std::os::unix::ffi::OsStrExt; + use std::sync::atomic::{AtomicUsize, Ordering}; // Features: // * atomic cloexec on socket: 2.6.27 @@ -72,15 +73,15 @@ mod os { } fn kernel_version() -> Result { - static mut KERNEL_VERS: usize = 0; + static KERNEL_VERS: AtomicUsize = AtomicUsize::new(0); + let mut kernel_vers = KERNEL_VERS.load(Ordering::Relaxed); - unsafe { - if KERNEL_VERS == 0 { - KERNEL_VERS = parse_kernel_version()?; - } - - Ok(KERNEL_VERS) + if kernel_vers == 0 { + kernel_vers = parse_kernel_version()?; + KERNEL_VERS.store(kernel_vers, Ordering::Relaxed); } + + Ok(kernel_vers) } /// Check if the OS supports atomic close-on-exec for sockets From 918a5abb67156a9a9d3785d7a5dfaf2cb35c74c9 Mon Sep 17 00:00:00 2001 From: Bob Haarman Date: Tue, 9 May 2023 16:40:31 +0000 Subject: [PATCH 292/358] remove unused mut from two variable declarations in sys/socket/mod.rs This addresses diagnostics like: error: variable does not need to be mutable --> src/sys/socket/mod.rs:1537:13 | 1537 | let mut p = &mut mmsghdr.msg_hdr; --- src/sys/socket/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index a953059bbc..9b6f18efb0 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1534,7 +1534,7 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>( for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() { - let mut p = &mut mmsghdr.msg_hdr; + let p = &mut mmsghdr.msg_hdr; p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; p.msg_iovlen = slice.as_ref().len() as _; @@ -1687,7 +1687,7 @@ where { let mut count = 0; for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() { - let mut p = &mut mmsghdr.msg_hdr; + let p = &mut mmsghdr.msg_hdr; p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; p.msg_iovlen = slice.as_ref().len() as _; count = i + 1; From 905c23e90be1ab4c6bc91f18f80eba17bcbd0c10 Mon Sep 17 00:00:00 2001 From: Jarred Allen Date: Fri, 19 May 2023 16:40:23 -0700 Subject: [PATCH 293/358] Set the length of a sockaddr received on Linux --- src/sys/socket/addr.rs | 2 +- src/sys/socket/mod.rs | 34 ++++++++++++++++++---------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 4830974933..8c5a56fe05 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1679,7 +1679,7 @@ impl PartialEq for SockaddrStorage { } } -mod private { +pub(super) mod private { pub trait SockaddrLikePriv { /// Returns a mutable raw pointer to the inner structure. /// diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 9b6f18efb0..1bbfa5414f 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1609,7 +1609,7 @@ impl MultiHeaders { { // we will be storing pointers to addresses inside mhdr - convert it into boxed // slice so it can'be changed later by pushing anything into self.addresses - let mut addresses = vec![std::mem::MaybeUninit::uninit(); num_slices].into_boxed_slice(); + let mut addresses = vec![std::mem::MaybeUninit::::uninit(); num_slices].into_boxed_slice(); let msg_controllen = cmsg_buffer.as_ref().map_or(0, |v| v.capacity()); @@ -1626,7 +1626,9 @@ impl MultiHeaders { Some(v) => ((&v[ix * msg_controllen] as *const u8), msg_controllen), None => (std::ptr::null(), 0), }; - let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.as_mut_ptr()) }; + let msg_hdr = unsafe { + pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, ::as_mut_ptr(address.assume_init_mut()).cast()) + }; libc::mmsghdr { msg_hdr, msg_len: 0, @@ -1761,7 +1763,7 @@ where mmsghdr.msg_hdr, mmsghdr.msg_len as isize, self.rmm.msg_controllen, - address, + Some(address), ) }) } @@ -1914,7 +1916,7 @@ unsafe fn read_mhdr<'a, 'i, S>( mhdr: msghdr, r: isize, msg_controllen: usize, - address: S, + address: Option, ) -> RecvMsg<'a, 'i, S> where S: SockaddrLike { @@ -1933,7 +1935,7 @@ unsafe fn read_mhdr<'a, 'i, S>( RecvMsg { bytes: r as usize, cmsghdr, - address: Some(address), + address, flags: MsgFlags::from_bits_truncate(mhdr.msg_flags), mhdr, iobufs: std::marker::PhantomData, @@ -1951,22 +1953,19 @@ unsafe fn read_mhdr<'a, 'i, S>( /// headers are not used /// /// Buffers must remain valid for the whole lifetime of msghdr -unsafe fn pack_mhdr_to_receive( +unsafe fn pack_mhdr_to_receive( iov_buffer: *const IoSliceMut, iov_buffer_len: usize, cmsg_buffer: *const u8, cmsg_capacity: usize, - address: *mut S, -) -> msghdr - where - S: SockaddrLike -{ + address: *mut libc::sockaddr_storage, +) -> msghdr { // Musl's msghdr has private fields, so this is the only way to // initialize it. let mut mhdr = mem::MaybeUninit::::zeroed(); let p = mhdr.as_mut_ptr(); - (*p).msg_name = (*address).as_mut_ptr() as *mut c_void; - (*p).msg_namelen = S::size(); + (*p).msg_name = address as *mut c_void; + (*p).msg_namelen = mem::size_of::() as u32; (*p).msg_iov = iov_buffer as *mut iovec; (*p).msg_iovlen = iov_buffer_len as _; (*p).msg_control = cmsg_buffer as *mut c_void; @@ -2048,20 +2047,23 @@ pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'i where S: SockaddrLike + 'a, 'inner: 'outer { - let mut address = mem::MaybeUninit::uninit(); + let mut address: libc::sockaddr_storage = unsafe { mem::MaybeUninit::zeroed().assume_init() }; + let address_ptr: *mut libc::sockaddr_storage = &mut address as *mut libc::sockaddr_storage; let (msg_control, msg_controllen) = cmsg_buffer.as_mut() .map(|v| (v.as_mut_ptr(), v.capacity())) .unwrap_or((ptr::null_mut(), 0)); let mut mhdr = unsafe { - pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr()) + pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address_ptr) }; let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; let r = Errno::result(ret)?; - Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init()) }) + let address = unsafe { S::from_raw(address_ptr.cast::(), Some(mhdr.msg_namelen)) }; + + Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address) }) } } From 96fa5a898cb3dba90469cdf5c8df9042ef391456 Mon Sep 17 00:00:00 2001 From: Jarred Allen Date: Fri, 19 May 2023 16:58:22 -0700 Subject: [PATCH 294/358] Add test coverage for bug with unset socket address length --- test/sys/test_socket.rs | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 0a8d0544cb..b78c8c491a 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -202,6 +202,50 @@ pub fn test_socketpair() { assert_eq!(&buf[..], b"hello"); } +#[test] +pub fn test_recvmsg_sockaddr_un() { + use nix::sys::socket::{ + self, bind, socket, AddressFamily, MsgFlags, SockFlag, SockType, + }; + + let tempdir = tempfile::tempdir().unwrap(); + let sockname = tempdir.path().join("sock"); + let sock = socket( + AddressFamily::Unix, + SockType::Datagram, + SockFlag::empty(), + None, + ) + .expect("socket failed"); + let sockaddr = UnixAddr::new(&sockname).unwrap(); + bind(sock, &sockaddr).expect("bind failed"); + + // Send a message + let send_buffer = "hello".as_bytes(); + if let Err(e) = socket::sendmsg( + sock, + &[std::io::IoSlice::new(send_buffer)], + &[], + MsgFlags::empty(), + Some(&sockaddr), + ) { + print!("Couldn't send ({e:?}), so skipping test"); + return; + } + + // Receive the message + let mut recv_buffer = [0u8; 32]; + let received = socket::recvmsg( + sock, + &mut [std::io::IoSliceMut::new(&mut recv_buffer)], + None, + MsgFlags::empty(), + ) + .unwrap(); + // Check the address in the received message + assert_eq!(sockaddr, received.address.unwrap()); +} + #[test] pub fn test_std_conversions() { use nix::sys::socket::*; From a4dd9cd1165a1e5cf864c06f634b426d9c88ebc9 Mon Sep 17 00:00:00 2001 From: Andrii Pohrebniak Date: Thu, 18 May 2023 12:25:39 +0100 Subject: [PATCH 295/358] timerfd: Add TFD_TIMER_CANCEL_ON_SET flag --- CHANGELOG.md | 2 ++ src/sys/time.rs | 1 + src/sys/timerfd.rs | 10 ++++++++++ 3 files changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index daa8b6d940..c87abc4b8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added `mq_timedreceive` to `::nix::mqueue`. ([#1966])(https://github.com/nix-rust/nix/pull/1966) - Added `LocalPeerPid` to `nix::sys::socket::sockopt` for macOS. ([#1967](https://github.com/nix-rust/nix/pull/1967)) +- Added `TFD_TIMER_CANCEL_ON_SET` to `::nix::sys::time::TimerSetTimeFlags` on Linux and Android. + ([#2040](https://github.com/nix-rust/nix/pull/2040)) ### Changed diff --git a/src/sys/time.rs b/src/sys/time.rs index a1894e4d54..30ee5fd1b5 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -93,6 +93,7 @@ pub(crate) mod timer { /// Flags that are used for arming the timer. pub struct TimerSetTimeFlags: libc::c_int { const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME; + const TFD_TIMER_CANCEL_ON_SET = libc::TFD_TIMER_CANCEL_ON_SET; } } #[cfg(any( diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs index 90a05a8ccd..c4337c9dfa 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -135,6 +135,13 @@ impl TimerFd { /// Then the one shot TimeSpec and the delay TimeSpec of the delayed /// interval are going to be interpreted as absolute. /// + /// # Cancel on a clock change + /// + /// If you set a `TFD_TIMER_CANCEL_ON_SET` alongside `TFD_TIMER_ABSTIME` + /// and the clock for this timer is `CLOCK_REALTIME` or `CLOCK_REALTIME_ALARM`, + /// then this timer is marked as cancelable if the real-time clock undergoes + /// a discontinuous change. + /// /// # Disabling alarms /// /// Note: Only one alarm can be set for any given timer. Setting a new alarm @@ -202,6 +209,9 @@ impl TimerFd { /// Note: If the alarm is unset, then you will wait forever. pub fn wait(&self) -> Result<()> { while let Err(e) = read(self.fd.as_fd().as_raw_fd(), &mut [0u8; 8]) { + if e == Errno::ECANCELED { + break; + } if e != Errno::EINTR { return Err(e); } From 9514900a6ae3131a2c90709dcbebbb35e512acb7 Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 21 May 2023 09:35:01 +0200 Subject: [PATCH 296/358] Update memoffset to 0.9 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 18b3a47d2b..ee3882acfc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } static_assertions = "1" -memoffset = { version = "0.8", optional = true } +memoffset = { version = "0.9", optional = true } [features] default = [ From e42c3589a3c17e69043bc76c9a087acf6e5cb83e Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 21 May 2023 08:52:42 -0600 Subject: [PATCH 297/358] Clippy cleanup: fix the new clippy::non_minimal_cfg lint --- src/fcntl.rs | 4 ++-- src/sys/socket/mod.rs | 2 +- src/sys/socket/sockopt.rs | 4 ++-- test/test_fcntl.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/fcntl.rs b/src/fcntl.rs index a9ef9ad1bc..d799ff378e 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -701,7 +701,7 @@ pub fn vmsplice( } } -#[cfg(any(target_os = "linux"))] +#[cfg(target_os = "linux")] #[cfg(feature = "fs")] libc_bitflags!( /// Mode argument flags for fallocate determining operation performed on a given range. @@ -741,7 +741,7 @@ feature! { /// /// Allows the caller to directly manipulate the allocated disk space for the /// file referred to by fd. -#[cfg(any(target_os = "linux"))] +#[cfg(target_os = "linux")] #[cfg(feature = "fs")] pub fn fallocate( fd: RawFd, diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 9b6f18efb0..1e3438eab9 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -236,7 +236,7 @@ impl SockProtocol { #[allow(non_upper_case_globals)] pub const CanBcm: SockProtocol = SockProtocol::NetlinkUserSock; // Matches libc::CAN_BCM } -#[cfg(any(target_os = "linux"))] +#[cfg(target_os = "linux")] libc_bitflags! { /// Configuration flags for `SO_TIMESTAMPING` interface /// diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index a18b5905ae..d5bcda4c13 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -683,7 +683,7 @@ sockopt_impl!( libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6 ); -#[cfg(any(target_os = "linux"))] +#[cfg(target_os = "linux")] sockopt_impl!( /// Specifies exact type of timestamping information collected by the kernel /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) @@ -702,7 +702,7 @@ sockopt_impl!( libc::SO_TIMESTAMP, bool ); -#[cfg(all(target_os = "linux"))] +#[cfg(target_os = "linux")] sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message. ReceiveTimestampns, diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 8f50f16b5a..de502d1a33 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -238,7 +238,7 @@ mod linux_android { use nix::unistd::{close, pipe, read, write}; use tempfile::tempfile; - #[cfg(any(target_os = "linux"))] + #[cfg(target_os = "linux")] use tempfile::NamedTempFile; use crate::*; @@ -355,7 +355,7 @@ mod linux_android { close(wr).unwrap(); } - #[cfg(any(target_os = "linux"))] + #[cfg(target_os = "linux")] #[test] fn test_fallocate() { let tmp = NamedTempFile::new().unwrap(); From ee2e1deff805692c4a4cc9172b458b8a5edca44f Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Wed, 26 Apr 2023 12:13:29 +0100 Subject: [PATCH 298/358] Use .bits() method rather than field for bitflags. --- src/mount/bsd.rs | 4 ++-- src/mount/linux.rs | 4 ++-- src/mqueue.rs | 2 +- src/sys/stat.rs | 4 ++-- src/unistd.rs | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs index d124f1f9ab..dbff654112 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd.rs @@ -392,7 +392,7 @@ impl<'a> Nmount<'a> { let niov = self.iov.len() as c_uint; let iovp = self.iov.as_mut_ptr() as *mut libc::iovec; - let res = unsafe { libc::nmount(iovp, niov, flags.bits) }; + let res = unsafe { libc::nmount(iovp, niov, flags.bits()) }; match Errno::result(res) { Ok(_) => Ok(()), Err(error) => { @@ -446,7 +446,7 @@ where P: ?Sized + NixPath, { let res = mountpoint.with_nix_path(|cstr| unsafe { - libc::unmount(cstr.as_ptr(), flags.bits) + libc::unmount(cstr.as_ptr(), flags.bits()) })?; Errno::result(res).map(drop) diff --git a/src/mount/linux.rs b/src/mount/linux.rs index 5f19a5f1f7..e987603786 100644 --- a/src/mount/linux.rs +++ b/src/mount/linux.rs @@ -132,7 +132,7 @@ pub fn mount< s, t.as_ptr(), ty, - flags.bits, + flags.bits(), d as *const libc::c_void, ) }) @@ -156,7 +156,7 @@ pub fn umount(target: &P) -> Result<()> { /// See also [`umount`](https://man7.org/linux/man-pages/man2/umount.2.html) pub fn umount2(target: &P, flags: MntFlags) -> Result<()> { let res = target.with_nix_path(|cstr| unsafe { - libc::umount2(cstr.as_ptr(), flags.bits) + libc::umount2(cstr.as_ptr(), flags.bits()) })?; Errno::result(res).map(drop) diff --git a/src/mqueue.rs b/src/mqueue.rs index ac183eb55a..7ce7d5e8bc 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -139,7 +139,7 @@ impl MqAttr { /// Open a message queue /// /// See also [`mq_open(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html) -// The mode.bits cast is only lossless on some OSes +// The mode.bits() cast is only lossless on some OSes #[allow(clippy::cast_lossless)] pub fn mq_open( name: &CStr, diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 78203bfbe3..7e51c03a3f 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -177,7 +177,7 @@ pub fn mknod( dev: dev_t, ) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { - libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev) + libc::mknod(cstr.as_ptr(), kind.bits() | perm.bits() as mode_t, dev) })?; Errno::result(res).map(drop) @@ -202,7 +202,7 @@ pub fn mknodat( libc::mknodat( dirfd, cstr.as_ptr(), - kind.bits | perm.bits() as mode_t, + kind.bits() | perm.bits() as mode_t, dev, ) })?; diff --git a/src/unistd.rs b/src/unistd.rs index 7230c3370f..afa80e9b9d 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -3375,7 +3375,7 @@ feature! { /// See [access(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html) pub fn access(path: &P, amode: AccessFlags) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { - libc::access(cstr.as_ptr(), amode.bits) + libc::access(cstr.as_ptr(), amode.bits()) })?; Errno::result(res).map(drop) } @@ -3422,7 +3422,7 @@ pub fn faccessat( ))] pub fn eaccess(path: &P, mode: AccessFlags) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { - libc::eaccess(cstr.as_ptr(), mode.bits) + libc::eaccess(cstr.as_ptr(), mode.bits()) })?; Errno::result(res).map(drop) } From 2e5bc8b2038b6847baad1cf11b0697b5bc67a028 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Wed, 26 Apr 2023 14:04:44 +0100 Subject: [PATCH 299/358] Update to bitflags 2.3.1. This is a new major version and requires some code changes. --- Cargo.toml | 2 +- src/macros.rs | 1 + src/sys/termios.rs | 2 +- src/sys/time.rs | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ee3882acfc..243f309d58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ targets = [ [dependencies] libc = { version = "0.2.141", features = ["extra_traits"] } -bitflags = "1.1" +bitflags = "2.3.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } static_assertions = "1" diff --git a/src/macros.rs b/src/macros.rs index 5d83a5ac3c..2d3564416a 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -63,6 +63,7 @@ macro_rules! libc_bitflags { } ) => { ::bitflags::bitflags! { + #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] $(#[$outer])* pub struct $BitFlags: $T { $( diff --git a/src/sys/termios.rs b/src/sys/termios.rs index b0286f51f1..0f1c995090 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -309,7 +309,7 @@ impl Termios { let termios = *self.inner.borrow_mut(); self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag); self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag); - self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag); + self.control_flags = ControlFlags::from_bits_retain(termios.c_cflag); self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag); self.control_chars = termios.c_cc; #[cfg(any( diff --git a/src/sys/time.rs b/src/sys/time.rs index 30ee5fd1b5..a0160e21ff 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -91,6 +91,7 @@ pub(crate) mod timer { #[cfg(any(target_os = "android", target_os = "linux"))] bitflags! { /// Flags that are used for arming the timer. + #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct TimerSetTimeFlags: libc::c_int { const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME; const TFD_TIMER_CANCEL_ON_SET = libc::TFD_TIMER_CANCEL_ON_SET; @@ -104,6 +105,7 @@ pub(crate) mod timer { ))] bitflags! { /// Flags that are used for arming the timer. + #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct TimerSetTimeFlags: libc::c_int { const TFD_TIMER_ABSTIME = libc::TIMER_ABSTIME; } From 1a89311dd5dde148d70709ce49913a283f46b39f Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Wed, 26 Apr 2023 14:31:55 +0100 Subject: [PATCH 300/358] Use repr(transparent) for bitflags. --- src/macros.rs | 1 + src/sys/statvfs.rs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macros.rs b/src/macros.rs index 2d3564416a..adff2bc6be 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -64,6 +64,7 @@ macro_rules! libc_bitflags { ) => { ::bitflags::bitflags! { #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + #[repr(transparent)] $(#[$outer])* pub struct $BitFlags: $T { $( diff --git a/src/sys/statvfs.rs b/src/sys/statvfs.rs index c2c86624c8..35424e5e27 100644 --- a/src/sys/statvfs.rs +++ b/src/sys/statvfs.rs @@ -12,7 +12,6 @@ use crate::{errno::Errno, NixPath, Result}; #[cfg(not(target_os = "redox"))] libc_bitflags!( /// File system mount Flags - #[repr(C)] #[derive(Default)] pub struct FsFlags: c_ulong { /// Read Only From aef996a454467f188348447707e8e7598b6c4e98 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Mon, 22 May 2023 11:23:39 +0100 Subject: [PATCH 301/358] Fix warnings. --- src/sys/event.rs | 6 +++--- test/sys/test_socket.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sys/event.rs b/src/sys/event.rs index 5dcf121ae2..ec7f7e277a 100644 --- a/src/sys/event.rs +++ b/src/sys/event.rs @@ -71,7 +71,7 @@ impl Kqueue { timeout as *const timespec } else { ptr::null() - } + }, ) }; Errno::result(res).map(|r| r as usize) @@ -86,7 +86,7 @@ impl Kqueue { target_os = "openbsd" ))] type type_of_udata = *mut libc::c_void; -#[cfg(any(target_os = "netbsd"))] +#[cfg(target_os = "netbsd")] type type_of_udata = intptr_t; #[cfg(target_os = "netbsd")] @@ -171,7 +171,7 @@ libc_enum! { ))] #[doc(hidden)] pub type type_of_event_flag = u16; -#[cfg(any(target_os = "netbsd"))] +#[cfg(target_os = "netbsd")] #[doc(hidden)] pub type type_of_event_flag = u32; libc_bitflags! { diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 0a8d0544cb..9fb7e89a57 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -10,7 +10,7 @@ use std::path::Path; use std::slice; use std::str::FromStr; -#[cfg(any(target_os = "linux"))] +#[cfg(target_os = "linux")] #[cfg_attr(qemu, ignore)] #[test] pub fn test_timestamping() { @@ -2082,7 +2082,7 @@ pub fn test_vsock() { // 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"))] +#[cfg(target_os = "linux")] #[test] fn test_recvmsg_timestampns() { use nix::sys::socket::*; @@ -2137,7 +2137,7 @@ fn test_recvmsg_timestampns() { // 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"))] +#[cfg(target_os = "linux")] #[test] fn test_recvmmsg_timestampns() { use nix::sys::socket::*; From c80828e9dce12c5ae49fcb9510786a1d5e96aaa3 Mon Sep 17 00:00:00 2001 From: Jarred Allen Date: Mon, 22 May 2023 11:45:01 -0700 Subject: [PATCH 302/358] PR suggestion: Set the length later instead of using `from_raw` --- src/sys/socket/addr.rs | 101 +++++++++++++++++++++++++++++++++++++++-- src/sys/socket/mod.rs | 30 ++++++------ 2 files changed, 114 insertions(+), 17 deletions(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 8c5a56fe05..12cdc7a41d 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -763,6 +763,22 @@ impl SockaddrLike for UnixAddr { { mem::size_of::() as libc::socklen_t } + + unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + cfg_if! { + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "redox", + ))] { + self.sun_len = new_length as u8; + } else { + self.sun.sun_len = new_length as u8; + } + }; + Ok(()) + } } impl AsRef for UnixAddr { @@ -912,8 +928,30 @@ pub trait SockaddrLike: private::SockaddrLikePriv { { mem::size_of::() as libc::socklen_t } + + /// Set the length of this socket address + /// + /// This method may only be called on socket addresses whose lenghts are dynamic, and it + /// returns an error if called on a type whose length is static. + /// + /// # Safety + /// + /// `new_length` must be a valid length for this type of address. Specifically, reads of that + /// length from `self` must be valid. + unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic>; } +/// The error returned by [`SockaddrLike::set_length`] on an address whose length is statically +/// fixed. +#[derive(Copy, Clone, Debug)] +pub struct SocketAddressLengthNotDynamic; +impl fmt::Display for SocketAddressLengthNotDynamic { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Attempted to set length on socket whose length is statically fixed") + } +} +impl std::error::Error for SocketAddressLengthNotDynamic {} + impl private::SockaddrLikePriv for () { fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { ptr::null_mut() @@ -946,6 +984,10 @@ impl SockaddrLike for () { fn len(&self) -> libc::socklen_t { 0 } + + unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + Err(SocketAddressLengthNotDynamic) + } } /// An IPv4 socket address @@ -1015,6 +1057,10 @@ impl SockaddrLike for SockaddrIn { } Some(Self(ptr::read_unaligned(addr as *const _))) } + + unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + Err(SocketAddressLengthNotDynamic) + } } #[cfg(feature = "net")] @@ -1134,6 +1180,10 @@ impl SockaddrLike for SockaddrIn6 { } Some(Self(ptr::read_unaligned(addr as *const _))) } + + unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + Err(SocketAddressLengthNotDynamic) + } } #[cfg(feature = "net")] @@ -1361,6 +1411,27 @@ impl SockaddrLike for SockaddrStorage { None => mem::size_of_val(self) as libc::socklen_t, } } + + unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + match self.as_unix_addr_mut() { + Some(addr) => { + cfg_if! { + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "redox", + ))] { + addr.sun_len = new_length as u8; + } else { + addr.sun.sun_len = new_length as u8; + } + } + Ok(()) + }, + None => Err(SocketAddressLengthNotDynamic), + } + } } macro_rules! accessors { @@ -1754,6 +1825,10 @@ pub mod netlink { } Some(Self(ptr::read_unaligned(addr as *const _))) } + + unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + Err(SocketAddressLengthNotDynamic) + } } impl AsRef for NetlinkAddr { @@ -1803,6 +1878,10 @@ pub mod alg { } Some(Self(ptr::read_unaligned(addr as *const _))) } + + unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + Err(SocketAddressLengthNotDynamic) + } } impl AsRef for AlgAddr { @@ -1902,7 +1981,7 @@ pub mod sys_control { use std::{fmt, mem, ptr}; use std::os::unix::io::RawFd; use crate::{Errno, Result}; - use super::{private, SockaddrLike}; + use super::{private, SockaddrLike, SocketAddressLengthNotDynamic}; // FIXME: Move type into `libc` #[repr(C)] @@ -1943,6 +2022,10 @@ pub mod sys_control { } Some(Self(ptr::read_unaligned(addr as *const _))) } + + unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + Err(SocketAddressLengthNotDynamic) + } } impl AsRef for SysControlAddr { @@ -2007,7 +2090,7 @@ pub mod sys_control { mod datalink { feature! { #![feature = "net"] - use super::{fmt, mem, private, ptr, SockaddrLike}; + use super::{fmt, mem, private, ptr, SockaddrLike, SocketAddressLengthNotDynamic}; /// Hardware Address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -2085,6 +2168,10 @@ mod datalink { } Some(Self(ptr::read_unaligned(addr as *const _))) } + + unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + Err(SocketAddressLengthNotDynamic) + } } impl AsRef for LinkAddr { @@ -2110,7 +2197,7 @@ mod datalink { mod datalink { feature! { #![feature = "net"] - use super::{fmt, mem, private, ptr, SockaddrLike}; + use super::{fmt, mem, private, ptr, SockaddrLike, SocketAddressLengthNotDynamic}; /// Hardware Address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -2209,6 +2296,10 @@ mod datalink { } Some(Self(ptr::read_unaligned(addr as *const _))) } + + unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + Err(SocketAddressLengthNotDynamic) + } } impl AsRef for LinkAddr { @@ -2257,6 +2348,10 @@ pub mod vsock { } Some(Self(ptr::read_unaligned(addr as *const _))) } + + unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + Err(SocketAddressLengthNotDynamic) + } } impl AsRef for VsockAddr { diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 1bbfa5414f..78b7e8b08c 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1627,7 +1627,7 @@ impl MultiHeaders { None => (std::ptr::null(), 0), }; let msg_hdr = unsafe { - pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, ::as_mut_ptr(address.assume_init_mut()).cast()) + pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.assume_init_mut()) }; libc::mmsghdr { msg_hdr, @@ -1763,7 +1763,7 @@ where mmsghdr.msg_hdr, mmsghdr.msg_len as isize, self.rmm.msg_controllen, - Some(address), + address, ) }) } @@ -1916,7 +1916,7 @@ unsafe fn read_mhdr<'a, 'i, S>( mhdr: msghdr, r: isize, msg_controllen: usize, - address: Option, + mut address: S, ) -> RecvMsg<'a, 'i, S> where S: SockaddrLike { @@ -1932,10 +1932,15 @@ unsafe fn read_mhdr<'a, 'i, S>( }.as_ref() }; + // Ignore errors if this socket address has statically-known length + // + // This is to ensure that unix socket addresses have their length set appropriately. + let _ = unsafe { address.set_length(mhdr.msg_namelen as usize) }; + RecvMsg { bytes: r as usize, cmsghdr, - address, + address: Some(address), flags: MsgFlags::from_bits_truncate(mhdr.msg_flags), mhdr, iobufs: std::marker::PhantomData, @@ -1953,19 +1958,19 @@ unsafe fn read_mhdr<'a, 'i, S>( /// headers are not used /// /// Buffers must remain valid for the whole lifetime of msghdr -unsafe fn pack_mhdr_to_receive( +unsafe fn pack_mhdr_to_receive( iov_buffer: *const IoSliceMut, iov_buffer_len: usize, cmsg_buffer: *const u8, cmsg_capacity: usize, - address: *mut libc::sockaddr_storage, -) -> msghdr { + address: *mut S, +) -> msghdr where S: SockaddrLike { // Musl's msghdr has private fields, so this is the only way to // initialize it. let mut mhdr = mem::MaybeUninit::::zeroed(); let p = mhdr.as_mut_ptr(); (*p).msg_name = address as *mut c_void; - (*p).msg_namelen = mem::size_of::() as u32; + (*p).msg_namelen = S::size(); (*p).msg_iov = iov_buffer as *mut iovec; (*p).msg_iovlen = iov_buffer_len as _; (*p).msg_control = cmsg_buffer as *mut c_void; @@ -2047,23 +2052,20 @@ pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'i where S: SockaddrLike + 'a, 'inner: 'outer { - let mut address: libc::sockaddr_storage = unsafe { mem::MaybeUninit::zeroed().assume_init() }; - let address_ptr: *mut libc::sockaddr_storage = &mut address as *mut libc::sockaddr_storage; + let mut address: mem::MaybeUninit = mem::MaybeUninit::zeroed(); let (msg_control, msg_controllen) = cmsg_buffer.as_mut() .map(|v| (v.as_mut_ptr(), v.capacity())) .unwrap_or((ptr::null_mut(), 0)); let mut mhdr = unsafe { - pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address_ptr) + pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr()) }; let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; let r = Errno::result(ret)?; - let address = unsafe { S::from_raw(address_ptr.cast::(), Some(mhdr.msg_namelen)) }; - - Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address) }) + Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init()) }) } } From 72a2f567ee7a378543ba7275dddbc2af1517f58a Mon Sep 17 00:00:00 2001 From: Jarred Allen Date: Mon, 22 May 2023 11:47:24 -0700 Subject: [PATCH 303/358] PR suggestions: use `skip` macro --- test/sys/test_socket.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index b78c8c491a..125edceba5 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -229,8 +229,7 @@ pub fn test_recvmsg_sockaddr_un() { MsgFlags::empty(), Some(&sockaddr), ) { - print!("Couldn't send ({e:?}), so skipping test"); - return; + crate::skip!("Couldn't send ({e:?}), so skipping test"); } // Receive the message From e5bd9ba193fe9e30108e0197d09aa8aa48c95d88 Mon Sep 17 00:00:00 2001 From: Jarred Allen Date: Mon, 22 May 2023 12:43:03 -0700 Subject: [PATCH 304/358] Fixup accidentally-introduced changes --- src/sys/socket/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 78b7e8b08c..6690273bfd 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1626,9 +1626,7 @@ impl MultiHeaders { Some(v) => ((&v[ix * msg_controllen] as *const u8), msg_controllen), None => (std::ptr::null(), 0), }; - let msg_hdr = unsafe { - pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.assume_init_mut()) - }; + let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.as_mut_ptr()) }; libc::mmsghdr { msg_hdr, msg_len: 0, @@ -1964,7 +1962,10 @@ unsafe fn pack_mhdr_to_receive( cmsg_buffer: *const u8, cmsg_capacity: usize, address: *mut S, -) -> msghdr where S: SockaddrLike { +) -> msghdr + where + S: SockaddrLike +{ // Musl's msghdr has private fields, so this is the only way to // initialize it. let mut mhdr = mem::MaybeUninit::::zeroed(); @@ -2052,7 +2053,7 @@ pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'i where S: SockaddrLike + 'a, 'inner: 'outer { - let mut address: mem::MaybeUninit = mem::MaybeUninit::zeroed(); + let mut address = mem::MaybeUninit::zeroed(); let (msg_control, msg_controllen) = cmsg_buffer.as_mut() .map(|v| (v.as_mut_ptr(), v.capacity())) From ff0fb3d18776151d0c8694f564ffb21164d1e17f Mon Sep 17 00:00:00 2001 From: Jarred Allen Date: Mon, 22 May 2023 12:46:01 -0700 Subject: [PATCH 305/358] Remove redundant `unsafe` block --- src/sys/socket/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 6690273bfd..ffab9741e1 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1933,7 +1933,7 @@ unsafe fn read_mhdr<'a, 'i, S>( // Ignore errors if this socket address has statically-known length // // This is to ensure that unix socket addresses have their length set appropriately. - let _ = unsafe { address.set_length(mhdr.msg_namelen as usize) }; + let _ = address.set_length(mhdr.msg_namelen as usize); RecvMsg { bytes: r as usize, From 6c91a149327c987a2644d2a662b49ef7339485c9 Mon Sep 17 00:00:00 2001 From: Chris Spencer Date: Fri, 2 Jun 2023 15:21:29 +0100 Subject: [PATCH 306/358] Fix typo in comment --- src/sys/socket/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 1e3438eab9..84812205e7 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -247,9 +247,9 @@ libc_bitflags! { SOF_TIMESTAMPING_SOFTWARE; /// Report hardware timestamps as generated by SOF_TIMESTAMPING_TX_HARDWARE when available. SOF_TIMESTAMPING_RAW_HARDWARE; - /// Collect transmiting timestamps as reported by hardware + /// Collect transmitting timestamps as reported by hardware SOF_TIMESTAMPING_TX_HARDWARE; - /// Collect transmiting timestamps as reported by software + /// Collect transmitting timestamps as reported by software SOF_TIMESTAMPING_TX_SOFTWARE; /// Collect receiving timestamps as reported by hardware SOF_TIMESTAMPING_RX_HARDWARE; From d66c0c1d5a8c7515f699428d063f179328aff32e Mon Sep 17 00:00:00 2001 From: Chris Spencer Date: Fri, 2 Jun 2023 15:28:12 +0100 Subject: [PATCH 307/358] Enable additional socket timestamping flags --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c87abc4b8c..7cbd8d37c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added `LocalPeerPid` to `nix::sys::socket::sockopt` for macOS. ([#1967](https://github.com/nix-rust/nix/pull/1967)) - Added `TFD_TIMER_CANCEL_ON_SET` to `::nix::sys::time::TimerSetTimeFlags` on Linux and Android. ([#2040](https://github.com/nix-rust/nix/pull/2040)) +- Added `SOF_TIMESTAMPING_OPT_ID` and `SOF_TIMESTAMPING_OPT_TSONLY` to `nix::sys::socket::TimestampingFlag`. + ([#2048](https://github.com/nix-rust/nix/pull/2048)) ### Changed diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 84812205e7..5ecfbe3243 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -255,6 +255,10 @@ libc_bitflags! { SOF_TIMESTAMPING_RX_HARDWARE; /// Collect receiving timestamps as reported by software SOF_TIMESTAMPING_RX_SOFTWARE; + /// Generate a unique identifier along with each transmitted packet + SOF_TIMESTAMPING_OPT_ID; + /// Return transmit timestamps alongside an empty packet instead of the original packet + SOF_TIMESTAMPING_OPT_TSONLY; } } From 3147e67b6797ff56bee5001ce61cf508eb8129ea Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 5 Jun 2023 16:59:13 -0600 Subject: [PATCH 308/358] Update CHANGELOG for patch release 0.26.2 [skip ci] --- CHANGELOG.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c87abc4b8c..22a968dcc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,9 +36,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#2012](https://github.com/nix-rust/nix/pull/2012)) ### Fixed -- Fix `SockaddrIn6` bug that was swapping flowinfo and scope_id byte ordering. - ([#1964](https://github.com/nix-rust/nix/pull/1964)) -- Fix: send ETH_P_ALL in htons format +- Fix: send `ETH_P_ALL` in htons format ([#1925](https://github.com/nix-rust/nix/pull/1925)) ### Removed @@ -51,6 +49,14 @@ This project adheres to [Semantic Versioning](https://semver.org/). `nix::sys::signalfd::SignalFd` instead. ([#1938](https://github.com/nix-rust/nix/pull/1938)) +## [0.26.2] - 2023-01-18 + +### Fixed + +- Fix `SockaddrIn6` bug that was swapping `flowinfo` and `scope_id` byte + ordering. + ([#1964](https://github.com/nix-rust/nix/pull/1964)) + ## [0.26.1] - 2022-11-29 ### Fixed - Fix UB with `sys::socket::sockopt::SockType` using `SOCK_PACKET`. From 9b331316963e14c249570f5be9a65bb3269c41fd Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 5 Jun 2023 17:02:36 -0600 Subject: [PATCH 309/358] Fix CI with the latest Rustup The latest Rustup does not allow the toolchain specification to be blank, which we were using. Fix it by ensuring that only one toolchain is ever installed in a given task, so we won't need to use the +$TOOLCHAIN with cargo. --- .cirrus.yml | 48 ++++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 1ffe4611f4..f3624f4bde 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -8,29 +8,28 @@ env: RUSTFLAGS: -D warnings RUSTDOCFLAGS: -D warnings TOOL: cargo - # The MSRV - TOOLCHAIN: 1.63.0 + MSRV: 1.63.0 ZFLAGS: # Tests that don't require executing the build binaries build: &BUILD build_script: - . $HOME/.cargo/env || true - - $TOOL +$TOOLCHAIN -Vv - - rustc +$TOOLCHAIN -Vv - - $TOOL +$TOOLCHAIN $BUILD $ZFLAGS --target $TARGET --all-targets - - $TOOL +$TOOLCHAIN doc $ZFLAGS --no-deps --target $TARGET - - $TOOL +$TOOLCHAIN clippy $ZFLAGS --target $TARGET --all-targets -- -D warnings + - $TOOL -Vv + - rustc -Vv + - $TOOL $BUILD $ZFLAGS --target $TARGET --all-targets + - $TOOL doc $ZFLAGS --no-deps --target $TARGET + - $TOOL clippy $ZFLAGS --target $TARGET --all-targets -- -D warnings - if [ -z "$NOHACK" ]; then mkdir -p $HOME/.cargo/bin; export PATH=$HOME/.cargo/bin:$PATH; fi - if [ -z "$NOHACK" ]; then curl -LsSf https://github.com/taiki-e/cargo-hack/releases/latest/download/cargo-hack-${HOST:-$TARGET}.tar.gz | tar xzf - -C ~/.cargo/bin; fi - - if [ -z "$NOHACK" ]; then $TOOL +$TOOLCHAIN hack $ZFLAGS check --target $TARGET --each-feature; fi + - if [ -z "$NOHACK" ]; then $TOOL hack $ZFLAGS check --target $TARGET --each-feature; fi # Tests that do require executing the binaries test: &TEST << : *BUILD test_script: - . $HOME/.cargo/env || true - - $TOOL +$TOOLCHAIN test --target $TARGET + - $TOOL 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 @@ -52,10 +51,10 @@ task: setup_script: - kldload mqueuefs - fetch https://sh.rustup.rs -o rustup.sh - - sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN + - sh rustup.sh -y --profile=minimal --default-toolchain $MSRV - . $HOME/.cargo/env - rustup target add i686-unknown-freebsd - - rustup component add --toolchain $TOOLCHAIN clippy + - rustup component add clippy << : *TEST i386_test_script: - . $HOME/.cargo/env @@ -76,9 +75,9 @@ task: image: ghcr.io/cirruslabs/macos-ventura-base:latest setup_script: - curl --proto '=https' --tlsv1.2 -sSf -o rustup.sh https://sh.rustup.rs - - sh rustup.sh -y --profile=minimal --default-toolchain $TOOLCHAIN + - sh rustup.sh -y --profile=minimal --default-toolchain $MSRV - . $HOME/.cargo/env - - rustup component add --toolchain $TOOLCHAIN clippy + - rustup component add clippy << : *TEST before_cache_script: rm -rf $CARGO_HOME/registry/index @@ -129,7 +128,7 @@ 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 $TOOLCHAIN + - sh rustup.sh -y --profile=minimal --default-toolchain $MSRV - . $HOME/.cargo/env - cargo install cross --version 0.2.1 # cross 0.2.2 bumped the MSRV to 1.58.1 << : *TEST @@ -165,9 +164,7 @@ task: image: rust:latest env: TARGET: x86_64-unknown-linux-gnu - TOOLCHAIN: setup_script: - - rustup target add $TARGET - rustup component add clippy << : *TEST before_cache_script: rm -rf $CARGO_HOME/registry/index @@ -242,37 +239,33 @@ task: TARGET: x86_64-unknown-netbsd setup_script: - rustup target add $TARGET - - rustup toolchain install $TOOLCHAIN --profile minimal --target $TARGET - - rustup component add --toolchain $TOOLCHAIN clippy + - rustup component add clippy << : *BUILD before_cache_script: rm -rf $CARGO_HOME/registry/index task: container: - image: rust:1.63.0 + # Redox's MSRV policy is unclear. Until they define it, use nightly. + image: rustlang/rust:nightly env: BUILD: check name: Redox x86_64 env: HOST: x86_64-unknown-linux-gnu TARGET: x86_64-unknown-redox - # Redox's MSRV policy is unclear. Until they define it, use nightly. - TOOLCHAIN: nightly setup_script: - rustup target add $TARGET - - rustup toolchain install $TOOLCHAIN --profile minimal --target $TARGET - - rustup component add --toolchain $TOOLCHAIN clippy + - rustup component add clippy << : *BUILD before_cache_script: rm -rf $CARGO_HOME/registry/index -# Rust Tier 3 targets can't use Rustup +## Rust Tier 3 targets can't use Rustup task: container: image: rustlang/rust:nightly env: BUILD: check HOST: x86_64-unknown-linux-gnu - TOOLCHAIN: nightly ZFLAGS: -Zbuild-std matrix: - name: DragonFly BSD x86_64 @@ -299,7 +292,6 @@ task: name: Minver env: HOST: x86_64-unknown-linux-gnu - TOOLCHAIN: nightly container: image: rustlang/rust:nightly setup_script: @@ -313,5 +305,5 @@ task: name: Rust Formatter container: image: rust:latest - setup_script: rustup +$TOOLCHAIN component add rustfmt - test_script: $TOOL +$TOOLCHAIN fmt --all -- --check **/*.rs + setup_script: rustup component add rustfmt + test_script: cargo fmt --all -- --check **/*.rs From 57cdbed0ab9077e33d48c1b7a6f44b5cc0e67cbd Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 3 Jun 2023 09:31:07 -0400 Subject: [PATCH 310/358] Clippy cleanup: fix the new clippy::non-minimal-cfg lint --- src/sys/event.rs | 4 ++-- test/sys/test_socket.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sys/event.rs b/src/sys/event.rs index 5dcf121ae2..58e48c91d9 100644 --- a/src/sys/event.rs +++ b/src/sys/event.rs @@ -86,7 +86,7 @@ impl Kqueue { target_os = "openbsd" ))] type type_of_udata = *mut libc::c_void; -#[cfg(any(target_os = "netbsd"))] +#[cfg(target_os = "netbsd")] type type_of_udata = intptr_t; #[cfg(target_os = "netbsd")] @@ -171,7 +171,7 @@ libc_enum! { ))] #[doc(hidden)] pub type type_of_event_flag = u16; -#[cfg(any(target_os = "netbsd"))] +#[cfg(target_os = "netbsd")] #[doc(hidden)] pub type type_of_event_flag = u32; libc_bitflags! { diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 0a8d0544cb..9fb7e89a57 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -10,7 +10,7 @@ use std::path::Path; use std::slice; use std::str::FromStr; -#[cfg(any(target_os = "linux"))] +#[cfg(target_os = "linux")] #[cfg_attr(qemu, ignore)] #[test] pub fn test_timestamping() { @@ -2082,7 +2082,7 @@ pub fn test_vsock() { // 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"))] +#[cfg(target_os = "linux")] #[test] fn test_recvmsg_timestampns() { use nix::sys::socket::*; @@ -2137,7 +2137,7 @@ fn test_recvmsg_timestampns() { // 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"))] +#[cfg(target_os = "linux")] #[test] fn test_recvmmsg_timestampns() { use nix::sys::socket::*; From e63dd8fa5944e945557c1605b633345d07aeea27 Mon Sep 17 00:00:00 2001 From: Niels Sascha Reedijk Date: Sat, 17 Jun 2023 15:04:46 +0000 Subject: [PATCH 311/358] Haiku: `speed_t` is defined as `u8` for 32 and 64 bit systems --- src/sys/termios.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/termios.rs b/src/sys/termios.rs index b0286f51f1..694a1338d3 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -355,9 +355,9 @@ libc_enum! { /// enum. /// /// B0 is special and will disable the port. - #[cfg_attr(all(any(target_os = "haiku"), target_pointer_width = "64"), repr(u8))] + #[cfg_attr(target_os = "haiku", repr(u8))] #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))] - #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos", target_os = "haiku"), target_pointer_width = "64")), repr(u32))] + #[cfg_attr(all(not(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64")), not(target_os = "haiku")), repr(u32))] #[non_exhaustive] pub enum BaudRate { B0, From fccc89f9f04a8ec6404defcd5a0882078ae75643 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 27 Jun 2023 17:50:31 -0600 Subject: [PATCH 312/358] Disable the doc test for sys::personality::personality on aarch64 It's failing in CI, and we don't yet know why. Possibly the cloud provider just turned on seccomp. Issue #2060 --- src/sys/personality.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sys/personality.rs b/src/sys/personality.rs index f295a05fad..30231dd7b8 100644 --- a/src/sys/personality.rs +++ b/src/sys/personality.rs @@ -80,7 +80,10 @@ pub fn get() -> Result { /// /// Example: /// -/// ``` +// Disable test on aarch64 until we know why it fails. +// https://github.com/nix-rust/nix/issues/2060 +#[cfg_attr(target_arch = "aarch64", doc = " ```no_run")] +#[cfg_attr(not(target_arch = "aarch64"), doc = " ```")] /// # use nix::sys::personality::{self, Persona}; /// let mut pers = personality::get().unwrap(); /// assert!(!pers.contains(Persona::ADDR_NO_RANDOMIZE)); From 1546857f8c6a8ccd444eb656f4421003a376f5cd Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 27 Jun 2023 17:30:35 -0600 Subject: [PATCH 313/358] For invalid IP address conversions with future Rust versions Rust's standard library no longer guarantees that Ipv4Addr and Ipv6Addr are wrappers around the C types (though for now at least, they are identical on all platforms I'm aware of). So do the conversions explicitly instead of transmuting. Fixes #2053 --- CHANGELOG.md | 5 +++++ Cargo.toml | 1 - src/sys/socket/addr.rs | 16 ++++++---------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c87abc4b8c..7e450900e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,11 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1964](https://github.com/nix-rust/nix/pull/1964)) - Fix: send ETH_P_ALL in htons format ([#1925](https://github.com/nix-rust/nix/pull/1925)) +- Fix potentially invalid conversions in + `SockaddrIn::from`, + `SockaddrIn6::from`, `IpMembershipRequest::new`, and + `Ipv6MembershipRequest::new` with future Rust versions. + ([#2061](https://github.com/nix-rust/nix/pull/2061)) ### Removed diff --git a/Cargo.toml b/Cargo.toml index ee3882acfc..996d1d30c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,6 @@ libc = { version = "0.2.141", features = ["extra_traits"] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } -static_assertions = "1" memoffset = { version = "0.9", optional = true } [features] diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 4830974933..2b3a1ed439 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -39,18 +39,17 @@ use std::{fmt, mem, net, ptr, slice}; /// Convert a std::net::Ipv4Addr into the libc form. #[cfg(feature = "net")] pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr { - static_assertions::assert_eq_size!(net::Ipv4Addr, libc::in_addr); - // Safe because both types have the same memory layout, and no fancy Drop - // impls. - unsafe { mem::transmute(addr) } + libc::in_addr { + s_addr: u32::from_ne_bytes(addr.octets()) + } } /// Convert a std::net::Ipv6Addr into the libc form. #[cfg(feature = "net")] pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr { - static_assertions::assert_eq_size!(net::Ipv6Addr, libc::in6_addr); - // Safe because both are Newtype wrappers around the same libc type - unsafe { mem::transmute(*addr) } + libc::in6_addr { + s6_addr: addr.octets() + } } /// These constants specify the protocol family to be used @@ -949,9 +948,6 @@ impl SockaddrLike for () { } /// An IPv4 socket address -// This is identical to net::SocketAddrV4. But the standard library -// doesn't allow direct access to the libc fields, which we need. So we -// reimplement it here. #[cfg(feature = "net")] #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] From 5b2e4af76e7eb9318cc9fdb75a453e1970405d12 Mon Sep 17 00:00:00 2001 From: Jason Dusek Date: Sun, 2 Jul 2023 00:17:58 -0500 Subject: [PATCH 314/358] Address seeming typo in lib.rs I believe the `my` here was intended to be `many` -- but am not sure. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6349d37e0f..8649a34d44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ //! * `fs` - File system functionality //! * `hostname` - Get and set the system's hostname //! * `inotify` - Linux's `inotify` file system notification API -//! * `ioctl` - The `ioctl` syscall, and wrappers for my specific instances +//! * `ioctl` - The `ioctl` syscall, and wrappers for many specific instances //! * `kmod` - Load and unload kernel modules //! * `mman` - Stuff relating to memory management //! * `mount` - Mount and unmount file systems From 45894112298e94af0a6040e2a6c155d8a9bef8ed Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 15 Jul 2023 11:33:24 -0600 Subject: [PATCH 315/358] Clippy cleanup --- src/mount/bsd.rs | 2 +- src/sys/socket/addr.rs | 3 +++ src/sys/socket/mod.rs | 2 +- test/test_fcntl.rs | 2 +- test/test_sendfile.rs | 8 ++++---- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs index dbff654112..6ed2dc7fbf 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd.rs @@ -391,7 +391,7 @@ impl<'a> Nmount<'a> { }); let niov = self.iov.len() as c_uint; - let iovp = self.iov.as_mut_ptr() as *mut libc::iovec; + let iovp = self.iov.as_mut_ptr(); let res = unsafe { libc::nmount(iovp, niov, flags.bits()) }; match Errno::result(res) { Ok(_) => Ok(()), diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 2b3a1ed439..ff222b5e2e 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -484,6 +484,7 @@ enum UnixAddrKind<'a> { } impl<'a> UnixAddrKind<'a> { /// Safety: sun & sun_len must be valid + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self { assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path)); let path_len = @@ -520,6 +521,7 @@ impl<'a> UnixAddrKind<'a> { impl UnixAddr { /// Create a new sockaddr_un representing a filesystem path. + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms pub fn new(path: &P) -> Result { path.with_nix_path(|cstr| unsafe { let mut ret = libc::sockaddr_un { @@ -567,6 +569,7 @@ impl UnixAddr { /// processes to communicate with processes having a different filesystem view. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms pub fn new_abstract(path: &[u8]) -> Result { unsafe { let mut ret = libc::sockaddr_un { diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 1e3438eab9..c5a897c329 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -2234,7 +2234,7 @@ pub fn recvfrom( Ok(( ret, T::from_raw( - addr.assume_init().as_ptr() as *const sockaddr, + addr.assume_init().as_ptr(), Some(len), ), )) diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index de502d1a33..31df6d038f 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -340,7 +340,7 @@ mod linux_android { let buf1 = b"abcdef"; let buf2 = b"defghi"; - let iovecs = vec![IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])]; + let iovecs = [IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])]; let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap(); diff --git a/test/test_sendfile.rs b/test/test_sendfile.rs index c6ac6e6fa1..b85e030fd3 100644 --- a/test/test_sendfile.rs +++ b/test/test_sendfile.rs @@ -72,10 +72,10 @@ fn test_sendfile64_linux() { fn test_sendfile_freebsd() { // Declare the content let header_strings = - vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; + ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; let body = "Xabcdef123456"; let body_offset = 1; - let trailer_strings = vec!["\n", "Served by Make Believe\n"]; + let trailer_strings = ["\n", "Served by Make Believe\n"]; // Write the body to a file let mut tmp = tempfile().unwrap(); @@ -123,10 +123,10 @@ fn test_sendfile_freebsd() { fn test_sendfile_dragonfly() { // Declare the content let header_strings = - vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; + ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; let body = "Xabcdef123456"; let body_offset = 1; - let trailer_strings = vec!["\n", "Served by Make Believe\n"]; + let trailer_strings = ["\n", "Served by Make Believe\n"]; // Write the body to a file let mut tmp = tempfile().unwrap(); From 87190dab193d3ceaf8443556adfeba35177bdd24 Mon Sep 17 00:00:00 2001 From: Chris Spencer Date: Tue, 6 Jun 2023 10:57:08 +0100 Subject: [PATCH 316/358] Enable socket timestamping options on Android --- CHANGELOG.md | 1 + Cargo.toml | 2 +- src/sys/socket/mod.rs | 14 +++++++------- src/sys/socket/sockopt.rs | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d865659c6c..94927bd6ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#2040](https://github.com/nix-rust/nix/pull/2040)) - Added `SOF_TIMESTAMPING_OPT_ID` and `SOF_TIMESTAMPING_OPT_TSONLY` to `nix::sys::socket::TimestampingFlag`. ([#2048](https://github.com/nix-rust/nix/pull/2048)) +- Enabled socket timestamping options on Android. ([#2077](https://github.com/nix-rust/nix/pull/2077)) ### Changed diff --git a/Cargo.toml b/Cargo.toml index 831aeeb06c..a40d250ebf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.141", features = ["extra_traits"] } +libc = { version = "0.2.147", features = ["extra_traits"] } bitflags = "2.3.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index e6665aaf14..06b93c6f71 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1,7 +1,7 @@ //! Socket interface functions //! //! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html) -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "android", target_os = "linux"))] #[cfg(feature = "uio")] use crate::sys::time::TimeSpec; #[cfg(not(target_os = "redox"))] @@ -236,7 +236,7 @@ impl SockProtocol { #[allow(non_upper_case_globals)] pub const CanBcm: SockProtocol = SockProtocol::NetlinkUserSock; // Matches libc::CAN_BCM } -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "android", target_os = "linux"))] libc_bitflags! { /// Configuration flags for `SO_TIMESTAMPING` interface /// @@ -737,12 +737,12 @@ pub enum ControlMessageOwned { /// A set of nanosecond resolution timestamps /// /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - #[cfg(all(target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux"))] ScmTimestampsns(Timestamps), /// Nanoseconds resolution timestamp /// /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) - #[cfg(all(target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] ScmTimestampns(TimeSpec), #[cfg(any( @@ -839,7 +839,7 @@ pub enum ControlMessageOwned { } /// For representing packet timestamps via `SO_TIMESTAMPING` interface -#[cfg(all(target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "linux"))] #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Timestamps { /// software based timestamp, usually one containing data @@ -892,12 +892,12 @@ impl ControlMessageOwned { let tv: libc::timeval = ptr::read_unaligned(p as *const _); ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) }, - #[cfg(all(target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux"))] (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => { let ts: libc::timespec = ptr::read_unaligned(p as *const _); ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts)) } - #[cfg(all(target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux"))] (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => { let tp = p as *const libc::timespec; let ts: libc::timespec = ptr::read_unaligned(tp); diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index d5bcda4c13..0d675ffb01 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -683,7 +683,7 @@ sockopt_impl!( libc::IP6T_SO_ORIGINAL_DST, libc::sockaddr_in6 ); -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!( /// Specifies exact type of timestamping information collected by the kernel /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) @@ -702,7 +702,7 @@ sockopt_impl!( libc::SO_TIMESTAMP, bool ); -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message. ReceiveTimestampns, From 012e788adcd8a41bdb028b5a6dc6dd1738dd2f9c Mon Sep 17 00:00:00 2001 From: Jarred Allen Date: Mon, 17 Jul 2023 11:33:43 -0700 Subject: [PATCH 317/358] More PR feedback --- CHANGELOG.md | 2 ++ src/sys/socket/addr.rs | 64 ++++++------------------------------------ src/sys/socket/mod.rs | 2 +- 3 files changed, 12 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c87abc4b8c..c6b5dad11f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1964](https://github.com/nix-rust/nix/pull/1964)) - Fix: send ETH_P_ALL in htons format ([#1925](https://github.com/nix-rust/nix/pull/1925)) +- Fix: `recvmsg` now sets the length of the received `sockaddr_un` field + correctly on Linux platforms. ([#2041](https://github.com/nix-rust/nix/pull/2041)) ### Removed diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 12cdc7a41d..88bd6f5a1f 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -931,14 +931,17 @@ pub trait SockaddrLike: private::SockaddrLikePriv { /// Set the length of this socket address /// - /// This method may only be called on socket addresses whose lenghts are dynamic, and it + /// This method may only be called on socket addresses whose lengths are dynamic, and it /// returns an error if called on a type whose length is static. /// /// # Safety /// /// `new_length` must be a valid length for this type of address. Specifically, reads of that /// length from `self` must be valid. - unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic>; + #[doc(hidden)] + unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + Err(SocketAddressLengthNotDynamic) + } } /// The error returned by [`SockaddrLike::set_length`] on an address whose length is statically @@ -984,10 +987,6 @@ impl SockaddrLike for () { fn len(&self) -> libc::socklen_t { 0 } - - unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { - Err(SocketAddressLengthNotDynamic) - } } /// An IPv4 socket address @@ -1057,10 +1056,6 @@ impl SockaddrLike for SockaddrIn { } Some(Self(ptr::read_unaligned(addr as *const _))) } - - unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { - Err(SocketAddressLengthNotDynamic) - } } #[cfg(feature = "net")] @@ -1180,10 +1175,6 @@ impl SockaddrLike for SockaddrIn6 { } Some(Self(ptr::read_unaligned(addr as *const _))) } - - unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { - Err(SocketAddressLengthNotDynamic) - } } #[cfg(feature = "net")] @@ -1415,19 +1406,7 @@ impl SockaddrLike for SockaddrStorage { unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { match self.as_unix_addr_mut() { Some(addr) => { - cfg_if! { - if #[cfg(any(target_os = "android", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "redox", - ))] { - addr.sun_len = new_length as u8; - } else { - addr.sun.sun_len = new_length as u8; - } - } - Ok(()) + addr.set_length(new_length) }, None => Err(SocketAddressLengthNotDynamic), } @@ -1825,10 +1804,6 @@ pub mod netlink { } Some(Self(ptr::read_unaligned(addr as *const _))) } - - unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { - Err(SocketAddressLengthNotDynamic) - } } impl AsRef for NetlinkAddr { @@ -1878,10 +1853,6 @@ pub mod alg { } Some(Self(ptr::read_unaligned(addr as *const _))) } - - unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { - Err(SocketAddressLengthNotDynamic) - } } impl AsRef for AlgAddr { @@ -1981,7 +1952,7 @@ pub mod sys_control { use std::{fmt, mem, ptr}; use std::os::unix::io::RawFd; use crate::{Errno, Result}; - use super::{private, SockaddrLike, SocketAddressLengthNotDynamic}; + use super::{private, SockaddrLike}; // FIXME: Move type into `libc` #[repr(C)] @@ -2022,10 +1993,6 @@ pub mod sys_control { } Some(Self(ptr::read_unaligned(addr as *const _))) } - - unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { - Err(SocketAddressLengthNotDynamic) - } } impl AsRef for SysControlAddr { @@ -2090,7 +2057,7 @@ pub mod sys_control { mod datalink { feature! { #![feature = "net"] - use super::{fmt, mem, private, ptr, SockaddrLike, SocketAddressLengthNotDynamic}; + use super::{fmt, mem, private, ptr, SockaddrLike}; /// Hardware Address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -2168,10 +2135,6 @@ mod datalink { } Some(Self(ptr::read_unaligned(addr as *const _))) } - - unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { - Err(SocketAddressLengthNotDynamic) - } } impl AsRef for LinkAddr { @@ -2197,7 +2160,7 @@ mod datalink { mod datalink { feature! { #![feature = "net"] - use super::{fmt, mem, private, ptr, SockaddrLike, SocketAddressLengthNotDynamic}; + use super::{fmt, mem, private, ptr, SockaddrLike}; /// Hardware Address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -2296,10 +2259,6 @@ mod datalink { } Some(Self(ptr::read_unaligned(addr as *const _))) } - - unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { - Err(SocketAddressLengthNotDynamic) - } } impl AsRef for LinkAddr { @@ -2307,7 +2266,6 @@ mod datalink { &self.0 } } - } } @@ -2348,10 +2306,6 @@ pub mod vsock { } Some(Self(ptr::read_unaligned(addr as *const _))) } - - unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { - Err(SocketAddressLengthNotDynamic) - } } impl AsRef for VsockAddr { diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index c77bc96146..4ca129978e 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -2053,7 +2053,7 @@ pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'i where S: SockaddrLike + 'a, 'inner: 'outer { - let mut address = mem::MaybeUninit::zeroed(); + let mut address = mem::MaybeUninit::uninit(); let (msg_control, msg_controllen) = cmsg_buffer.as_mut() .map(|v| (v.as_mut_ptr(), v.capacity())) From 2378f12dd5a05751a79a0bf8553033c1fbece4f3 Mon Sep 17 00:00:00 2001 From: Jarred Allen Date: Mon, 17 Jul 2023 14:45:43 -0700 Subject: [PATCH 318/358] Correctly let the kernel set the length on BSDs Co-authored-by: Alan Somers --- src/sys/socket/addr.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 0517615e0a..5ec2fb5bca 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -775,8 +775,6 @@ impl SockaddrLike for UnixAddr { target_os = "redox", ))] { self.sun_len = new_length as u8; - } else { - self.sun.sun_len = new_length as u8; } }; Ok(()) From 2d60044196bbcf6c4da187f413e7ddd00f0a2ae0 Mon Sep 17 00:00:00 2001 From: Jarred Allen Date: Mon, 17 Jul 2023 14:57:11 -0700 Subject: [PATCH 319/358] Fix lint --- src/sys/socket/addr.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 5ec2fb5bca..1d86e756f9 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -767,6 +767,8 @@ impl SockaddrLike for UnixAddr { } unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> { + // `new_length` is only used on some platforms, so it must be provided even when not used + #![allow(unused_variables)] cfg_if! { if #[cfg(any(target_os = "android", target_os = "fuchsia", From 625287e50d01b61edc721a5b1d38e5fbd81ed744 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 17 Jul 2023 17:14:30 -0600 Subject: [PATCH 320/358] Remove sigevent support on Fuchsia It triggers UB, which the compiler warns about beginning with 1.41.0. Remove it, due to lack of a Fuchsia maintainer and lack of feedback from the original Fuchsia porter. Fixes #1441 --- CHANGELOG.md | 2 ++ src/sys/signal.rs | 17 +++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56b9b7d9f9..9c7f09dd2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - `nix::sys::signalfd::signalfd` is deprecated. Use `nix::sys::signalfd::SignalFd` instead. ([#1938](https://github.com/nix-rust/nix/pull/1938)) +- Removed `SigEvent` support on Fuchsia, where it was unsound. + ([#2079](https://github.com/nix-rust/nix/pull/2079)) ## [0.26.2] - 2023-01-18 diff --git a/src/sys/signal.rs b/src/sys/signal.rs index efa35ebfd2..a0ad8cd0db 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -13,7 +13,11 @@ use std::os::unix::io::RawFd; use std::ptr; use std::str::FromStr; -#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] +#[cfg(not(any( + target_os = "fuchsia", + target_os = "openbsd", + target_os = "redox" +)))] #[cfg(any(feature = "aio", feature = "signal"))] pub use self::sigevent::*; @@ -979,7 +983,7 @@ pub type type_of_thread_id = libc::pid_t; // 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")))] +#[cfg(not(any(target_os = "fuchsia", target_os = "openbsd", target_os = "redox")))] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum SigevNotify { /// No notification will be delivered @@ -1018,7 +1022,11 @@ pub enum SigevNotify { } } -#[cfg(not(any(target_os = "openbsd", target_os = "redox")))] +#[cfg(not(any( + target_os = "fuchsia", + target_os = "openbsd", + target_os = "redox" +)))] #[cfg_attr(docsrs, doc(cfg(all())))] mod sigevent { feature! { @@ -1052,9 +1060,6 @@ mod sigevent { /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the /// more genuinely useful `sigev_notify_thread_id` - // Allow invalid_value warning on Fuchsia only. - // See https://github.com/nix-rust/nix/issues/1441 - #[cfg_attr(target_os = "fuchsia", allow(invalid_value))] pub fn new(sigev_notify: SigevNotify) -> SigEvent { let mut sev = unsafe { mem::MaybeUninit::::zeroed().assume_init() }; sev.sigev_notify = match sigev_notify { From 7a9826273f961e8d7f2d4b9c862e5afea38c3568 Mon Sep 17 00:00:00 2001 From: Todd Neal Date: Fri, 16 Jun 2023 18:01:51 +0000 Subject: [PATCH 321/358] add vsock support for macOS --- CHANGELOG.md | 1 + src/sys/socket/addr.rs | 37 +++++++++++++++++++++++++---------- src/sys/socket/mod.rs | 2 +- test/sys/test_socket.rs | 43 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56b9b7d9f9..2d44fd1c83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added `SOF_TIMESTAMPING_OPT_ID` and `SOF_TIMESTAMPING_OPT_TSONLY` to `nix::sys::socket::TimestampingFlag`. ([#2048](https://github.com/nix-rust/nix/pull/2048)) - Enabled socket timestamping options on Android. ([#2077](https://github.com/nix-rust/nix/pull/2077)) +- Added vsock support for macOS ([#2056](https://github.com/nix-rust/nix/pull/2056)) ### Changed diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 1d86e756f9..685acf7bb3 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -13,7 +13,7 @@ ))] #[cfg(feature = "net")] pub use self::datalink::LinkAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] pub use self::vsock::VsockAddr; use super::sa_family_t; use crate::errno::Errno; @@ -248,7 +248,7 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] Nfc = libc::AF_NFC, /// VMWare VSockets protocol for hypervisor-guest interaction. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] #[cfg_attr(docsrs, doc(cfg(all())))] Vsock = libc::AF_VSOCK, /// ARPANet IMP addresses @@ -443,7 +443,7 @@ impl AddressFamily { target_os = "openbsd" ))] libc::AF_LINK => Some(AddressFamily::Link), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] libc::AF_VSOCK => Some(AddressFamily::Vsock), _ => None, } @@ -1286,7 +1286,7 @@ pub union SockaddrStorage { sin6: SockaddrIn6, ss: libc::sockaddr_storage, su: UnixAddr, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))] #[cfg_attr(docsrs, doc(cfg(all())))] vsock: VsockAddr, } @@ -1378,7 +1378,7 @@ impl SockaddrLike for SockaddrStorage { libc::AF_SYSTEM => { SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl }) } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))] libc::AF_VSOCK => { VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock }) } @@ -1554,7 +1554,7 @@ impl SockaddrStorage { accessors! {as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr, AddressFamily::System, libc::sockaddr_ctl, sctl} - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] #[cfg_attr(docsrs, doc(cfg(all())))] accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr, AddressFamily::Vsock, libc::sockaddr_vm, vsock} @@ -1604,7 +1604,7 @@ impl fmt::Display for SockaddrStorage { #[cfg(feature = "ioctl")] libc::AF_SYSTEM => self.sctl.fmt(f), libc::AF_UNIX => self.su.fmt(f), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] libc::AF_VSOCK => self.vsock.fmt(f), _ => "

    ".fmt(f), } @@ -1678,7 +1678,7 @@ impl Hash for SockaddrStorage { #[cfg(feature = "ioctl")] libc::AF_SYSTEM => self.sctl.hash(s), libc::AF_UNIX => self.su.hash(s), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] libc::AF_VSOCK => self.vsock.hash(s), _ => self.ss.hash(s), } @@ -1720,7 +1720,7 @@ impl PartialEq for SockaddrStorage { #[cfg(feature = "ioctl")] (libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl, (libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock, _ => false, } @@ -2268,7 +2268,7 @@ mod datalink { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub mod vsock { use super::*; @@ -2314,20 +2314,33 @@ pub mod vsock { } impl PartialEq for VsockAddr { + #[cfg(any(target_os = "android", target_os = "linux"))] fn eq(&self, other: &Self) -> bool { let (inner, other) = (self.0, other.0); (inner.svm_family, inner.svm_cid, inner.svm_port) == (other.svm_family, other.svm_cid, other.svm_port) } + #[cfg(target_os = "macos")] + fn eq(&self, other: &Self) -> bool { + let (inner, other) = (self.0, other.0); + (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len) + == (other.svm_family, other.svm_cid, other.svm_port, inner.svm_len) + } } impl Eq for VsockAddr {} impl Hash for VsockAddr { + #[cfg(any(target_os = "android", target_os = "linux"))] fn hash(&self, s: &mut H) { let inner = self.0; (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s); } + #[cfg(target_os = "macos")] + fn hash(&self, s: &mut H) { + let inner = self.0; + (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len).hash(s); + } } /// VSOCK Address @@ -2342,6 +2355,10 @@ pub mod vsock { addr.svm_cid = cid; addr.svm_port = port; + #[cfg(target_os = "macos")] + { + addr.svm_len = std::mem::size_of::() as u8; + } VsockAddr(addr) } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index c304f6e3c2..c95af80fcb 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -62,7 +62,7 @@ pub use crate::sys::socket::addr::netlink::NetlinkAddr; #[cfg(any(target_os = "ios", target_os = "macos"))] #[cfg(feature = "ioctl")] pub use crate::sys::socket::addr::sys_control::SysControlAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] pub use crate::sys::socket::addr::vsock::VsockAddr; #[cfg(all(feature = "uio", not(target_os = "redox")))] diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index ad7b457ebf..0759dc609a 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -2122,6 +2122,49 @@ pub fn test_vsock() { assert_eq!(addr3.as_ref().svm_port, addr1.port()); } +#[cfg(target_os = "macos")] +#[test] +pub fn test_vsock() { + use nix::sys::socket::SockaddrLike; + use nix::sys::socket::{AddressFamily, VsockAddr}; + use std::mem; + + let port: u32 = 3000; + + // macOS doesn't have a VMADDR_CID_LOCAL, so test with host again + let addr_host = VsockAddr::new(libc::VMADDR_CID_HOST, port); + assert_eq!(addr_host.cid(), libc::VMADDR_CID_HOST); + assert_eq!(addr_host.port(), port); + + let addr_any = VsockAddr::new(libc::VMADDR_CID_ANY, libc::VMADDR_PORT_ANY); + assert_eq!(addr_any.cid(), libc::VMADDR_CID_ANY); + assert_eq!(addr_any.port(), libc::VMADDR_PORT_ANY); + + assert_ne!(addr_host, addr_any); + assert_ne!(calculate_hash(&addr_host), calculate_hash(&addr_any)); + + let addr1 = VsockAddr::new(libc::VMADDR_CID_HOST, port); + let addr2 = VsockAddr::new(libc::VMADDR_CID_HOST, port); + assert_eq!(addr1, addr2); + assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); + + let addr3 = unsafe { + VsockAddr::from_raw( + addr2.as_ref() as *const libc::sockaddr_vm as *const libc::sockaddr, + Some(mem::size_of::().try_into().unwrap()), + ) + } + .unwrap(); + assert_eq!( + addr3.as_ref().svm_family, + AddressFamily::Vsock as libc::sa_family_t + ); + let cid = addr3.as_ref().svm_cid; + let port = addr3.as_ref().svm_port; + assert_eq!(cid, addr1.cid()); + assert_eq!(port, addr1.port()); +} + // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack // of QEMU support is suspected. #[cfg_attr(qemu, ignore)] From 8345f3e6942288a03e221708182ab799e8b65875 Mon Sep 17 00:00:00 2001 From: Qiu Chaofan Date: Wed, 21 Sep 2022 17:28:31 +0800 Subject: [PATCH 322/358] Initial support for AIX operating system --- src/dir.rs | 5 +- src/errno.rs | 247 ++++++++++++++++++++++++++++++++++++++ src/fcntl.rs | 5 +- src/features.rs | 1 + src/pty.rs | 8 +- src/sys/mman.rs | 4 +- src/sys/resource.rs | 4 + src/sys/signal.rs | 50 +++++++- src/sys/socket/addr.rs | 11 +- src/sys/socket/mod.rs | 4 +- src/sys/socket/sockopt.rs | 2 +- src/sys/termios.rs | 23 +++- src/unistd.rs | 14 ++- 13 files changed, 362 insertions(+), 16 deletions(-) diff --git a/src/dir.rs b/src/dir.rs index e1854c35e8..d6b7ea9b7c 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -221,7 +221,8 @@ impl Entry { #[allow(clippy::unnecessary_cast)] pub fn ino(&self) -> u64 { cfg_if! { - if #[cfg(any(target_os = "android", + if #[cfg(any(target_os = "aix", + target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "haiku", @@ -250,6 +251,7 @@ impl Entry { /// `fstat` if this returns `None`. pub fn file_type(&self) -> Option { #[cfg(not(any( + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "haiku" @@ -267,6 +269,7 @@ impl Entry { // illumos, Solaris, and Haiku systems do not have the d_type member at all: #[cfg(any( + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "haiku" diff --git a/src/errno.rs b/src/errno.rs index d8ad28de85..50b35248f8 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -34,6 +34,10 @@ cfg_if! { unsafe fn errno_location() -> *mut c_int { libc::_errnop() } + } else if #[cfg(any(target_os = "aix"))] { + unsafe fn errno_location() -> *mut c_int { + libc::_Errno() + } } } @@ -223,6 +227,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia" @@ -232,6 +237,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia" @@ -241,6 +247,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia" @@ -250,6 +257,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia" @@ -259,6 +267,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia" @@ -268,6 +277,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia" @@ -277,6 +287,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia" @@ -286,6 +297,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia" @@ -421,6 +433,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia" @@ -457,6 +470,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia" @@ -466,6 +480,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia" @@ -482,6 +497,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "fuchsia" ))] EBADMSG => "Not a data message", @@ -492,6 +508,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "fuchsia", target_os = "haiku" ))] @@ -572,6 +589,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia", @@ -582,6 +600,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "fuchsia" @@ -722,6 +741,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "fuchsia" ))] EOWNERDEAD => "Owner died", @@ -732,6 +752,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "linux", target_os = "android", + target_os = "aix", target_os = "fuchsia" ))] ENOTRECOVERABLE => "State not recoverable", @@ -868,6 +889,7 @@ fn desc(errno: Errno) -> &'static str { target_os = "ios", target_os = "openbsd", target_os = "netbsd", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "haiku" @@ -879,6 +901,7 @@ fn desc(errno: Errno) -> &'static str { target_os = "freebsd", target_os = "dragonfly", target_os = "ios", + target_os = "aix", target_os = "openbsd", target_os = "netbsd" ))] @@ -889,6 +912,7 @@ fn desc(errno: Errno) -> &'static str { target_os = "freebsd", target_os = "dragonfly", target_os = "ios", + target_os = "aix", target_os = "openbsd", target_os = "netbsd", target_os = "redox" @@ -903,6 +927,7 @@ fn desc(errno: Errno) -> &'static str { target_os = "openbsd", target_os = "netbsd", target_os = "redox", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "haiku" @@ -917,6 +942,7 @@ fn desc(errno: Errno) -> &'static str { target_os = "openbsd", target_os = "netbsd", target_os = "redox", + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "haiku" @@ -928,6 +954,7 @@ fn desc(errno: Errno) -> &'static str { target_os = "freebsd", target_os = "dragonfly", target_os = "ios", + target_os = "aix", target_os = "openbsd", target_os = "netbsd", target_os = "redox" @@ -1009,6 +1036,7 @@ fn desc(errno: Errno) -> &'static str { target_os = "freebsd", target_os = "dragonfly", target_os = "ios", + target_os = "aix", target_os = "openbsd", target_os = "netbsd", target_os = "redox" @@ -1044,6 +1072,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "aix", target_os = "netbsd", target_os = "redox" ))] @@ -1060,6 +1089,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "aix", target_os = "netbsd", target_os = "redox" ))] @@ -1068,6 +1098,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "aix", target_os = "netbsd", target_os = "redox" ))] @@ -1076,6 +1107,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "aix", target_os = "netbsd", target_os = "redox" ))] @@ -1084,6 +1116,7 @@ fn desc(errno: Errno) -> &'static str { #[cfg(any( target_os = "macos", target_os = "ios", + target_os = "aix", target_os = "illumos", target_os = "solaris" ))] @@ -3131,3 +3164,217 @@ mod consts { } } } + +#[cfg(target_os = "aix")] +mod consts { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr(i32)] + #[non_exhaustive] + pub enum Errno { + UnknownErrno = 0, + EPERM = libc::EPERM, + ENOENT = libc::ENOENT, + ESRCH = libc::ESRCH, + EINTR = libc::EINTR, + EIO = libc::EIO, + ENXIO = libc::ENXIO, + E2BIG = libc::E2BIG, + ENOEXEC = libc::ENOEXEC, + EBADF = libc::EBADF, + ECHILD = libc::ECHILD, + EAGAIN = libc::EAGAIN, + ENOMEM = libc::ENOMEM, + EACCES = libc::EACCES, + EFAULT = libc::EFAULT, + ENOTBLK = libc::ENOTBLK, + EBUSY = libc::EBUSY, + EEXIST = libc::EEXIST, + EXDEV = libc::EXDEV, + ENODEV = libc::ENODEV, + ENOTDIR = libc::ENOTDIR, + EISDIR = libc::EISDIR, + EINVAL = libc::EINVAL, + ENFILE = libc::ENFILE, + EMFILE = libc::EMFILE, + ENOTTY = libc::ENOTTY, + ETXTBSY = libc::ETXTBSY, + EFBIG = libc::EFBIG, + ENOSPC = libc::ENOSPC, + ESPIPE = libc::ESPIPE, + EROFS = libc::EROFS, + EMLINK = libc::EMLINK, + EPIPE = libc::EPIPE, + EDOM = libc::EDOM, + ERANGE = libc::ERANGE, + EDEADLK = libc::EDEADLK, + ENAMETOOLONG = libc::ENAMETOOLONG, + ENOLCK = libc::ENOLCK, + ENOSYS = libc::ENOSYS, + ENOTEMPTY = libc::ENOTEMPTY, + ELOOP = libc::ELOOP, + ENOMSG = libc::ENOMSG, + EIDRM = libc::EIDRM, + EINPROGRESS = libc::EINPROGRESS, + EALREADY = libc::EALREADY, + ENOTSOCK = libc::ENOTSOCK, + EDESTADDRREQ = libc::EDESTADDRREQ, + EMSGSIZE = libc::EMSGSIZE, + EPROTOTYPE = libc::EPROTOTYPE, + ENOPROTOOPT = libc::ENOPROTOOPT, + EPROTONOSUPPORT = libc::EPROTONOSUPPORT, + ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT, + EPFNOSUPPORT = libc::EPFNOSUPPORT, + EAFNOSUPPORT = libc::EAFNOSUPPORT, + EADDRINUSE = libc::EADDRINUSE, + EADDRNOTAVAIL = libc::EADDRNOTAVAIL, + ENETDOWN = libc::ENETDOWN, + ENETUNREACH = libc::ENETUNREACH, + ENETRESET = libc::ENETRESET, + ECONNABORTED = libc::ECONNABORTED, + ECONNRESET = libc::ECONNRESET, + ENOBUFS = libc::ENOBUFS, + EISCONN = libc::EISCONN, + ENOTCONN = libc::ENOTCONN, + ESHUTDOWN = libc::ESHUTDOWN, + ETOOMANYREFS = libc::ETOOMANYREFS, + ETIMEDOUT = libc::ETIMEDOUT, + ECONNREFUSED = libc::ECONNREFUSED, + EHOSTDOWN = libc::EHOSTDOWN, + EHOSTUNREACH = libc::EHOSTUNREACH, + ECHRNG = libc::ECHRNG, + EL2NSYNC = libc::EL2NSYNC, + EL3HLT = libc::EL3HLT, + EL3RST = libc::EL3RST, + ELNRNG = libc::ELNRNG, + EUNATCH = libc::EUNATCH, + ENOCSI = libc::ENOCSI, + EL2HLT = libc::EL2HLT, + ENOLINK = libc::ENOLINK, + EPROTO = libc::EPROTO, + EMULTIHOP = libc::EMULTIHOP, + EBADMSG = libc::EBADMSG, + EOVERFLOW = libc::EOVERFLOW, + EILSEQ = libc::EILSEQ, + ERESTART = libc::ERESTART, + EOWNERDEAD = libc::EOWNERDEAD, + ENOTRECOVERABLE = libc::ENOTRECOVERABLE, + ENOTSUP = libc::ENOTSUP, + EPROCLIM = libc::EPROCLIM, + EUSERS = libc::EUSERS, + EDQUOT = libc::EDQUOT, + ESTALE = libc::ESTALE, + EREMOTE = libc::EREMOTE, + ECANCELED = libc::ECANCELED, + ENODATA = libc::ENODATA, + ENOSR = libc::ENOSR, + ENOSTR = libc::ENOSTR, + ETIME = libc::ETIME, + EOPNOTSUPP = libc::EOPNOTSUPP, + } + + pub const fn from_i32(e: i32) -> Errno { + use self::Errno::*; + + match e { + libc::EPERM => EPERM, + libc::ENOENT => ENOENT, + libc::ESRCH => ESRCH, + libc::EINTR => EINTR, + libc::EIO => EIO, + libc::ENXIO => ENXIO, + libc::E2BIG => E2BIG, + libc::ENOEXEC => ENOEXEC, + libc::EBADF => EBADF, + libc::ECHILD => ECHILD, + libc::EAGAIN => EAGAIN, + libc::ENOMEM => ENOMEM, + libc::EACCES => EACCES, + libc::EFAULT => EFAULT, + libc::ENOTBLK => ENOTBLK, + libc::EBUSY => EBUSY, + libc::EEXIST => EEXIST, + libc::EXDEV => EXDEV, + libc::ENODEV => ENODEV, + libc::ENOTDIR => ENOTDIR, + libc::EISDIR => EISDIR, + libc::EINVAL => EINVAL, + libc::ENFILE => ENFILE, + libc::EMFILE => EMFILE, + libc::ENOTTY => ENOTTY, + libc::ETXTBSY => ETXTBSY, + libc::EFBIG => EFBIG, + libc::ENOSPC => ENOSPC, + libc::ESPIPE => ESPIPE, + libc::EROFS => EROFS, + libc::EMLINK => EMLINK, + libc::EPIPE => EPIPE, + libc::EDOM => EDOM, + libc::ERANGE => ERANGE, + libc::EDEADLK => EDEADLK, + libc::ENAMETOOLONG => ENAMETOOLONG, + libc::ENOLCK => ENOLCK, + libc::ENOSYS => ENOSYS, + libc::ENOTEMPTY => ENOTEMPTY, + libc::ELOOP => ELOOP, + libc::ENOMSG => ENOMSG, + libc::EIDRM => EIDRM, + libc::EINPROGRESS => EINPROGRESS, + libc::EALREADY => EALREADY, + libc::ENOTSOCK => ENOTSOCK, + libc::EDESTADDRREQ => EDESTADDRREQ, + libc::EMSGSIZE => EMSGSIZE, + libc::EPROTOTYPE => EPROTOTYPE, + libc::ENOPROTOOPT => ENOPROTOOPT, + libc::EPROTONOSUPPORT => EPROTONOSUPPORT, + libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT, + libc::EPFNOSUPPORT => EPFNOSUPPORT, + libc::EAFNOSUPPORT => EAFNOSUPPORT, + libc::EADDRINUSE => EADDRINUSE, + libc::EADDRNOTAVAIL => EADDRNOTAVAIL, + libc::ENETDOWN => ENETDOWN, + libc::ENETUNREACH => ENETUNREACH, + libc::ENETRESET => ENETRESET, + libc::ECONNABORTED => ECONNABORTED, + libc::ECONNRESET => ECONNRESET, + libc::ENOBUFS => ENOBUFS, + libc::EISCONN => EISCONN, + libc::ENOTCONN => ENOTCONN, + libc::ESHUTDOWN => ESHUTDOWN, + libc::ETOOMANYREFS => ETOOMANYREFS, + libc::ETIMEDOUT => ETIMEDOUT, + libc::ECONNREFUSED => ECONNREFUSED, + libc::EHOSTDOWN => EHOSTDOWN, + libc::EHOSTUNREACH => EHOSTUNREACH, + libc::ECHRNG => ECHRNG, + libc::EL2NSYNC => EL2NSYNC, + libc::EL3HLT => EL3HLT, + libc::EL3RST => EL3RST, + libc::ELNRNG => ELNRNG, + libc::EUNATCH => EUNATCH, + libc::ENOCSI => ENOCSI, + libc::EL2HLT => EL2HLT, + libc::ENOLINK => ENOLINK, + libc::EPROTO => EPROTO, + libc::EMULTIHOP => EMULTIHOP, + libc::EBADMSG => EBADMSG, + libc::EOVERFLOW => EOVERFLOW, + libc::EILSEQ => EILSEQ, + libc::ERESTART => ERESTART, + libc::ENOTRECOVERABLE => ENOTRECOVERABLE, + libc::EOWNERDEAD => EOWNERDEAD, + libc::ENOTSUP => ENOTSUP, + libc::EPROCLIM => EPROCLIM, + libc::EUSERS => EUSERS, + libc::EDQUOT => EDQUOT, + libc::ESTALE => ESTALE, + libc::EREMOTE => EREMOTE, + libc::ECANCELED => ECANCELED, + libc::ENODATA => ENODATA, + libc::ENOSR => ENOSR, + libc::ENOSTR => ENOSTR, + libc::ETIME => ETIME, + libc::EOPNOTSUPP => EOPNOTSUPP, + _ => UnknownErrno, + } + } +} diff --git a/src/fcntl.rs b/src/fcntl.rs index d799ff378e..f7bb698980 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -54,7 +54,10 @@ libc_bitflags!( /// Open the file in append-only mode. O_APPEND; /// Generate a signal when input or output becomes possible. - #[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "haiku")))] + #[cfg(not(any(target_os = "aix", + target_os = "illumos", + target_os = "solaris", + target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] O_ASYNC; /// Closes the file descriptor once an `execve` call is made. diff --git a/src/features.rs b/src/features.rs index 2f07a8fccd..9e292cbf5d 100644 --- a/src/features.rs +++ b/src/features.rs @@ -113,6 +113,7 @@ mod os { } #[cfg(any( + target_os = "aix", target_os = "macos", target_os = "ios", target_os = "fuchsia", diff --git a/src/pty.rs b/src/pty.rs index 2866c6df48..455828b703 100644 --- a/src/pty.rs +++ b/src/pty.rs @@ -5,13 +5,17 @@ pub use libc::winsize as Winsize; use std::ffi::CStr; use std::io; +#[cfg(not(target_os = "aix"))] use std::mem; use std::os::unix::prelude::*; use crate::errno::Errno; +#[cfg(not(target_os = "aix"))] use crate::sys::termios::Termios; #[cfg(feature = "process")] -use crate::unistd::{ForkResult, Pid}; +use crate::unistd::ForkResult; +#[cfg(all(feature = "process", not(target_os = "aix")))] +use crate::unistd::Pid; use crate::{fcntl, unistd, Result}; /// Representation of a master/slave pty pair @@ -224,6 +228,7 @@ pub fn unlockpt(fd: &PtyMaster) -> Result<()> { /// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's /// terminal settings of the slave will be set to the values in `termios`. #[inline] +#[cfg(not(target_os = "aix"))] pub fn openpty< 'a, 'b, @@ -315,6 +320,7 @@ feature! { /// special care must be taken to only invoke code you can control and audit. /// /// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html +#[cfg(not(target_os = "aix"))] pub unsafe fn forkpty<'a, 'b, T: Into>, U: Into>>( winsize: T, termios: U, diff --git a/src/sys/mman.rs b/src/sys/mman.rs index e689e06e04..8cfd6d6d54 100644 --- a/src/sys/mman.rs +++ b/src/sys/mman.rs @@ -82,7 +82,7 @@ libc_bitflags! { /// Do not reserve swap space for this mapping. /// /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. - #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))] + #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", target_os = "aix")))] #[cfg_attr(docsrs, doc(cfg(all())))] MAP_NORESERVE; /// Populate page tables for a mapping. @@ -282,6 +282,8 @@ libc_enum! { #[cfg_attr(docsrs, doc(cfg(all())))] MADV_DODUMP, /// Specify that the application no longer needs the pages in the given range. + #[cfg(not(target_os = "aix"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MADV_FREE, /// Request that the system not flush the current range to disk unless it needs to. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] diff --git a/src/sys/resource.rs b/src/sys/resource.rs index 8927737763..f42d32e3ca 100644 --- a/src/sys/resource.rs +++ b/src/sys/resource.rs @@ -20,6 +20,7 @@ cfg_if! { target_os = "ios", target_os = "android", target_os = "dragonfly", + target_os = "aix", all(target_os = "linux", not(target_env = "gnu")) ))]{ use libc::rlimit; @@ -51,6 +52,7 @@ libc_enum! { target_os = "ios", target_os = "android", target_os = "dragonfly", + target_os = "aix", all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc"))) ), repr(i32))] #[non_exhaustive] @@ -115,6 +117,7 @@ libc_enum! { target_os = "netbsd", target_os = "openbsd", target_os = "linux", + target_os = "aix", ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum number of simultaneous processes for this user id. @@ -131,6 +134,7 @@ libc_enum! { target_os = "netbsd", target_os = "openbsd", target_os = "linux", + target_os = "aix", ))] #[cfg_attr(docsrs, doc(cfg(all())))] /// When there is memory pressure and swap is available, prioritize diff --git a/src/sys/signal.rs b/src/sys/signal.rs index efa35ebfd2..60f835c5f8 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -93,7 +93,8 @@ libc_enum! { #[cfg_attr(docsrs, doc(cfg(all())))] SIGIO, #[cfg(any(target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux"))] + target_os = "fuchsia", target_os = "linux", + target_os = "aix"))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Power failure imminent. SIGPWR, @@ -107,7 +108,8 @@ libc_enum! { SIGEMT, #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux", - target_os = "redox", target_os = "haiku")))] + target_os = "redox", target_os = "haiku", + target_os = "aix")))] #[cfg_attr(docsrs, doc(cfg(all())))] /// Information request SIGINFO, @@ -186,6 +188,7 @@ impl FromStr for Signal { target_os = "fuchsia", target_os = "linux", target_os = "redox", + target_os = "aix", target_os = "haiku" )))] "SIGINFO" => Signal::SIGINFO, @@ -250,6 +253,7 @@ impl Signal { target_os = "android", target_os = "emscripten", target_os = "fuchsia", + target_os = "aix", target_os = "linux" ))] Signal::SIGPWR => "SIGPWR", @@ -269,6 +273,7 @@ impl Signal { target_os = "fuchsia", target_os = "linux", target_os = "redox", + target_os = "aix", target_os = "haiku" )))] Signal::SIGINFO => "SIGINFO", @@ -345,11 +350,20 @@ const SIGNALS: [Signal; 30] = [ SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS, ]; +#[cfg(target_os = "aix")] +#[cfg(feature = "signal")] +const SIGNALS: [Signal; 30] = [ + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGEMT, SIGFPE, SIGKILL, SIGSEGV, + SIGSYS, SIGPIPE, SIGALRM, SIGTERM, SIGUSR1, SIGUSR2, SIGPWR, SIGWINCH, + SIGURG, SIGPOLL, SIGIO, SIGSTOP, SIGTSTP, SIGCONT, SIGTTIN, SIGTTOU, + SIGVTALRM, SIGPROF, SIGXCPU, SIGXFSZ, SIGTRAP, +]; #[cfg(not(any( target_os = "linux", target_os = "android", target_os = "fuchsia", target_os = "emscripten", + target_os = "aix", target_os = "redox", target_os = "haiku" )))] @@ -669,6 +683,7 @@ impl SigAction { /// is the `SigAction` variant). `mask` specifies other signals to block during execution of /// the signal-catching function. pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction { + #[cfg(not(target_os = "aix"))] unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) { (*p).sa_sigaction = match handler { SigHandler::SigDfl => libc::SIG_DFL, @@ -679,6 +694,16 @@ impl SigAction { }; } + #[cfg(target_os = "aix")] + unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) { + (*p).sa_union.__su_sigaction = match handler { + SigHandler::SigDfl => mem::transmute::(libc::SIG_DFL), + SigHandler::SigIgn => mem::transmute::(libc::SIG_IGN), + SigHandler::Handler(f) => mem::transmute::(f), + SigHandler::SigAction(f) => f, + }; + } + let mut s = mem::MaybeUninit::::uninit(); unsafe { let p = s.as_mut_ptr(); @@ -706,6 +731,7 @@ impl SigAction { } /// Returns the action's handler. + #[cfg(not(target_os = "aix"))] pub fn handler(&self) -> SigHandler { match self.sigaction.sa_sigaction { libc::SIG_DFL => SigHandler::SigDfl, @@ -738,6 +764,26 @@ impl SigAction { as extern fn(libc::c_int)), } } + + /// Returns the action's handler. + #[cfg(target_os = "aix")] + pub fn handler(&self) -> SigHandler { + unsafe { + match self.sigaction.sa_union.__su_sigaction as usize { + libc::SIG_DFL => SigHandler::SigDfl, + libc::SIG_IGN => SigHandler::SigIgn, + p if self.flags().contains(SaFlags::SA_SIGINFO) => + SigHandler::SigAction( + *(&p as *const usize + as *const extern fn(_, _, _)) + as extern fn(_, _, _)), + p => SigHandler::Handler( + *(&p as *const usize + as *const extern fn(libc::c_int)) + as extern fn(libc::c_int)), + } + } + } } /// Changes the action taken by a process on receipt of a specific signal. diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 1d86e756f9..a7a45ff543 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -9,7 +9,8 @@ target_os = "netbsd", target_os = "openbsd", target_os = "haiku", - target_os = "fuchsia" + target_os = "fuchsia", + target_os = "aix", ))] #[cfg(feature = "net")] pub use self::datalink::LinkAddr; @@ -99,7 +100,8 @@ pub enum AddressFamily { #[cfg_attr(docsrs, doc(cfg(all())))] Ax25 = libc::AF_AX25, /// IPX - Novell protocols - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "aix", target_os = "redox")))] + #[cfg_attr(docsrs, doc(cfg(all())))] Ipx = libc::AF_IPX, /// AppleTalk #[cfg(not(target_os = "redox"))] @@ -200,6 +202,7 @@ pub enum AddressFamily { Tipc = libc::AF_TIPC, /// Bluetooth low-level socket protocol #[cfg(not(any( + target_os = "aix", target_os = "illumos", target_os = "ios", target_os = "macos", @@ -219,6 +222,7 @@ pub enum AddressFamily { RxRpc = libc::AF_RXRPC, /// New "modular ISDN" driver interface protocol #[cfg(not(any( + target_os = "aix", target_os = "illumos", target_os = "solaris", target_os = "haiku", @@ -1014,6 +1018,7 @@ impl SockaddrIn { target_os = "ios", target_os = "macos", target_os = "netbsd", + target_os = "aix", target_os = "haiku", target_os = "openbsd" ))] @@ -2153,6 +2158,7 @@ mod datalink { target_os = "illumos", target_os = "netbsd", target_os = "haiku", + target_os = "aix", target_os = "openbsd" ))] #[cfg_attr(docsrs, doc(cfg(all())))] @@ -2524,6 +2530,7 @@ mod tests { #[test] fn size() { #[cfg(any( + target_os = "aix", target_os = "dragonfly", target_os = "freebsd", target_os = "ios", diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index c304f6e3c2..3103502168 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -322,6 +322,8 @@ libc_bitflags! { /// which will affect all threads in /// the calling process and as well as other processes that hold /// file descriptors referring to the same open file description. + #[cfg(not(target_os = "aix"))] + #[cfg_attr(docsrs, doc(cfg(all())))] MSG_DONTWAIT; /// Receive flags: Control Data was discarded (buffer too small) MSG_CTRUNC; @@ -887,7 +889,7 @@ impl ControlMessageOwned { let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _); ControlMessageOwned::ScmCreds(cred.into()) } - #[cfg(not(target_os = "haiku"))] + #[cfg(not(any(target_os = "aix", target_os = "haiku")))] (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => { let tv: libc::timeval = ptr::read_unaligned(p as *const _); ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 0d675ffb01..5d28185cb8 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -693,7 +693,7 @@ sockopt_impl!( libc::SO_TIMESTAMPING, super::TimestampingFlag ); -#[cfg(not(any(target_os = "haiku", target_os = "redox")))] +#[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "redox")))] sockopt_impl!( /// Enable or disable the receiving of the `SO_TIMESTAMP` control message. ReceiveTimestamp, diff --git a/src/sys/termios.rs b/src/sys/termios.rs index af29d64dfa..ecaa3eaf8f 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -397,6 +397,8 @@ libc_enum! { #[cfg_attr(docsrs, doc(cfg(all())))] B28800, B38400, + #[cfg(not(target_os = "aix"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B57600, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -405,10 +407,14 @@ libc_enum! { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] B76800, + #[cfg(not(target_os = "aix"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B115200, #[cfg(any(target_os = "illumos", target_os = "solaris"))] #[cfg_attr(docsrs, doc(cfg(all())))] B153600, + #[cfg(not(target_os = "aix"))] + #[cfg_attr(docsrs, doc(cfg(all())))] B230400, #[cfg(any(target_os = "illumos", target_os = "solaris"))] #[cfg_attr(docsrs, doc(cfg(all())))] @@ -542,6 +548,8 @@ libc_enum! { #[repr(usize)] #[non_exhaustive] pub enum SpecialCharacterIndices { + #[cfg(not(target_os = "aix"))] + #[cfg_attr(docsrs, doc(cfg(all())))] VDISCARD, #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -549,6 +557,7 @@ libc_enum! { target_os = "macos", target_os = "netbsd", target_os = "openbsd", + target_os = "aix", target_os = "solaris"))] #[cfg_attr(docsrs, doc(cfg(all())))] VDSUSP, @@ -566,7 +575,7 @@ libc_enum! { VKILL, VLNEXT, #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris")))] + target_os = "illumos", target_os = "solaris", target_os = "aix")))] #[cfg_attr(docsrs, doc(cfg(all())))] VMIN, VQUIT, @@ -590,9 +599,11 @@ libc_enum! { #[cfg_attr(docsrs, doc(cfg(all())))] VSWTCH, #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), - target_os = "illumos", target_os = "solaris")))] + target_os = "illumos", target_os = "solaris", target_os = "aix")))] #[cfg_attr(docsrs, doc(cfg(all())))] VTIME, + #[cfg(not(target_os = "aix"))] + #[cfg_attr(docsrs, doc(cfg(all())))] VWERASE, #[cfg(target_os = "dragonfly")] #[cfg_attr(docsrs, doc(cfg(all())))] @@ -603,7 +614,8 @@ libc_enum! { #[cfg(any( all(target_os = "linux", target_arch = "sparc64"), target_os = "illumos", - target_os = "solaris" + target_os = "solaris", + target_os = "aix", ))] impl SpecialCharacterIndices { pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF; @@ -616,6 +628,7 @@ pub use libc::NCCS; target_os = "dragonfly", target_os = "freebsd", target_os = "linux", + target_os = "aix", target_os = "macos", target_os = "netbsd", target_os = "openbsd" @@ -881,7 +894,7 @@ libc_bitflags! { PARODD; HUPCL; CLOCAL; - #[cfg(not(target_os = "redox"))] + #[cfg(not(any(target_os = "redox", target_os = "aix")))] #[cfg_attr(docsrs, doc(cfg(all())))] CRTSCTS; #[cfg(any(target_os = "android", target_os = "linux"))] @@ -967,7 +980,7 @@ libc_bitflags! { #[cfg_attr(docsrs, doc(cfg(all())))] ALTWERASE; IEXTEN; - #[cfg(not(any(target_os = "redox", target_os = "haiku")))] + #[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "aix")))] #[cfg_attr(docsrs, doc(cfg(all())))] EXTPROC; TOSTOP; diff --git a/src/unistd.rs b/src/unistd.rs index afa80e9b9d..bb9f1c1f67 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -1025,6 +1025,7 @@ pub fn sethostname>(name: S) -> Result<()> { target_os = "illumos", target_os = "ios", target_os = "macos", + target_os = "aix", target_os = "solaris", ))] { type sethostname_len_t = c_int; } else { @@ -1646,7 +1647,8 @@ pub fn getgroups() -> Result> { )))] pub fn setgroups(groups: &[Gid]) -> Result<()> { cfg_if! { - if #[cfg(any(target_os = "dragonfly", + if #[cfg(any(target_os = "aix", + target_os = "dragonfly", target_os = "freebsd", target_os = "illumos", target_os = "ios", @@ -1693,6 +1695,7 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { /// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation /// will only ever return the complete list or else an error. #[cfg(not(any( + target_os = "aix", target_os = "illumos", target_os = "ios", target_os = "macos", @@ -3457,6 +3460,7 @@ pub struct User { pub shell: PathBuf, /// Login class #[cfg(not(any( + target_os = "aix", target_os = "android", target_os = "fuchsia", target_os = "haiku", @@ -3468,6 +3472,7 @@ pub struct User { pub class: CString, /// Last password change #[cfg(not(any( + target_os = "aix", target_os = "android", target_os = "fuchsia", target_os = "haiku", @@ -3479,6 +3484,7 @@ pub struct User { pub change: libc::time_t, /// Expiration time of account #[cfg(not(any( + target_os = "aix", target_os = "android", target_os = "fuchsia", target_os = "haiku", @@ -3533,6 +3539,7 @@ impl From<&libc::passwd> for User { uid: Uid::from_raw(pw.pw_uid), gid: Gid::from_raw(pw.pw_gid), #[cfg(not(any( + target_os = "aix", target_os = "android", target_os = "fuchsia", target_os = "haiku", @@ -3543,6 +3550,7 @@ impl From<&libc::passwd> for User { class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes()) .unwrap(), #[cfg(not(any( + target_os = "aix", target_os = "android", target_os = "fuchsia", target_os = "haiku", @@ -3552,6 +3560,7 @@ impl From<&libc::passwd> for User { )))] change: pw.pw_change, #[cfg(not(any( + target_os = "aix", target_os = "android", target_os = "fuchsia", target_os = "haiku", @@ -3593,6 +3602,7 @@ impl From for libc::passwd { pw_uid: u.uid.0, pw_gid: u.gid.0, #[cfg(not(any( + target_os = "aix", target_os = "android", target_os = "fuchsia", target_os = "haiku", @@ -3602,6 +3612,7 @@ impl From for libc::passwd { )))] pw_class: u.class.into_raw(), #[cfg(not(any( + target_os = "aix", target_os = "android", target_os = "fuchsia", target_os = "haiku", @@ -3611,6 +3622,7 @@ impl From for libc::passwd { )))] pw_change: u.change, #[cfg(not(any( + target_os = "aix", target_os = "android", target_os = "fuchsia", target_os = "haiku", From 59e7794f0a4d8302e6d80a474fb23cdbf9f92e25 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 6 Aug 2023 12:05:41 -0600 Subject: [PATCH 323/358] Clippy cleanup Clippy found some const-correctness issues in internal APIs, but nothing user-facing. --- .cirrus.yml | 5 ++++- src/dir.rs | 3 +++ src/sys/socket/mod.rs | 22 +++++++++++----------- src/sys/uio.rs | 6 ++++++ 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index f3624f4bde..6d5402df69 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -5,6 +5,7 @@ cargo_cache: env: # Build by default; don't just check BUILD: build + CLIPPYFLAGS: -D warnings -A unknown-lints RUSTFLAGS: -D warnings RUSTDOCFLAGS: -D warnings TOOL: cargo @@ -19,7 +20,7 @@ build: &BUILD - rustc -Vv - $TOOL $BUILD $ZFLAGS --target $TARGET --all-targets - $TOOL doc $ZFLAGS --no-deps --target $TARGET - - $TOOL clippy $ZFLAGS --target $TARGET --all-targets -- -D warnings + - $TOOL clippy $ZFLAGS --target $TARGET --all-targets -- $CLIPPYFLAGS - if [ -z "$NOHACK" ]; then mkdir -p $HOME/.cargo/bin; export PATH=$HOME/.cargo/bin:$PATH; fi - if [ -z "$NOHACK" ]; then curl -LsSf https://github.com/taiki-e/cargo-hack/releases/latest/download/cargo-hack-${HOST:-$TARGET}.tar.gz | tar xzf - -C ~/.cargo/bin; fi - if [ -z "$NOHACK" ]; then $TOOL hack $ZFLAGS check --target $TARGET --each-feature; fi @@ -253,6 +254,7 @@ task: env: HOST: x86_64-unknown-linux-gnu TARGET: x86_64-unknown-redox + CLIPPYFLAGS: -D warnings setup_script: - rustup target add $TARGET - rustup component add clippy @@ -267,6 +269,7 @@ task: BUILD: check HOST: x86_64-unknown-linux-gnu ZFLAGS: -Zbuild-std + CLIPPYFLAGS: -D warnings matrix: - name: DragonFly BSD x86_64 env: diff --git a/src/dir.rs b/src/dir.rs index e1854c35e8..6df6c2a775 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -101,6 +101,9 @@ impl Drop for Dir { } } +// The pass by mut is technically needless only because the inner NonNull is +// Copy. But philosophically we're mutating the Dir, so we pass by mut. +#[allow(clippy::needless_pass_by_ref_mut)] fn next(dir: &mut Dir) -> Option> { unsafe { // Note: POSIX specifies that portable applications should dynamically allocate a diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index c304f6e3c2..c16e33467c 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1619,18 +1619,18 @@ impl MultiHeaders { // we'll need a cmsg_buffer for each slice, we preallocate a vector and split // it into "slices" parts - let cmsg_buffers = + let mut cmsg_buffers = cmsg_buffer.map(|v| vec![0u8; v.capacity() * num_slices].into_boxed_slice()); let items = addresses .iter_mut() .enumerate() .map(|(ix, address)| { - let (ptr, cap) = match &cmsg_buffers { - Some(v) => ((&v[ix * msg_controllen] as *const u8), msg_controllen), - None => (std::ptr::null(), 0), + let (ptr, cap) = match &mut cmsg_buffers { + Some(v) => ((&mut v[ix * msg_controllen] as *mut u8), msg_controllen), + None => (std::ptr::null_mut(), 0), }; - let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.as_mut_ptr()) }; + let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null_mut(), 0, ptr, cap, address.as_mut_ptr()) }; libc::mmsghdr { msg_hdr, msg_len: 0, @@ -1961,9 +1961,9 @@ unsafe fn read_mhdr<'a, 'i, S>( /// /// Buffers must remain valid for the whole lifetime of msghdr unsafe fn pack_mhdr_to_receive( - iov_buffer: *const IoSliceMut, + iov_buffer: *mut IoSliceMut, iov_buffer_len: usize, - cmsg_buffer: *const u8, + cmsg_buffer: *mut u8, cmsg_capacity: usize, address: *mut S, ) -> msghdr @@ -1999,7 +1999,7 @@ fn pack_mhdr_to_send<'a, I, C, S>( // The message header must be initialized before the individual cmsgs. let cmsg_ptr = if capacity > 0 { - cmsg_buffer.as_ptr() as *mut c_void + cmsg_buffer.as_mut_ptr() as *mut c_void } else { ptr::null_mut() }; @@ -2063,7 +2063,7 @@ pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'i .map(|v| (v.as_mut_ptr(), v.capacity())) .unwrap_or((ptr::null_mut(), 0)); let mut mhdr = unsafe { - pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr()) + pack_mhdr_to_receive(iov.as_mut().as_mut_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr()) }; let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; @@ -2209,7 +2209,7 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result { unsafe { let ret = libc::recv( sockfd, - buf.as_ptr() as *mut c_void, + buf.as_mut_ptr() as *mut c_void, buf.len() as size_t, flags.bits(), ); @@ -2233,7 +2233,7 @@ pub fn recvfrom( let ret = Errno::result(libc::recvfrom( sockfd, - buf.as_ptr() as *mut c_void, + buf.as_mut_ptr() as *mut c_void, buf.len() as size_t, 0, addr.as_mut_ptr() as *mut sockaddr, diff --git a/src/sys/uio.rs b/src/sys/uio.rs index ce0fb54ddb..eaf61edfd4 100644 --- a/src/sys/uio.rs +++ b/src/sys/uio.rs @@ -27,6 +27,9 @@ pub fn writev(fd: Fd, iov: &[IoSlice<'_>]) -> Result { /// Low-level vectored read from a raw file descriptor /// /// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html) +// Clippy doesn't know that we need to pass iov mutably only because the +// mutation happens after converting iov to a pointer +#[allow(clippy::needless_pass_by_ref_mut)] pub fn readv(fd: Fd, iov: &mut [IoSliceMut<'_>]) -> Result { // SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec let res = unsafe { @@ -70,6 +73,9 @@ pub fn pwritev(fd: Fd, iov: &[IoSlice<'_>], offset: off_t) -> Result( fd: Fd, iov: &mut [IoSliceMut<'_>], From 31162fd42441d3853a9b4b269bb8094bad75ad48 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 6 Aug 2023 13:01:44 -0600 Subject: [PATCH 324/358] Fix the build on Haiku By restricting tempfile to 3.6.0 or lower. https://github.com/Stebalien/tempfile/issues/246 --- Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a40d250ebf..62452ab432 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,7 +80,9 @@ assert-impl = "0.1" lazy_static = "1.4" parking_lot = "0.12" rand = "0.8" -tempfile = "3.3.0" +# tempfile 3.7.0 doesn't build on Haiku +# https://github.com/Stebalien/tempfile/issues/246 +tempfile = ">=3.3.0, < 3.7.0" semver = "1.0.7" [target.'cfg(any(target_os = "android", target_os = "linux"))'.dev-dependencies] From 5378cceff0fc5693caa6619e23f431726f7e150e Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 6 Aug 2023 07:50:17 +0100 Subject: [PATCH 325/358] Adding new sockopt entries for FreeBSD related to routing --- src/sys/socket/sockopt.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 0d675ffb01..317d73f2cf 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -746,6 +746,26 @@ sockopt_impl!( libc::IP_BINDANY, bool ); +#[cfg(target_os = "freebsd")] +sockopt_impl!( + /// Set the route table (FIB) for this socket up to the `net.fibs` OID limit + /// (more specific than the setfib command line/call which are process based). + Fib, + SetOnly, + libc::SOL_SOCKET, + libc::SO_SETFIB, + i32 +); +#[cfg(target_os = "freebsd")] +sockopt_impl!( + /// Set `so_user_cookie` for this socket allowing network traffic based + /// upon it, similar to Linux's netfilter MARK. + UserCookie, + SetOnly, + libc::SOL_SOCKET, + libc::SO_USER_COOKIE, + u32 +); #[cfg(target_os = "linux")] sockopt_impl!( /// Set the mark for each packet sent through this socket (similar to the From 8e4150e8cd4c3ac74b885313569fdb2440a99e91 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 6 Aug 2023 07:53:05 +0100 Subject: [PATCH 326/358] adding changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56b9b7d9f9..6962d6858e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added `SOF_TIMESTAMPING_OPT_ID` and `SOF_TIMESTAMPING_OPT_TSONLY` to `nix::sys::socket::TimestampingFlag`. ([#2048](https://github.com/nix-rust/nix/pull/2048)) - Enabled socket timestamping options on Android. ([#2077](https://github.com/nix-rust/nix/pull/2077)) +- Added `SO_SETFIB` and `SO_USER_COOKIE` to `nix::sys::socket::sockopt` for FreeBSD. + ([#2085](https://github.com/nix-rust/nix/pull/2085)) ### Changed From 94b2c5520b666028a9e65155ebcccc9e1d27e6ba Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 6 Aug 2023 16:02:14 -0600 Subject: [PATCH 327/358] Fix Haiku build by updating tempfile to 3.7.1 https://github.com/Stebalien/tempfile/issues/246 --- Cargo.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 62452ab432..c788b5eb0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,9 +80,7 @@ assert-impl = "0.1" lazy_static = "1.4" parking_lot = "0.12" rand = "0.8" -# tempfile 3.7.0 doesn't build on Haiku -# https://github.com/Stebalien/tempfile/issues/246 -tempfile = ">=3.3.0, < 3.7.0" +tempfile = "3.7.1" semver = "1.0.7" [target.'cfg(any(target_os = "android", target_os = "linux"))'.dev-dependencies] From 2ab1eafbdd6113d889c2d82b13ddaa538b3082f0 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 7 Aug 2023 00:13:21 +0100 Subject: [PATCH 328/358] sockopt add OpenBSD's SO_RTABLE to set the route table. Also SO_ACCEPTFILTER for FreeBSD/NetBSD. --- src/sys/socket/sockopt.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 317d73f2cf..82b32866d6 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -766,6 +766,26 @@ sockopt_impl!( libc::SO_USER_COOKIE, u32 ); +#[cfg(target_os = "openbsd")] +sockopt_impl!( + /// Set the route table for this socket, needs a privileged user if + /// the process/socket had been set to the non default route. + Rtable, + SetOnly, + libc::SOL_SOCKET, + libc::SO_RTABLE, + i32 +); +#[cfg(any(target_os = "freebsd", target_os = "netbsd"))] +sockopt_impl!( + /// Get/set a filter on this socket before accepting connections similarly + /// to Linux's TCP_DEFER_ACCEPT but after the listen's call. + AcceptFilter, + Both, + libc::SOL_SOCKET, + libc::SO_ACCEPTFILTER, + libc::accept_filter_arg +); #[cfg(target_os = "linux")] sockopt_impl!( /// Set the mark for each packet sent through this socket (similar to the From 3591ed85c3ef1bec4ca064b5ae2fc7974f2a69ed Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 6 Aug 2023 23:20:26 +0100 Subject: [PATCH 329/358] add CHANGELOG entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa4888d973..fb7d229975 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added vsock support for macOS ([#2056](https://github.com/nix-rust/nix/pull/2056)) - Added `SO_SETFIB` and `SO_USER_COOKIE` to `nix::sys::socket::sockopt` for FreeBSD. ([#2085](https://github.com/nix-rust/nix/pull/2085)) +- Added `SO_RTABLE` for OpenBSD and `SO_ACCEPTFILTER` for FreeBSD/NetBSD to `nix::sys::socket::sockopt`. + ([#2085](https://github.com/nix-rust/nix/pull/2085)) ### Changed From 5e7bfd59702bfb94a525755269d465dc0ba881ce Mon Sep 17 00:00:00 2001 From: Alex Zepeda Date: Sat, 29 Jul 2023 14:29:44 -0700 Subject: [PATCH 330/358] fcntl: Solaris doesn't have flock(2) Solaris hasn't included flock(2) for a long while now, and building this wrapper creates issues with undefined symbols. However, OpenSolaris derivatives like Illumos do include flock(2) so they should not be excluded here. --- CHANGELOG.md | 1 + src/fcntl.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb7d229975..308f929025 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#2085](https://github.com/nix-rust/nix/pull/2085)) - Added `SO_RTABLE` for OpenBSD and `SO_ACCEPTFILTER` for FreeBSD/NetBSD to `nix::sys::socket::sockopt`. ([#2085](https://github.com/nix-rust/nix/pull/2085)) +- Removed `flock` from `::nix::fcntl` on Solaris. ([#2082](https://github.com/nix-rust/nix/pull/2082)) ### Changed diff --git a/src/fcntl.rs b/src/fcntl.rs index f7bb698980..85c8e1a49e 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -559,7 +559,7 @@ pub enum FlockArg { UnlockNonblock, } -#[cfg(not(target_os = "redox"))] +#[cfg(not(any(target_os = "redox", target_os = "solaris")))] pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> { use self::FlockArg::*; From 950bd09df4757b7d485966d0a98d47f422476248 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 6 Aug 2023 18:28:59 -0600 Subject: [PATCH 331/358] Retire Bors Bors worked well for a long time. But that product is now retiring. It's been replaced by GitHub's built-in merge queues. Fixes #2078 --- CONTRIBUTING.md | 28 +++++++++---------------- bors.toml | 54 ------------------------------------------------- 2 files changed, 9 insertions(+), 73 deletions(-) delete mode 100644 bors.toml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 00221157b7..8898a7c1fa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -79,32 +79,22 @@ environment. We also have [continuous integration set up on Cirrus-CI][cirrus-ci], which might find some issues on other platforms. The CI will run once you open a pull request. -There is also infrastructure for running tests for other targets -locally. More information is available in the [CI Readme][ci-readme]. - [cirrus-ci]: https://cirrus-ci.com/github/nix-rust/nix -[ci-readme]: ci/README.md ### Disabling a test in the CI environment -Sometimes there are features that cannot be tested in the CI environment. -To stop a test from running under CI, add `skip_if_cirrus!()` to it. Please +Sometimes there are features that cannot be tested in the CI environment. To +stop a test from running under CI, add `skip_if_cirrus!()` to it. Please describe the reason it shouldn't run under CI, and a link to an issue if -possible! - -## bors, the bot who merges all the PRs - -All pull requests are merged via [bors], an integration bot. After the -pull request has been reviewed, the reviewer will leave a comment like - -> bors r+ - -to let bors know that it was approved. Then bors will check that it passes -tests when merged with the latest changes in the `master` branch, and -merge if the tests succeed. +possible! Other tests cannot be run under QEMU, which is used for some +architectures. To skip them, add a `#[cfg_attr(qemu, ignore)]` attribute to +the test. -[bors]: https://bors-ng.github.io/ +## GitHub Merge Queues +We use GitHub merge queues to ensure that subtle merge conflicts won't result +in failing code. If you add or remove a CI job, remember to adjust the +required status checks in the repository's branch protection rules! ## API conventions diff --git a/bors.toml b/bors.toml deleted file mode 100644 index b6f81c33af..0000000000 --- a/bors.toml +++ /dev/null @@ -1,54 +0,0 @@ -status = [ - "Android aarch64", - "Android arm", - "Android armv7", - "Android i686", - "Android x86_64", - "DragonFly BSD x86_64", - "FreeBSD 12 amd64 & i686", - "FreeBSD 14 amd64 & i686", - "Fuchsia x86_64", - "Linux MIPS", - "Linux MIPS64 el", - "Linux MIPS64", - "Linux aarch64", - "Linux arm gnueabi", - "Linux arm-musleabi", - "Linux armv7 gnueabihf", - "Linux armv7 uclibceabihf", - "Linux i686 musl", - "Linux i686", - "Linux mipsel", - "Linux powerpc", - "Linux powerpc64", - "Linux powerpc64le", - "Linux s390x", - "Linux x32", - "Linux x86_64 musl", - "Linux x86_64", - "macOS aarch64", - "macOS x86_64", - "Minver", - "NetBSD x86_64", - "OpenBSD x86_64", - "Redox x86_64", - "Rust Stable", - "Rust Formatter", - "iOS aarch64", - "iOS x86_64", - "Illumos", - "Haiku x86_64", -] - -# Set bors's timeout to 1 hour -# -# bors's timeout should always be at least twice as long as the test suite -# takes. This is to allow the CI provider to fast-fail a test; if one of the -# builders immediately reports a failure, then bors will move on to the next -# batch, leaving the slower builders to work through the already-doomed run and -# the next one. -# -# At the time this was written, nix's test suite took about twenty minutes to -# run. The timeout was raised to one hour to give nix room to grow and time -# for delays on Cirrus's end. -timeout_sec = 3600 From c1317e477fe6c4ca84f53ab39a0f78269b4d6d21 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 5 Dec 2022 11:18:18 -0700 Subject: [PATCH 332/358] Add I/O safety to sockopt and some socket functions * socket * socketpair * listen * setsockopt * getsockopt --- src/sys/socket/addr.rs | 8 +- src/sys/socket/mod.rs | 66 +++--- src/sys/socket/sockopt.rs | 41 ++-- test/sys/test_socket.rs | 456 ++++++++++++++++++++++---------------- test/sys/test_sockopt.rs | 121 +++++----- 5 files changed, 393 insertions(+), 299 deletions(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index f3c0a05da2..1783531d49 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -875,9 +875,10 @@ pub trait SockaddrLike: private::SockaddrLikePriv { /// One common use is to match on the family of a union type, like this: /// ``` /// # use nix::sys::socket::*; + /// # use std::os::unix::io::AsRawFd; /// let fd = socket(AddressFamily::Inet, SockType::Stream, /// SockFlag::empty(), None).unwrap(); - /// let ss: SockaddrStorage = getsockname(fd).unwrap(); + /// let ss: SockaddrStorage = getsockname(fd.as_raw_fd()).unwrap(); /// match ss.family().unwrap() { /// AddressFamily::Inet => println!("{}", ss.as_sockaddr_in().unwrap()), /// AddressFamily::Inet6 => println!("{}", ss.as_sockaddr_in6().unwrap()), @@ -1261,11 +1262,12 @@ impl std::str::FromStr for SockaddrIn6 { /// ``` /// # use nix::sys::socket::*; /// # use std::str::FromStr; +/// # use std::os::unix::io::AsRawFd; /// let localhost = SockaddrIn::from_str("127.0.0.1:8081").unwrap(); /// let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), /// None).unwrap(); -/// bind(fd, &localhost).expect("bind"); -/// let ss: SockaddrStorage = getsockname(fd).expect("getsockname"); +/// bind(fd.as_raw_fd(), &localhost).expect("bind"); +/// let ss: SockaddrStorage = getsockname(fd.as_raw_fd()).expect("getsockname"); /// assert_eq!(&localhost, ss.as_sockaddr_in().unwrap()); /// ``` #[derive(Clone, Copy, Eq)] diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 6c858c8735..2e2897dbb2 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -18,7 +18,7 @@ use libc::{ use std::io::{IoSlice, IoSliceMut}; #[cfg(feature = "net")] use std::net; -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, RawFd, OwnedFd}; use std::{mem, ptr}; #[deny(missing_docs)] @@ -693,6 +693,7 @@ pub enum ControlMessageOwned { /// # use std::io::{IoSlice, IoSliceMut}; /// # use std::time::*; /// # use std::str::FromStr; + /// # use std::os::unix::io::AsRawFd; /// # fn main() { /// // Set up /// let message = "Ohayō!".as_bytes(); @@ -701,22 +702,22 @@ pub enum ControlMessageOwned { /// SockType::Datagram, /// SockFlag::empty(), /// None).unwrap(); - /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap(); + /// setsockopt(&in_socket, sockopt::ReceiveTimestamp, &true).unwrap(); /// let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); - /// bind(in_socket, &localhost).unwrap(); - /// let address: SockaddrIn = getsockname(in_socket).unwrap(); + /// bind(in_socket.as_raw_fd(), &localhost).unwrap(); + /// let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap(); /// // Get initial time /// let time0 = SystemTime::now(); /// // Send the message /// let iov = [IoSlice::new(message)]; /// let flags = MsgFlags::empty(); - /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); + /// let l = sendmsg(in_socket.as_raw_fd(), &iov, &[], flags, Some(&address)).unwrap(); /// assert_eq!(message.len(), l); /// // Receive the message /// let mut buffer = vec![0u8; message.len()]; /// let mut cmsgspace = cmsg_space!(TimeVal); /// let mut iov = [IoSliceMut::new(&mut buffer)]; - /// let r = recvmsg::(in_socket, &mut iov, Some(&mut cmsgspace), flags) + /// let r = recvmsg::(in_socket.as_raw_fd(), &mut iov, Some(&mut cmsgspace), flags) /// .unwrap(); /// let rtime = match r.cmsgs().next() { /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime, @@ -732,7 +733,6 @@ pub enum ControlMessageOwned { /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); /// // Close socket - /// nix::unistd::close(in_socket).unwrap(); /// # } /// ``` ScmTimestamp(TimeVal), @@ -1451,6 +1451,7 @@ impl<'a> ControlMessage<'a> { /// # use nix::sys::socket::*; /// # use nix::unistd::pipe; /// # use std::io::IoSlice; +/// # use std::os::unix::io::AsRawFd; /// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, /// SockFlag::empty()) /// .unwrap(); @@ -1459,7 +1460,7 @@ impl<'a> ControlMessage<'a> { /// let iov = [IoSlice::new(b"hello")]; /// let fds = [r]; /// let cmsg = ControlMessage::ScmRights(&fds); -/// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); +/// sendmsg::<()>(fd1.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); /// ``` /// When directing to a specific address, the generic type will be inferred. /// ``` @@ -1467,6 +1468,7 @@ impl<'a> ControlMessage<'a> { /// # use nix::unistd::pipe; /// # use std::io::IoSlice; /// # use std::str::FromStr; +/// # use std::os::unix::io::AsRawFd; /// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap(); /// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), /// None).unwrap(); @@ -1475,7 +1477,7 @@ impl<'a> ControlMessage<'a> { /// let iov = [IoSlice::new(b"hello")]; /// let fds = [r]; /// let cmsg = ControlMessage::ScmRights(&fds); -/// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); +/// sendmsg(fd.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); /// ``` pub fn sendmsg(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage], flags: MsgFlags, addr: Option<&S>) -> Result @@ -1823,6 +1825,7 @@ mod test { use crate::sys::socket::{AddressFamily, ControlMessageOwned}; use crate::*; use std::str::FromStr; + use std::os::unix::io::AsRawFd; #[cfg_attr(qemu, ignore)] #[test] @@ -1849,9 +1852,9 @@ mod test { None, )?; - crate::sys::socket::bind(rsock, &sock_addr)?; + crate::sys::socket::bind(rsock.as_raw_fd(), &sock_addr)?; - setsockopt(rsock, Timestamping, &TimestampingFlag::all())?; + setsockopt(&rsock, Timestamping, &TimestampingFlag::all())?; let sbuf = (0..400).map(|i| i as u8).collect::>(); @@ -1873,13 +1876,13 @@ mod test { let iov1 = [IoSlice::new(&sbuf)]; let cmsg = cmsg_space!(crate::sys::socket::Timestamps); - sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); + sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap(); let mut data = super::MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg)); let t = sys::time::TimeSpec::from_duration(std::time::Duration::from_secs(10)); - let recv = super::recvmmsg(rsock, &mut data, recv_iovs.iter(), flags, Some(t))?; + let recv = super::recvmmsg(rsock.as_raw_fd(), &mut data, recv_iovs.iter(), flags, Some(t))?; for rmsg in recv { #[cfg(not(any(qemu, target_arch = "aarch64")))] @@ -2091,7 +2094,7 @@ pub fn socket>>( ty: SockType, flags: SockFlag, protocol: T, -) -> Result { +) -> Result { let protocol = match protocol.into() { None => 0, Some(p) => p as c_int, @@ -2105,7 +2108,13 @@ pub fn socket>>( let res = unsafe { libc::socket(domain as c_int, ty, protocol) }; - Errno::result(res) + match res { + -1 => Err(Errno::last()), + fd => { + // Safe because libc::socket returned success + unsafe { Ok(OwnedFd::from_raw_fd(fd)) } + } + } } /// Create a pair of connected sockets @@ -2116,7 +2125,7 @@ pub fn socketpair>>( ty: SockType, protocol: T, flags: SockFlag, -) -> Result<(RawFd, RawFd)> { +) -> Result<(OwnedFd, OwnedFd)> { let protocol = match protocol.into() { None => 0, Some(p) => p as c_int, @@ -2135,14 +2144,18 @@ pub fn socketpair>>( }; Errno::result(res)?; - Ok((fds[0], fds[1])) + // Safe because socketpair returned success. + unsafe { + Ok((OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1]))) + } } /// Listen for connections on a socket /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html) -pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> { - let res = unsafe { libc::listen(sockfd, backlog as c_int) }; +pub fn listen(sock: &F, backlog: usize) -> Result<()> { + let fd = sock.as_fd().as_raw_fd(); + let res = unsafe { libc::listen(fd, backlog as c_int) }; Errno::result(res).map(drop) } @@ -2302,7 +2315,7 @@ pub trait GetSockOpt: Copy { type Val; /// Look up the value of this socket option on the given socket. - fn get(&self, fd: RawFd) -> Result; + fn get(&self, fd: &F) -> Result; } /// Represents a socket option that can be set. @@ -2310,13 +2323,13 @@ pub trait SetSockOpt: Clone { type Val; /// Set the value of this socket option on the given socket. - fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>; + fn set(&self, fd: &F, val: &Self::Val) -> Result<()>; } /// Get the current value for the requested socket option /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html) -pub fn getsockopt(fd: RawFd, opt: O) -> Result { +pub fn getsockopt(fd: &F, opt: O) -> Result { opt.get(fd) } @@ -2330,15 +2343,14 @@ pub fn getsockopt(fd: RawFd, opt: O) -> Result { /// use nix::sys::socket::setsockopt; /// use nix::sys::socket::sockopt::KeepAlive; /// use std::net::TcpListener; -/// use std::os::unix::io::AsRawFd; /// /// let listener = TcpListener::bind("0.0.0.0:0").unwrap(); -/// let fd = listener.as_raw_fd(); -/// let res = setsockopt(fd, KeepAlive, &true); +/// let fd = listener; +/// let res = setsockopt(&fd, KeepAlive, &true); /// assert!(res.is_ok()); /// ``` -pub fn setsockopt( - fd: RawFd, +pub fn setsockopt( + fd: &F, opt: O, val: &O::Val, ) -> Result<()> { diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index e4a22693c8..eec61dd416 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -9,7 +9,7 @@ use std::ffi::{OsStr, OsString}; use std::mem::{self, MaybeUninit}; #[cfg(target_family = "unix")] use std::os::unix::ffi::OsStrExt; -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsFd, AsRawFd}; // Constants // TCP_CA_NAME_MAX isn't defined in user space include files @@ -44,12 +44,12 @@ macro_rules! setsockopt_impl { impl SetSockOpt for $name { type Val = $ty; - fn set(&self, fd: RawFd, val: &$ty) -> Result<()> { + fn set(&self, fd: &F, val: &$ty) -> Result<()> { unsafe { let setter: $setter = Set::new(val); let res = libc::setsockopt( - fd, + fd.as_fd().as_raw_fd(), $level, $flag, setter.ffi_ptr(), @@ -89,12 +89,12 @@ macro_rules! getsockopt_impl { impl GetSockOpt for $name { type Val = $ty; - fn get(&self, fd: RawFd) -> Result<$ty> { + fn get(&self, fd: &F) -> Result<$ty> { unsafe { let mut getter: $getter = Get::uninit(); let res = libc::getsockopt( - fd, + fd.as_fd().as_raw_fd(), $level, $flag, getter.ffi_ptr(), @@ -1033,10 +1033,10 @@ pub struct AlgSetAeadAuthSize; impl SetSockOpt for AlgSetAeadAuthSize { type Val = usize; - fn set(&self, fd: RawFd, val: &usize) -> Result<()> { + fn set(&self, fd: &F, val: &usize) -> Result<()> { unsafe { let res = libc::setsockopt( - fd, + fd.as_fd().as_raw_fd(), libc::SOL_ALG, libc::ALG_SET_AEAD_AUTHSIZE, ::std::ptr::null(), @@ -1067,10 +1067,10 @@ where { type Val = T; - fn set(&self, fd: RawFd, val: &T) -> Result<()> { + fn set(&self, fd: &F, val: &T) -> Result<()> { unsafe { let res = libc::setsockopt( - fd, + fd.as_fd().as_raw_fd(), libc::SOL_ALG, libc::ALG_SET_KEY, val.as_ref().as_ptr() as *const _, @@ -1383,8 +1383,8 @@ mod test { SockFlag::empty(), ) .unwrap(); - let a_cred = getsockopt(a, super::PeerCredentials).unwrap(); - let b_cred = getsockopt(b, super::PeerCredentials).unwrap(); + let a_cred = getsockopt(&a, super::PeerCredentials).unwrap(); + let b_cred = getsockopt(&b, super::PeerCredentials).unwrap(); assert_eq!(a_cred, b_cred); assert_ne!(a_cred.pid(), 0); } @@ -1392,25 +1392,21 @@ mod test { #[test] fn is_socket_type_unix() { use super::super::*; - use crate::unistd::close; - let (a, b) = socketpair( + let (a, _b) = socketpair( AddressFamily::Unix, SockType::Stream, None, SockFlag::empty(), ) .unwrap(); - let a_type = getsockopt(a, super::SockType).unwrap(); + let a_type = getsockopt(&a, super::SockType).unwrap(); assert_eq!(a_type, SockType::Stream); - close(a).unwrap(); - close(b).unwrap(); } #[test] fn is_socket_type_dgram() { use super::super::*; - use crate::unistd::close; let s = socket( AddressFamily::Inet, @@ -1419,16 +1415,14 @@ mod test { None, ) .unwrap(); - let s_type = getsockopt(s, super::SockType).unwrap(); + let s_type = getsockopt(&s, super::SockType).unwrap(); assert_eq!(s_type, SockType::Datagram); - close(s).unwrap(); } #[cfg(any(target_os = "freebsd", target_os = "linux"))] #[test] fn can_get_listen_on_tcp_socket() { use super::super::*; - use crate::unistd::close; let s = socket( AddressFamily::Inet, @@ -1437,11 +1431,10 @@ mod test { None, ) .unwrap(); - let s_listening = getsockopt(s, super::AcceptConn).unwrap(); + let s_listening = getsockopt(&s, super::AcceptConn).unwrap(); assert!(!s_listening); - listen(s, 10).unwrap(); - let s_listening2 = getsockopt(s, super::AcceptConn).unwrap(); + listen(&s, 10).unwrap(); + let s_listening2 = getsockopt(&s, super::AcceptConn).unwrap(); assert!(s_listening2); - close(s).unwrap(); } } diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 0759dc609a..f93a7339c3 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -5,7 +5,7 @@ use nix::sys::socket::{getsockname, AddressFamily, UnixAddr}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::net::{SocketAddrV4, SocketAddrV6}; -use std::os::unix::io::RawFd; +use std::os::unix::io::{AsRawFd, RawFd}; use std::path::Path; use std::slice; use std::str::FromStr; @@ -38,9 +38,9 @@ pub fn test_timestamping() { None, ) .unwrap(); - nix::sys::socket::bind(rsock, &sock_addr).unwrap(); + nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap(); - setsockopt(rsock, Timestamping, &TimestampingFlag::all()).unwrap(); + setsockopt(&rsock, Timestamping, &TimestampingFlag::all()).unwrap(); let sbuf = [0u8; 2048]; let mut rbuf = [0u8; 2048]; @@ -49,8 +49,10 @@ pub fn test_timestamping() { let mut iov2 = [IoSliceMut::new(&mut rbuf)]; let mut cmsg = cmsg_space!(nix::sys::socket::Timestamps); - sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); - let recv = recvmsg::<()>(rsock, &mut iov2, Some(&mut cmsg), flags).unwrap(); + sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap(); + let recv = + recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags) + .unwrap(); let mut ts = None; for c in recv.cmsgs() { @@ -179,8 +181,11 @@ pub fn test_getsockname() { ) .expect("socket failed"); let sockaddr = UnixAddr::new(&sockname).unwrap(); - bind(sock, &sockaddr).expect("bind failed"); - assert_eq!(sockaddr, getsockname(sock).expect("getsockname failed")); + bind(sock.as_raw_fd(), &sockaddr).expect("bind failed"); + assert_eq!( + sockaddr, + getsockname(sock.as_raw_fd()).expect("getsockname failed") + ); } #[test] @@ -195,9 +200,9 @@ pub fn test_socketpair() { SockFlag::empty(), ) .unwrap(); - write(fd1, b"hello").unwrap(); + write(fd1.as_raw_fd(), b"hello").unwrap(); let mut buf = [0; 5]; - read(fd2, &mut buf).unwrap(); + read(fd2.as_raw_fd(), &mut buf).unwrap(); assert_eq!(&buf[..], b"hello"); } @@ -218,12 +223,12 @@ pub fn test_recvmsg_sockaddr_un() { ) .expect("socket failed"); let sockaddr = UnixAddr::new(&sockname).unwrap(); - bind(sock, &sockaddr).expect("bind failed"); + bind(sock.as_raw_fd(), &sockaddr).expect("bind failed"); // Send a message let send_buffer = "hello".as_bytes(); if let Err(e) = socket::sendmsg( - sock, + sock.as_raw_fd(), &[std::io::IoSlice::new(send_buffer)], &[], MsgFlags::empty(), @@ -235,7 +240,7 @@ pub fn test_recvmsg_sockaddr_un() { // Receive the message let mut recv_buffer = [0u8; 32]; let received = socket::recvmsg( - sock, + sock.as_raw_fd(), &mut [std::io::IoSliceMut::new(&mut recv_buffer)], None, MsgFlags::empty(), @@ -308,7 +313,7 @@ mod recvfrom { ) .unwrap(); // Ignore from for stream sockets - let _ = sendrecv(fd1, fd2, send, |_, _| {}); + let _ = sendrecv(fd1.as_raw_fd(), fd2.as_raw_fd(), send, |_, _| {}); } #[test] @@ -322,7 +327,7 @@ mod recvfrom { None, ) .unwrap(); - bind(rsock, &sock_addr).unwrap(); + bind(rsock.as_raw_fd(), &sock_addr).unwrap(); let ssock = socket( AddressFamily::Inet, SockType::Datagram, @@ -331,9 +336,9 @@ mod recvfrom { ) .expect("send socket failed"); let from = sendrecv( - rsock, - ssock, - move |s, m, flags| sendto(s, m, &sock_addr, flags), + rsock.as_raw_fd(), + ssock.as_raw_fd(), + move |s, m, flags| sendto(s.as_raw_fd(), m, &sock_addr, flags), |_, _| {}, ); // UDP sockets should set the from address @@ -367,10 +372,10 @@ mod recvfrom { ) .unwrap(); - setsockopt(rsock, UdpGsoSegment, &(segment_size as _)) + setsockopt(&rsock, UdpGsoSegment, &(segment_size as _)) .expect("setsockopt UDP_SEGMENT failed"); - bind(rsock, &sock_addr).unwrap(); + bind(rsock.as_raw_fd(), &sock_addr).unwrap(); let ssock = socket( AddressFamily::Inet, SockType::Datagram, @@ -382,12 +387,18 @@ mod recvfrom { let mut num_packets_received: i32 = 0; sendrecv( - rsock, - ssock, + rsock.as_raw_fd(), + ssock.as_raw_fd(), move |s, m, flags| { let iov = [IoSlice::new(m)]; let cmsg = ControlMessage::UdpGsoSegments(&segment_size); - sendmsg(s, &iov, &[cmsg], flags, Some(&sock_addr)) + sendmsg( + s.as_raw_fd(), + &iov, + &[cmsg], + flags, + Some(&sock_addr), + ) }, { let num_packets_received_ref = &mut num_packets_received; @@ -424,7 +435,7 @@ mod recvfrom { ) .unwrap(); - setsockopt(rsock, UdpGroSegment, &true) + setsockopt(&rsock, UdpGroSegment, &true) .expect("setsockopt UDP_GRO failed"); } } @@ -451,7 +462,7 @@ mod recvfrom { None, ) .unwrap(); - bind(rsock, &sock_addr).unwrap(); + bind(rsock.as_raw_fd(), &sock_addr).unwrap(); let ssock = socket( AddressFamily::Inet, SockType::Datagram, @@ -461,8 +472,8 @@ mod recvfrom { .expect("send socket failed"); let from = sendrecv( - rsock, - ssock, + rsock.as_raw_fd(), + ssock.as_raw_fd(), move |s, m, flags| { let batch_size = 15; let mut iovs = Vec::with_capacity(1 + batch_size); @@ -520,7 +531,7 @@ mod recvfrom { None, ) .unwrap(); - bind(rsock, &sock_addr).unwrap(); + bind(rsock.as_raw_fd(), &sock_addr).unwrap(); let ssock = socket( AddressFamily::Inet, SockType::Datagram, @@ -531,8 +542,13 @@ mod recvfrom { let send_thread = thread::spawn(move || { for _ in 0..NUM_MESSAGES_SENT { - sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()) - .unwrap(); + sendto( + ssock.as_raw_fd(), + &DATA[..], + &sock_addr, + MsgFlags::empty(), + ) + .unwrap(); } }); @@ -549,10 +565,15 @@ mod recvfrom { let mut data = MultiHeaders::::preallocate(msgs.len(), None); - let res: Vec> = - recvmmsg(rsock, &mut data, msgs.iter(), MsgFlags::empty(), None) - .expect("recvmmsg") - .collect(); + let res: Vec> = recvmmsg( + rsock.as_raw_fd(), + &mut data, + msgs.iter(), + MsgFlags::empty(), + None, + ) + .expect("recvmmsg") + .collect(); assert_eq!(res.len(), DATA.len()); for RecvMsg { address, bytes, .. } in res.into_iter() { @@ -591,7 +612,7 @@ mod recvfrom { None, ) .unwrap(); - bind(rsock, &sock_addr).unwrap(); + bind(rsock.as_raw_fd(), &sock_addr).unwrap(); let ssock = socket( AddressFamily::Inet, SockType::Datagram, @@ -602,8 +623,13 @@ mod recvfrom { let send_thread = thread::spawn(move || { for _ in 0..NUM_MESSAGES_SENT { - sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()) - .unwrap(); + sendto( + ssock.as_raw_fd(), + &DATA[..], + &sock_addr, + MsgFlags::empty(), + ) + .unwrap(); } }); // Ensure we've sent all the messages before continuing so `recvmmsg` @@ -628,7 +654,7 @@ mod recvfrom { ); let res: Vec> = recvmmsg( - rsock, + rsock.as_raw_fd(), &mut data, msgs.iter(), MsgFlags::MSG_DONTWAIT, @@ -664,7 +690,7 @@ mod recvfrom { None, ) .expect("receive socket failed"); - match bind(rsock, &raddr) { + match bind(rsock.as_raw_fd(), &raddr) { Err(Errno::EADDRNOTAVAIL) => { println!("IPv6 not available, skipping test."); return; @@ -679,11 +705,11 @@ mod recvfrom { None, ) .expect("send socket failed"); - bind(ssock, &saddr).unwrap(); + bind(ssock.as_raw_fd(), &saddr).unwrap(); let from = sendrecv( - rsock, - ssock, - move |s, m, flags| sendto(s, m, &raddr, flags), + rsock.as_raw_fd(), + ssock.as_raw_fd(), + move |s, m, flags| sendto(s.as_raw_fd(), m, &raddr, flags), |_, _| {}, ); assert_eq!(AddressFamily::Inet6, from.unwrap().family().unwrap()); @@ -705,7 +731,7 @@ pub fn test_recvmsg_ebadf() { let mut iov = [IoSliceMut::new(&mut buf[..])]; let fd = -1; // Bad file descriptor - let r = recvmsg::<()>(fd, &mut iov, None, MsgFlags::empty()); + let r = recvmsg::<()>(fd.as_raw_fd(), &mut iov, None, MsgFlags::empty()); assert_eq!(r.err().unwrap(), Errno::EBADF); } @@ -737,11 +763,17 @@ pub fn test_scm_rights() { let fds = [r]; let cmsg = ControlMessage::ScmRights(&fds); assert_eq!( - sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), + sendmsg::<()>( + fd1.as_raw_fd(), + &iov, + &[cmsg], + MsgFlags::empty(), + None + ) + .unwrap(), 5 ); close(r).unwrap(); - close(fd1).unwrap(); } { @@ -750,7 +782,7 @@ pub fn test_scm_rights() { let mut iov = [IoSliceMut::new(&mut buf[..])]; let mut cmsgspace = cmsg_space!([RawFd; 1]); let msg = recvmsg::<()>( - fd2, + fd2.as_raw_fd(), &mut iov, Some(&mut cmsgspace), MsgFlags::empty(), @@ -770,14 +802,13 @@ pub fn test_scm_rights() { assert!(!msg .flags .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - close(fd2).unwrap(); } let received_r = received_r.expect("Did not receive passed fd"); // Ensure that the received file descriptor works - write(w, b"world").unwrap(); + write(w.as_raw_fd(), b"world").unwrap(); let mut buf = [0u8; 5]; - read(received_r, &mut buf).unwrap(); + read(received_r.as_raw_fd(), &mut buf).unwrap(); assert_eq!(&buf[..], b"world"); close(received_r).unwrap(); close(w).unwrap(); @@ -821,25 +852,32 @@ pub fn test_af_alg_cipher() { .expect("socket failed"); let sockaddr = AlgAddr::new(alg_type, alg_name); - bind(sock, &sockaddr).expect("bind failed"); + bind(sock.as_raw_fd(), &sockaddr).expect("bind failed"); assert_eq!(sockaddr.alg_name().to_string_lossy(), alg_name); assert_eq!(sockaddr.alg_type().to_string_lossy(), alg_type); - setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt"); - let session_socket = accept(sock).expect("accept failed"); + setsockopt(&sock, AlgSetKey::default(), &key).expect("setsockopt"); + let session_socket = accept(sock.as_raw_fd()).expect("accept failed"); let msgs = [ ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), ControlMessage::AlgSetIv(iv.as_slice()), ]; let iov = IoSlice::new(&payload); - sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) - .expect("sendmsg encrypt"); + sendmsg::<()>( + session_socket.as_raw_fd(), + &[iov], + &msgs, + MsgFlags::empty(), + None, + ) + .expect("sendmsg encrypt"); // allocate buffer for encrypted data let mut encrypted = vec![0u8; payload_len]; - let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt"); + let num_bytes = + read(session_socket.as_raw_fd(), &mut encrypted).expect("read encrypt"); assert_eq!(num_bytes, payload_len); let iov = IoSlice::new(&encrypted); @@ -850,12 +888,19 @@ pub fn test_af_alg_cipher() { ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT), ControlMessage::AlgSetIv(iv.as_slice()), ]; - sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) - .expect("sendmsg decrypt"); + sendmsg::<()>( + session_socket.as_raw_fd(), + &[iov], + &msgs, + MsgFlags::empty(), + None, + ) + .expect("sendmsg decrypt"); // allocate buffer for decrypted data let mut decrypted = vec![0u8; payload_len]; - let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt"); + let num_bytes = + read(session_socket.as_raw_fd(), &mut decrypted).expect("read decrypt"); assert_eq!(num_bytes, payload_len); assert_eq!(decrypted, payload); @@ -874,7 +919,7 @@ pub fn test_af_alg_aead() { accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr, ControlMessage, MsgFlags, SockFlag, SockType, }; - use nix::unistd::{close, read}; + use nix::unistd::read; use std::io::IoSlice; skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352"); @@ -916,12 +961,13 @@ pub fn test_af_alg_aead() { .expect("socket failed"); let sockaddr = AlgAddr::new(alg_type, alg_name); - bind(sock, &sockaddr).expect("bind failed"); + bind(sock.as_raw_fd(), &sockaddr).expect("bind failed"); - setsockopt(sock, AlgSetAeadAuthSize, &auth_size) + setsockopt(&sock, AlgSetAeadAuthSize, &auth_size) .expect("setsockopt AlgSetAeadAuthSize"); - setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt AlgSetKey"); - let session_socket = accept(sock).expect("accept failed"); + setsockopt(&sock, AlgSetKey::default(), &key) + .expect("setsockopt AlgSetKey"); + let session_socket = accept(sock.as_raw_fd()).expect("accept failed"); let msgs = [ ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT), @@ -930,15 +976,21 @@ pub fn test_af_alg_aead() { ]; let iov = IoSlice::new(&payload); - sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) - .expect("sendmsg encrypt"); + sendmsg::<()>( + session_socket.as_raw_fd(), + &[iov], + &msgs, + MsgFlags::empty(), + None, + ) + .expect("sendmsg encrypt"); // allocate buffer for encrypted data let mut encrypted = vec![0u8; (assoc_size as usize) + payload_len + auth_size]; - let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt"); + let num_bytes = + read(session_socket.as_raw_fd(), &mut encrypted).expect("read encrypt"); assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize)); - close(session_socket).expect("close"); for i in 0..assoc_size { encrypted[i as usize] = 10; @@ -948,15 +1000,21 @@ pub fn test_af_alg_aead() { let iv = vec![1u8; iv_len]; - let session_socket = accept(sock).expect("accept failed"); + let session_socket = accept(sock.as_raw_fd()).expect("accept failed"); let msgs = [ ControlMessage::AlgSetOp(&ALG_OP_DECRYPT), ControlMessage::AlgSetIv(iv.as_slice()), ControlMessage::AlgSetAeadAssoclen(&assoc_size), ]; - sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None) - .expect("sendmsg decrypt"); + sendmsg::<()>( + session_socket.as_raw_fd(), + &[iov], + &msgs, + MsgFlags::empty(), + None, + ) + .expect("sendmsg decrypt"); // allocate buffer for decrypted data let mut decrypted = @@ -967,7 +1025,8 @@ pub fn test_af_alg_aead() { // Do not block on read, as we may have fewer bytes than buffer size fcntl(session_socket, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)) .expect("fcntl non_blocking"); - let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt"); + let num_bytes = + read(session_socket.as_raw_fd(), &mut decrypted).expect("read decrypt"); assert!(num_bytes >= payload_len + (assoc_size as usize)); assert_eq!( @@ -1003,7 +1062,7 @@ pub fn test_sendmsg_ipv4packetinfo() { let sock_addr = SockaddrIn::new(127, 0, 0, 1, 4000); - bind(sock, &sock_addr).expect("bind failed"); + bind(sock.as_raw_fd(), &sock_addr).expect("bind failed"); let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; let iov = [IoSlice::new(&slice)]; @@ -1025,8 +1084,14 @@ pub fn test_sendmsg_ipv4packetinfo() { let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)]; - sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) - .expect("sendmsg"); + sendmsg( + sock.as_raw_fd(), + &iov, + &cmsg, + MsgFlags::empty(), + Some(&sock_addr), + ) + .expect("sendmsg"); } // Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`. @@ -1063,7 +1128,7 @@ pub fn test_sendmsg_ipv6packetinfo() { let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap(); let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa); - if let Err(Errno::EADDRNOTAVAIL) = bind(sock, &sock_addr) { + if let Err(Errno::EADDRNOTAVAIL) = bind(sock.as_raw_fd(), &sock_addr) { println!("IPv6 not available, skipping test."); return; } @@ -1079,7 +1144,7 @@ pub fn test_sendmsg_ipv6packetinfo() { let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)]; sendmsg::( - sock, + sock.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), @@ -1119,8 +1184,8 @@ pub fn test_sendmsg_ipv4sendsrcaddr() { .expect("socket failed"); let unspec_sock_addr = SockaddrIn::new(0, 0, 0, 0, 0); - bind(sock, &unspec_sock_addr).expect("bind failed"); - let bound_sock_addr: SockaddrIn = getsockname(sock).unwrap(); + bind(sock.as_raw_fd(), &unspec_sock_addr).expect("bind failed"); + let bound_sock_addr: SockaddrIn = getsockname(sock.as_raw_fd()).unwrap(); let localhost_sock_addr: SockaddrIn = SockaddrIn::new(127, 0, 0, 1, bound_sock_addr.port()); @@ -1131,7 +1196,7 @@ pub fn test_sendmsg_ipv4sendsrcaddr() { )]; sendmsg( - sock, + sock.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), @@ -1208,7 +1273,6 @@ pub fn test_sendmsg_empty_cmsgs() { recvmsg, sendmsg, socketpair, AddressFamily, MsgFlags, SockFlag, SockType, }; - use nix::unistd::close; use std::io::{IoSlice, IoSliceMut}; let (fd1, fd2) = socketpair( @@ -1222,10 +1286,10 @@ pub fn test_sendmsg_empty_cmsgs() { { let iov = [IoSlice::new(b"hello")]; assert_eq!( - sendmsg::<()>(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), + sendmsg::<()>(fd1.as_raw_fd(), &iov, &[], MsgFlags::empty(), None) + .unwrap(), 5 ); - close(fd1).unwrap(); } { @@ -1234,7 +1298,7 @@ pub fn test_sendmsg_empty_cmsgs() { let mut cmsgspace = cmsg_space!([RawFd; 1]); let msg = recvmsg::<()>( - fd2, + fd2.as_raw_fd(), &mut iov, Some(&mut cmsgspace), MsgFlags::empty(), @@ -1248,7 +1312,6 @@ pub fn test_sendmsg_empty_cmsgs() { .flags .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); assert_eq!(msg.bytes, 5); - close(fd2).unwrap(); } } @@ -1266,7 +1329,7 @@ fn test_scm_credentials() { }; #[cfg(any(target_os = "android", target_os = "linux"))] use nix::sys::socket::{setsockopt, sockopt::PassCred}; - use nix::unistd::{close, getgid, getpid, getuid}; + use nix::unistd::{getgid, getpid, getuid}; use std::io::{IoSlice, IoSliceMut}; let (send, recv) = socketpair( @@ -1277,7 +1340,7 @@ fn test_scm_credentials() { ) .unwrap(); #[cfg(any(target_os = "android", target_os = "linux"))] - setsockopt(recv, PassCred, &true).unwrap(); + setsockopt(&recv, PassCred, &true).unwrap(); { let iov = [IoSlice::new(b"hello")]; @@ -1288,11 +1351,16 @@ fn test_scm_credentials() { #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] let cmsg = ControlMessage::ScmCreds; assert_eq!( - sendmsg::<()>(send, &iov, &[cmsg], MsgFlags::empty(), None) - .unwrap(), + sendmsg::<()>( + send.as_raw_fd(), + &iov, + &[cmsg], + MsgFlags::empty(), + None + ) + .unwrap(), 5 ); - close(send).unwrap(); } { @@ -1301,7 +1369,7 @@ fn test_scm_credentials() { let mut cmsgspace = cmsg_space!(UnixCredentials); let msg = recvmsg::<()>( - recv, + recv.as_raw_fd(), &mut iov, Some(&mut cmsgspace), MsgFlags::empty(), @@ -1328,7 +1396,6 @@ fn test_scm_credentials() { assert!(!msg .flags .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - close(recv).unwrap(); } } @@ -1374,7 +1441,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { SockFlag::empty(), ) .unwrap(); - setsockopt(recv, PassCred, &true).unwrap(); + setsockopt(&recv, PassCred, &true).unwrap(); let (r, w) = pipe().unwrap(); let mut received_r: Option = None; @@ -1393,19 +1460,29 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { ControlMessage::ScmRights(&fds), ]; assert_eq!( - sendmsg::<()>(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(), + sendmsg::<()>( + send.as_raw_fd(), + &iov, + &cmsgs, + MsgFlags::empty(), + None + ) + .unwrap(), 5 ); close(r).unwrap(); - close(send).unwrap(); } { let mut buf = [0u8; 5]; let mut iov = [IoSliceMut::new(&mut buf[..])]; - let msg = - recvmsg::<()>(recv, &mut iov, Some(&mut space), MsgFlags::empty()) - .unwrap(); + let msg = recvmsg::<()>( + recv.as_raw_fd(), + &mut iov, + Some(&mut space), + MsgFlags::empty(), + ) + .unwrap(); let mut received_cred = None; assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs"); @@ -1432,14 +1509,13 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { assert!(!msg .flags .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)); - close(recv).unwrap(); } let received_r = received_r.expect("Did not receive passed fd"); // Ensure that the received file descriptor works - write(w, b"world").unwrap(); + write(w.as_raw_fd(), b"world").unwrap(); let mut buf = [0u8; 5]; - read(received_r, &mut buf).unwrap(); + read(received_r.as_raw_fd(), &mut buf).unwrap(); assert_eq!(&buf[..], b"world"); close(received_r).unwrap(); close(w).unwrap(); @@ -1450,7 +1526,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec) { pub fn test_named_unixdomain() { use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr}; use nix::sys::socket::{SockFlag, SockType}; - use nix::unistd::{close, read, write}; + use nix::unistd::{read, write}; use std::thread; let tempdir = tempfile::tempdir().unwrap(); @@ -1463,8 +1539,8 @@ pub fn test_named_unixdomain() { ) .expect("socket failed"); let sockaddr = UnixAddr::new(&sockname).unwrap(); - bind(s1, &sockaddr).expect("bind failed"); - listen(s1, 10).expect("listen failed"); + bind(s1.as_raw_fd(), &sockaddr).expect("bind failed"); + listen(&s1, 10).expect("listen failed"); let thr = thread::spawn(move || { let s2 = socket( @@ -1474,17 +1550,14 @@ pub fn test_named_unixdomain() { None, ) .expect("socket failed"); - connect(s2, &sockaddr).expect("connect failed"); - write(s2, b"hello").expect("write failed"); - close(s2).unwrap(); + connect(s2.as_raw_fd(), &sockaddr).expect("connect failed"); + write(s2.as_raw_fd(), b"hello").expect("write failed"); }); - let s3 = accept(s1).expect("accept failed"); + let s3 = accept(s1.as_raw_fd()).expect("accept failed"); let mut buf = [0; 5]; - read(s3, &mut buf).unwrap(); - close(s3).unwrap(); - close(s1).unwrap(); + read(s3.as_raw_fd(), &mut buf).unwrap(); thr.join().unwrap(); assert_eq!(&buf[..], b"hello"); @@ -1496,9 +1569,8 @@ pub fn test_named_unixdomain() { pub fn test_unnamed_unixdomain() { use nix::sys::socket::{getsockname, socketpair}; use nix::sys::socket::{SockFlag, SockType}; - use nix::unistd::close; - let (fd_1, fd_2) = socketpair( + let (fd_1, _fd_2) = socketpair( AddressFamily::Unix, SockType::Stream, None, @@ -1506,11 +1578,9 @@ pub fn test_unnamed_unixdomain() { ) .expect("socketpair failed"); - let addr_1: UnixAddr = getsockname(fd_1).expect("getsockname failed"); + let addr_1: UnixAddr = + getsockname(fd_1.as_raw_fd()).expect("getsockname failed"); assert!(addr_1.is_unnamed()); - - close(fd_1).unwrap(); - close(fd_2).unwrap(); } // Test creating and using unnamed unix domain addresses for autobinding sockets @@ -1519,7 +1589,6 @@ pub fn test_unnamed_unixdomain() { pub fn test_unnamed_unixdomain_autobind() { use nix::sys::socket::{bind, getsockname, socket}; use nix::sys::socket::{SockFlag, SockType}; - use nix::unistd::close; let fd = socket( AddressFamily::Unix, @@ -1531,16 +1600,15 @@ pub fn test_unnamed_unixdomain_autobind() { // unix(7): "If a bind(2) call specifies addrlen as `sizeof(sa_family_t)`, or [...], then the // socket is autobound to an abstract address" - bind(fd, &UnixAddr::new_unnamed()).expect("bind failed"); + bind(fd.as_raw_fd(), &UnixAddr::new_unnamed()).expect("bind failed"); - let addr: UnixAddr = getsockname(fd).expect("getsockname failed"); + let addr: UnixAddr = + getsockname(fd.as_raw_fd()).expect("getsockname failed"); let addr = addr.as_abstract().unwrap(); // changed from 8 to 5 bytes in Linux 2.3.15, and rust's minimum supported Linux version is 3.2 // (as of 2022-11) assert_eq!(addr.len(), 5); - - close(fd).unwrap(); } // Test creating and using named system control sockets @@ -1559,15 +1627,15 @@ pub fn test_syscontrol() { SockProtocol::KextControl, ) .expect("socket failed"); - SysControlAddr::from_name(fd, "com.apple.net.utun_control", 0) + SysControlAddr::from_name(fd.as_raw_fd(), "com.apple.net.utun_control", 0) .expect("resolving sys_control name failed"); assert_eq!( - SysControlAddr::from_name(fd, "foo.bar.lol", 0).err(), + SysControlAddr::from_name(fd.as_raw_fd(), "foo.bar.lol", 0).err(), Some(Errno::ENOENT) ); // requires root privileges - // connect(fd, &sockaddr).expect("connect failed"); + // connect(fd.as_raw_fd(), &sockaddr).expect("connect failed"); } #[cfg(any( @@ -1648,9 +1716,10 @@ pub fn test_recv_ipv4pktinfo() { None, ) .expect("receive socket failed"); - bind(receive, &lo).expect("bind failed"); - let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); - setsockopt(receive, Ipv4PacketInfo, &true).expect("setsockopt failed"); + bind(receive.as_raw_fd(), &lo).expect("bind failed"); + let sa: SockaddrIn = + getsockname(receive.as_raw_fd()).expect("getsockname failed"); + setsockopt(&receive, Ipv4PacketInfo, &true).expect("setsockopt failed"); { let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; @@ -1663,7 +1732,7 @@ pub fn test_recv_ipv4pktinfo() { None, ) .expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa)) .expect("sendmsg failed"); } @@ -1673,7 +1742,7 @@ pub fn test_recv_ipv4pktinfo() { let mut space = cmsg_space!(libc::in_pktinfo); let msg = recvmsg::<()>( - receive, + receive.as_raw_fd(), &mut iovec, Some(&mut space), MsgFlags::empty(), @@ -1742,11 +1811,12 @@ pub fn test_recvif() { None, ) .expect("receive socket failed"); - bind(receive, &lo).expect("bind failed"); - let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); - setsockopt(receive, Ipv4RecvIf, &true) + bind(receive.as_raw_fd(), &lo).expect("bind failed"); + let sa: SockaddrIn = + getsockname(receive.as_raw_fd()).expect("getsockname failed"); + setsockopt(&receive, Ipv4RecvIf, &true) .expect("setsockopt IP_RECVIF failed"); - setsockopt(receive, Ipv4RecvDstAddr, &true) + setsockopt(&receive, Ipv4RecvDstAddr, &true) .expect("setsockopt IP_RECVDSTADDR failed"); { @@ -1760,7 +1830,7 @@ pub fn test_recvif() { None, ) .expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa)) .expect("sendmsg failed"); } @@ -1769,7 +1839,7 @@ pub fn test_recvif() { let mut iovec = [IoSliceMut::new(&mut buf)]; let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr); let msg = recvmsg::<()>( - receive, + receive.as_raw_fd(), &mut iovec, Some(&mut space), MsgFlags::empty(), @@ -1841,9 +1911,10 @@ pub fn test_recvif_ipv4() { None, ) .expect("receive socket failed"); - bind(receive, &lo).expect("bind failed"); - let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); - setsockopt(receive, Ipv4OrigDstAddr, &true) + bind(receive.as_raw_fd(), &lo).expect("bind failed"); + let sa: SockaddrIn = + getsockname(receive.as_raw_fd()).expect("getsockname failed"); + setsockopt(&receive, Ipv4OrigDstAddr, &true) .expect("setsockopt IP_ORIGDSTADDR failed"); { @@ -1857,7 +1928,7 @@ pub fn test_recvif_ipv4() { None, ) .expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa)) .expect("sendmsg failed"); } @@ -1866,7 +1937,7 @@ pub fn test_recvif_ipv4() { let mut iovec = [IoSliceMut::new(&mut buf)]; let mut space = cmsg_space!(libc::sockaddr_in); let msg = recvmsg::<()>( - receive, + receive.as_raw_fd(), &mut iovec, Some(&mut space), MsgFlags::empty(), @@ -1926,9 +1997,10 @@ pub fn test_recvif_ipv6() { None, ) .expect("receive socket failed"); - bind(receive, &lo).expect("bind failed"); - let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed"); - setsockopt(receive, Ipv6OrigDstAddr, &true) + bind(receive.as_raw_fd(), &lo).expect("bind failed"); + let sa: SockaddrIn6 = + getsockname(receive.as_raw_fd()).expect("getsockname failed"); + setsockopt(&receive, Ipv6OrigDstAddr, &true) .expect("setsockopt IP_ORIGDSTADDR failed"); { @@ -1942,7 +2014,7 @@ pub fn test_recvif_ipv6() { None, ) .expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa)) .expect("sendmsg failed"); } @@ -1951,7 +2023,7 @@ pub fn test_recvif_ipv6() { let mut iovec = [IoSliceMut::new(&mut buf)]; let mut space = cmsg_space!(libc::sockaddr_in6); let msg = recvmsg::<()>( - receive, + receive.as_raw_fd(), &mut iovec, Some(&mut space), MsgFlags::empty(), @@ -2031,9 +2103,10 @@ pub fn test_recv_ipv6pktinfo() { None, ) .expect("receive socket failed"); - bind(receive, &lo).expect("bind failed"); - let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed"); - setsockopt(receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed"); + bind(receive.as_raw_fd(), &lo).expect("bind failed"); + let sa: SockaddrIn6 = + getsockname(receive.as_raw_fd()).expect("getsockname failed"); + setsockopt(&receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed"); { let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; @@ -2046,7 +2119,7 @@ pub fn test_recv_ipv6pktinfo() { None, ) .expect("send socket failed"); - sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)) + sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa)) .expect("sendmsg failed"); } @@ -2056,7 +2129,7 @@ pub fn test_recv_ipv6pktinfo() { let mut space = cmsg_space!(libc::in6_pktinfo); let msg = recvmsg::<()>( - receive, + receive.as_raw_fd(), &mut iovec, Some(&mut space), MsgFlags::empty(), @@ -2185,24 +2258,30 @@ fn test_recvmsg_timestampns() { None, ) .unwrap(); - setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); + setsockopt(&in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); let localhost = SockaddrIn::new(127, 0, 0, 1, 0); - bind(in_socket, &localhost).unwrap(); - let address: SockaddrIn = getsockname(in_socket).unwrap(); + bind(in_socket.as_raw_fd(), &localhost).unwrap(); + let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap(); // Get initial time let time0 = SystemTime::now(); // Send the message let iov = [IoSlice::new(message)]; let flags = MsgFlags::empty(); - let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); + let l = sendmsg(in_socket.as_raw_fd(), &iov, &[], flags, Some(&address)) + .unwrap(); assert_eq!(message.len(), l); // Receive the message let mut buffer = vec![0u8; message.len()]; let mut cmsgspace = nix::cmsg_space!(TimeSpec); let mut iov = [IoSliceMut::new(&mut buffer)]; - let r = recvmsg::<()>(in_socket, &mut iov, Some(&mut cmsgspace), flags) - .unwrap(); + let r = recvmsg::<()>( + in_socket.as_raw_fd(), + &mut iov, + Some(&mut cmsgspace), + flags, + ) + .unwrap(); let rtime = match r.cmsgs().next() { Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, Some(_) => panic!("Unexpected control message"), @@ -2216,8 +2295,6 @@ fn test_recvmsg_timestampns() { Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32); assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); - // Close socket - nix::unistd::close(in_socket).unwrap(); } // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack @@ -2240,16 +2317,17 @@ fn test_recvmmsg_timestampns() { None, ) .unwrap(); - setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); + setsockopt(&in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); - bind(in_socket, &localhost).unwrap(); - let address: SockaddrIn = getsockname(in_socket).unwrap(); + bind(in_socket.as_raw_fd(), &localhost).unwrap(); + let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap(); // Get initial time let time0 = SystemTime::now(); // Send the message let iov = [IoSlice::new(message)]; let flags = MsgFlags::empty(); - let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); + let l = sendmsg(in_socket.as_raw_fd(), &iov, &[], flags, Some(&address)) + .unwrap(); assert_eq!(message.len(), l); // Receive the message let mut buffer = vec![0u8; message.len()]; @@ -2257,7 +2335,7 @@ fn test_recvmmsg_timestampns() { let iov = vec![[IoSliceMut::new(&mut buffer)]]; let mut data = MultiHeaders::preallocate(1, Some(cmsgspace)); let r: Vec> = - recvmmsg(in_socket, &mut data, iov.iter(), flags, None) + recvmmsg(in_socket.as_raw_fd(), &mut data, iov.iter(), flags, None) .unwrap() .collect(); let rtime = match r[0].cmsgs().next() { @@ -2273,8 +2351,6 @@ fn test_recvmmsg_timestampns() { Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32); assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); - // Close socket - nix::unistd::close(in_socket).unwrap(); } // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack @@ -2307,16 +2383,16 @@ fn test_recvmsg_rxq_ovfl() { .unwrap(); let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); - bind(in_socket, &localhost).unwrap(); + bind(in_socket.as_raw_fd(), &localhost).unwrap(); - let address: SockaddrIn = getsockname(in_socket).unwrap(); - connect(out_socket, &address).unwrap(); + let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap(); + connect(out_socket.as_raw_fd(), &address).unwrap(); // Set SO_RXQ_OVFL flag. - setsockopt(in_socket, RxqOvfl, &1).unwrap(); + setsockopt(&in_socket, RxqOvfl, &1).unwrap(); // Set the receiver buffer size to hold only 2 messages. - setsockopt(in_socket, RcvBuf, &bufsize).unwrap(); + setsockopt(&in_socket, RcvBuf, &bufsize).unwrap(); let mut drop_counter = 0; @@ -2327,8 +2403,14 @@ fn test_recvmsg_rxq_ovfl() { // Send the 3 messages (the receiver buffer can only hold 2 messages) // to create an overflow. for _ in 0..3 { - let l = - sendmsg(out_socket, &iov, &[], flags, Some(&address)).unwrap(); + let l = sendmsg( + out_socket.as_raw_fd(), + &iov, + &[], + flags, + Some(&address), + ) + .unwrap(); assert_eq!(message.len(), l); } @@ -2340,7 +2422,7 @@ fn test_recvmsg_rxq_ovfl() { let mut iov = [IoSliceMut::new(&mut buffer)]; match recvmsg::<()>( - in_socket, + in_socket.as_raw_fd(), &mut iov, Some(&mut cmsgspace), MsgFlags::MSG_DONTWAIT, @@ -2366,16 +2448,13 @@ fn test_recvmsg_rxq_ovfl() { // One packet lost. assert_eq!(drop_counter, 1); - - // Close sockets - nix::unistd::close(in_socket).unwrap(); - nix::unistd::close(out_socket).unwrap(); } #[cfg(any(target_os = "linux", target_os = "android",))] mod linux_errqueue { use super::FromStr; use nix::sys::socket::*; + use std::os::unix::io::AsRawFd; // Send a UDP datagram to a bogus destination address and observe an ICMP error (v4). // @@ -2496,9 +2575,9 @@ mod linux_errqueue { let sock_addr = SockaddrStorage::from(std_sa); let sock = socket(af, SockType::Datagram, SockFlag::SOCK_CLOEXEC, None) .unwrap(); - setsockopt(sock, opt, &true).unwrap(); + setsockopt(&sock, opt, &true).unwrap(); if let Err(e) = sendto( - sock, + sock.as_raw_fd(), MESSAGE_CONTENTS.as_bytes(), &sock_addr, MsgFlags::empty(), @@ -2513,7 +2592,7 @@ mod linux_errqueue { let mut cspace = cmsg_space!(libc::sock_extended_err, SA); let msg = recvmsg( - sock, + sock.as_raw_fd(), &mut iovec, Some(&mut cspace), MsgFlags::MSG_ERRQUEUE, @@ -2576,7 +2655,7 @@ pub fn test_txtime() { clockid: libc::CLOCK_MONOTONIC, flags: 0, }; - setsockopt(ssock, sockopt::TxTime, &txtime_cfg).unwrap(); + setsockopt(&ssock, sockopt::TxTime, &txtime_cfg).unwrap(); let rsock = socket( AddressFamily::Inet, @@ -2585,7 +2664,7 @@ pub fn test_txtime() { None, ) .unwrap(); - bind(rsock, &sock_addr).unwrap(); + bind(rsock.as_raw_fd(), &sock_addr).unwrap(); let sbuf = [0u8; 2048]; let iov1 = [std::io::IoSlice::new(&sbuf)]; @@ -2595,10 +2674,17 @@ pub fn test_txtime() { let txtime = (now + delay).num_nanoseconds() as u64; let cmsg = ControlMessage::TxTime(&txtime); - sendmsg(ssock, &iov1, &[cmsg], MsgFlags::empty(), Some(&sock_addr)) - .unwrap(); + sendmsg( + ssock.as_raw_fd(), + &iov1, + &[cmsg], + MsgFlags::empty(), + Some(&sock_addr), + ) + .unwrap(); let mut rbuf = [0u8; 2048]; let mut iov2 = [std::io::IoSliceMut::new(&mut rbuf)]; - recvmsg::<()>(rsock, &mut iov2, None, MsgFlags::empty()).unwrap(); + recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, None, MsgFlags::empty()) + .unwrap(); } diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index a498bdfa2c..0e34917325 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -5,6 +5,7 @@ use nix::sys::socket::{ SockProtocol, SockType, }; use rand::{thread_rng, Rng}; +use std::os::unix::io::AsRawFd; // NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not. #[cfg(any(target_os = "dragonfly", target_os = "freebsd",))] @@ -22,7 +23,7 @@ pub fn test_local_peercred_seqpacket() { SockFlag::empty(), ) .unwrap(); - let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap(); + let xucred = getsockopt(&fd1, sockopt::LocalPeerCred).unwrap(); assert_eq!(xucred.version(), 0); assert_eq!(Uid::from_raw(xucred.uid()), Uid::current()); assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); @@ -48,7 +49,7 @@ pub fn test_local_peercred_stream() { SockFlag::empty(), ) .unwrap(); - let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap(); + let xucred = getsockopt(&fd1, sockopt::LocalPeerCred).unwrap(); assert_eq!(xucred.version(), 0); assert_eq!(Uid::from_raw(xucred.uid()), Uid::current()); assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current()); @@ -66,7 +67,7 @@ pub fn test_local_peer_pid() { SockFlag::empty(), ) .unwrap(); - let pid = getsockopt(fd1, sockopt::LocalPeerPid).unwrap(); + let pid = getsockopt(&fd1, sockopt::LocalPeerPid).unwrap(); assert_eq!(pid, std::process::id() as _); } @@ -84,8 +85,8 @@ fn is_so_mark_functional() { None, ) .unwrap(); - setsockopt(s, sockopt::Mark, &1337).unwrap(); - let mark = getsockopt(s, sockopt::Mark).unwrap(); + setsockopt(&s, sockopt::Mark, &1337).unwrap(); + let mark = getsockopt(&s, sockopt::Mark).unwrap(); assert_eq!(mark, 1337); } @@ -99,18 +100,18 @@ fn test_so_buf() { ) .unwrap(); let bufsize: usize = thread_rng().gen_range(4096..131_072); - setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap(); - let actual = getsockopt(fd, sockopt::SndBuf).unwrap(); + setsockopt(&fd, sockopt::SndBuf, &bufsize).unwrap(); + let actual = getsockopt(&fd, sockopt::SndBuf).unwrap(); assert!(actual >= bufsize); - setsockopt(fd, sockopt::RcvBuf, &bufsize).unwrap(); - let actual = getsockopt(fd, sockopt::RcvBuf).unwrap(); + setsockopt(&fd, sockopt::RcvBuf, &bufsize).unwrap(); + let actual = getsockopt(&fd, sockopt::RcvBuf).unwrap(); assert!(actual >= bufsize); } #[test] fn test_so_tcp_maxseg() { use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn}; - use nix::unistd::{close, write}; + use nix::unistd::write; use std::net::SocketAddrV4; use std::str::FromStr; @@ -124,9 +125,9 @@ fn test_so_tcp_maxseg() { SockProtocol::Tcp, ) .unwrap(); - bind(rsock, &sock_addr).unwrap(); - listen(rsock, 10).unwrap(); - let initial = getsockopt(rsock, sockopt::TcpMaxSeg).unwrap(); + bind(rsock.as_raw_fd(), &sock_addr).unwrap(); + listen(&rsock, 10).unwrap(); + let initial = getsockopt(&rsock, sockopt::TcpMaxSeg).unwrap(); // Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some // platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger // than 700 @@ -134,7 +135,7 @@ fn test_so_tcp_maxseg() { if #[cfg(any(target_os = "android", target_os = "linux"))] { let segsize: u32 = 873; assert!(initial < segsize); - setsockopt(rsock, sockopt::TcpMaxSeg, &segsize).unwrap(); + setsockopt(&rsock, sockopt::TcpMaxSeg, &segsize).unwrap(); } else { assert!(initial < 700); } @@ -148,10 +149,10 @@ fn test_so_tcp_maxseg() { SockProtocol::Tcp, ) .unwrap(); - connect(ssock, &sock_addr).unwrap(); - let rsess = accept(rsock).unwrap(); + connect(ssock.as_raw_fd(), &sock_addr).unwrap(); + let rsess = accept(rsock.as_raw_fd()).unwrap(); write(rsess, b"hello").unwrap(); - let actual = getsockopt(ssock, sockopt::TcpMaxSeg).unwrap(); + let actual = getsockopt(&ssock, sockopt::TcpMaxSeg).unwrap(); // Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max // TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary. cfg_if! { @@ -163,8 +164,6 @@ fn test_so_tcp_maxseg() { assert!(536 < actual); } } - close(rsock).unwrap(); - close(ssock).unwrap(); } #[test] @@ -177,7 +176,7 @@ fn test_so_type() { ) .unwrap(); - assert_eq!(Ok(SockType::Stream), getsockopt(sockfd, sockopt::SockType)); + assert_eq!(Ok(SockType::Stream), getsockopt(&sockfd, sockopt::SockType)); } /// getsockopt(_, sockopt::SockType) should gracefully handle unknown socket @@ -186,12 +185,14 @@ fn test_so_type() { #[test] fn test_so_type_unknown() { use nix::errno::Errno; + use std::os::unix::io::{FromRawFd, OwnedFd}; require_capability!("test_so_type", CAP_NET_RAW); - let sockfd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) }; - assert!(sockfd >= 0, "Error opening socket: {}", nix::Error::last()); + let raw_fd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) }; + assert!(raw_fd >= 0, "Error opening socket: {}", nix::Error::last()); + let sockfd = unsafe { OwnedFd::from_raw_fd(raw_fd) }; - assert_eq!(Err(Errno::EINVAL), getsockopt(sockfd, sockopt::SockType)); + assert_eq!(Err(Errno::EINVAL), getsockopt(&sockfd, sockopt::SockType)); } // The CI doesn't supported getsockopt and setsockopt on emulated processors. @@ -214,17 +215,17 @@ fn test_tcp_congestion() { ) .unwrap(); - let val = getsockopt(fd, sockopt::TcpCongestion).unwrap(); - setsockopt(fd, sockopt::TcpCongestion, &val).unwrap(); + let val = getsockopt(&fd, sockopt::TcpCongestion).unwrap(); + setsockopt(&fd, sockopt::TcpCongestion, &val).unwrap(); setsockopt( - fd, + &fd, sockopt::TcpCongestion, &OsString::from("tcp_congestion_does_not_exist"), ) .unwrap_err(); - assert_eq!(getsockopt(fd, sockopt::TcpCongestion).unwrap(), val); + assert_eq!(getsockopt(&fd, sockopt::TcpCongestion).unwrap(), val); } #[test] @@ -240,10 +241,10 @@ fn test_bindtodevice() { ) .unwrap(); - let val = getsockopt(fd, sockopt::BindToDevice).unwrap(); - setsockopt(fd, sockopt::BindToDevice, &val).unwrap(); + let val = getsockopt(&fd, sockopt::BindToDevice).unwrap(); + setsockopt(&fd, sockopt::BindToDevice, &val).unwrap(); - assert_eq!(getsockopt(fd, sockopt::BindToDevice).unwrap(), val); + assert_eq!(getsockopt(&fd, sockopt::BindToDevice).unwrap(), val); } #[test] @@ -255,8 +256,8 @@ fn test_so_tcp_keepalive() { SockProtocol::Tcp, ) .unwrap(); - setsockopt(fd, sockopt::KeepAlive, &true).unwrap(); - assert!(getsockopt(fd, sockopt::KeepAlive).unwrap()); + setsockopt(&fd, sockopt::KeepAlive, &true).unwrap(); + assert!(getsockopt(&fd, sockopt::KeepAlive).unwrap()); #[cfg(any( target_os = "android", @@ -265,17 +266,17 @@ fn test_so_tcp_keepalive() { target_os = "linux" ))] { - let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap(); - setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap(); - assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1); + let x = getsockopt(&fd, sockopt::TcpKeepIdle).unwrap(); + setsockopt(&fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap(); + assert_eq!(getsockopt(&fd, sockopt::TcpKeepIdle).unwrap(), x + 1); - let x = getsockopt(fd, sockopt::TcpKeepCount).unwrap(); - setsockopt(fd, sockopt::TcpKeepCount, &(x + 1)).unwrap(); - assert_eq!(getsockopt(fd, sockopt::TcpKeepCount).unwrap(), x + 1); + let x = getsockopt(&fd, sockopt::TcpKeepCount).unwrap(); + setsockopt(&fd, sockopt::TcpKeepCount, &(x + 1)).unwrap(); + assert_eq!(getsockopt(&fd, sockopt::TcpKeepCount).unwrap(), x + 1); - let x = getsockopt(fd, sockopt::TcpKeepInterval).unwrap(); - setsockopt(fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap(); - assert_eq!(getsockopt(fd, sockopt::TcpKeepInterval).unwrap(), x + 1); + let x = getsockopt(&fd, sockopt::TcpKeepInterval).unwrap(); + setsockopt(&fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap(); + assert_eq!(getsockopt(&fd, sockopt::TcpKeepInterval).unwrap(), x + 1); } } @@ -299,11 +300,11 @@ fn test_get_mtu() { .unwrap(); // Bind and initiate connection - bind(usock, &SockaddrIn::from(std_sa)).unwrap(); - connect(usock, &SockaddrIn::from(std_sb)).unwrap(); + bind(usock.as_raw_fd(), &SockaddrIn::from(std_sa)).unwrap(); + connect(usock.as_raw_fd(), &SockaddrIn::from(std_sb)).unwrap(); // Loopback connections have 2^16 - the maximum - MTU - assert_eq!(getsockopt(usock, sockopt::IpMtu), Ok(u16::MAX as i32)) + assert_eq!(getsockopt(&usock, sockopt::IpMtu), Ok(u16::MAX as i32)) } #[test] @@ -316,7 +317,7 @@ fn test_ttl_opts() { None, ) .unwrap(); - setsockopt(fd4, sockopt::Ipv4Ttl, &1) + setsockopt(&fd4, sockopt::Ipv4Ttl, &1) .expect("setting ipv4ttl on an inet socket should succeed"); let fd6 = socket( AddressFamily::Inet6, @@ -325,7 +326,7 @@ fn test_ttl_opts() { None, ) .unwrap(); - setsockopt(fd6, sockopt::Ipv6Ttl, &1) + setsockopt(&fd6, sockopt::Ipv6Ttl, &1) .expect("setting ipv6ttl on an inet6 socket should succeed"); } @@ -339,9 +340,9 @@ fn test_dontfrag_opts() { SockProtocol::Tcp, ) .unwrap(); - setsockopt(fd4, sockopt::IpDontFrag, &true) + setsockopt(&fd4, sockopt::IpDontFrag, &true) .expect("setting IP_DONTFRAG on an inet stream socket should succeed"); - setsockopt(fd4, sockopt::IpDontFrag, &false).expect( + setsockopt(&fd4, sockopt::IpDontFrag, &false).expect( "unsetting IP_DONTFRAG on an inet stream socket should succeed", ); let fd4d = socket( @@ -351,10 +352,10 @@ fn test_dontfrag_opts() { None, ) .unwrap(); - setsockopt(fd4d, sockopt::IpDontFrag, &true).expect( + setsockopt(&fd4d, sockopt::IpDontFrag, &true).expect( "setting IP_DONTFRAG on an inet datagram socket should succeed", ); - setsockopt(fd4d, sockopt::IpDontFrag, &false).expect( + setsockopt(&fd4d, sockopt::IpDontFrag, &false).expect( "unsetting IP_DONTFRAG on an inet datagram socket should succeed", ); } @@ -377,10 +378,10 @@ fn test_v6dontfrag_opts() { SockProtocol::Tcp, ) .unwrap(); - setsockopt(fd6, sockopt::Ipv6DontFrag, &true).expect( + setsockopt(&fd6, sockopt::Ipv6DontFrag, &true).expect( "setting IPV6_DONTFRAG on an inet6 stream socket should succeed", ); - setsockopt(fd6, sockopt::Ipv6DontFrag, &false).expect( + setsockopt(&fd6, sockopt::Ipv6DontFrag, &false).expect( "unsetting IPV6_DONTFRAG on an inet6 stream socket should succeed", ); let fd6d = socket( @@ -390,10 +391,10 @@ fn test_v6dontfrag_opts() { None, ) .unwrap(); - setsockopt(fd6d, sockopt::Ipv6DontFrag, &true).expect( + setsockopt(&fd6d, sockopt::Ipv6DontFrag, &true).expect( "setting IPV6_DONTFRAG on an inet6 datagram socket should succeed", ); - setsockopt(fd6d, sockopt::Ipv6DontFrag, &false).expect( + setsockopt(&fd6d, sockopt::Ipv6DontFrag, &false).expect( "unsetting IPV6_DONTFRAG on an inet6 datagram socket should succeed", ); } @@ -409,8 +410,8 @@ fn test_so_priority() { ) .unwrap(); let priority = 3; - setsockopt(fd, sockopt::Priority, &priority).unwrap(); - assert_eq!(getsockopt(fd, sockopt::Priority).unwrap(), priority); + setsockopt(&fd, sockopt::Priority, &priority).unwrap(); + assert_eq!(getsockopt(&fd, sockopt::Priority).unwrap(), priority); } #[test] @@ -424,8 +425,8 @@ fn test_ip_tos() { ) .unwrap(); let tos = 0x80; // CS4 - setsockopt(fd, sockopt::IpTos, &tos).unwrap(); - assert_eq!(getsockopt(fd, sockopt::IpTos).unwrap(), tos); + setsockopt(&fd, sockopt::IpTos, &tos).unwrap(); + assert_eq!(getsockopt(&fd, sockopt::IpTos).unwrap(), tos); } #[test] @@ -442,6 +443,6 @@ fn test_ipv6_tclass() { ) .unwrap(); let class = 0x80; // CS4 - setsockopt(fd, sockopt::Ipv6TClass, &class).unwrap(); - assert_eq!(getsockopt(fd, sockopt::Ipv6TClass).unwrap(), class); + setsockopt(&fd, sockopt::Ipv6TClass, &class).unwrap(); + assert_eq!(getsockopt(&fd, sockopt::Ipv6TClass).unwrap(), class); } From 2589f437f288ff756cc66f987a62c01a0bf1110e Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Mon, 29 May 2023 21:46:47 +0800 Subject: [PATCH 333/358] Add support for LoongArch --- src/sys/ioctl/linux.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sys/ioctl/linux.rs b/src/sys/ioctl/linux.rs index 0c0a209053..669d517906 100644 --- a/src/sys/ioctl/linux.rs +++ b/src/sys/ioctl/linux.rs @@ -42,7 +42,8 @@ mod consts { target_arch = "x86_64", target_arch = "aarch64", target_arch = "riscv32", - target_arch = "riscv64" + target_arch = "riscv64", + target_arch = "loongarch64" ))] mod consts { #[doc(hidden)] From b6425d6b0e2d52075d50907d2519f18e5530945d Mon Sep 17 00:00:00 2001 From: smalis-msft <137308034+smalis-msft@users.noreply.github.com> Date: Tue, 8 Aug 2023 18:48:43 -0400 Subject: [PATCH 334/358] Do not enable any features by default --- Cargo.toml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c788b5eb0d..8cfd38fbc3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,13 +34,7 @@ pin-utils = { version = "0.1.0", optional = true } memoffset = { version = "0.9", optional = true } [features] -default = [ - "acct", "aio", "dir", "env", "event", "feature", "fs", - "hostname", "inotify", "ioctl", "kmod", "mman", "mount", "mqueue", - "net", "personality", "poll", "process", "pthread", "ptrace", "quota", - "reboot", "resource", "sched", "signal", "socket", "term", "time", - "ucontext", "uio", "user", "zerocopy", -] +default = [] acct = [] aio = ["pin-utils"] From 08f393e6c239b2e55f25fddd914662e2b741246c Mon Sep 17 00:00:00 2001 From: Steven Malis Date: Wed, 9 Aug 2023 10:44:44 -0400 Subject: [PATCH 335/358] Attempt to add --all-features to CI. --- .cirrus.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 6d5402df69..5aba3473c4 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -18,9 +18,9 @@ build: &BUILD - . $HOME/.cargo/env || true - $TOOL -Vv - rustc -Vv - - $TOOL $BUILD $ZFLAGS --target $TARGET --all-targets - - $TOOL doc $ZFLAGS --no-deps --target $TARGET - - $TOOL clippy $ZFLAGS --target $TARGET --all-targets -- $CLIPPYFLAGS + - $TOOL $BUILD $ZFLAGS --target $TARGET --all-targets --all-features + - $TOOL doc $ZFLAGS --no-deps --target $TARGET --all-features + - $TOOL clippy $ZFLAGS --target $TARGET --all-targets --all-features -- $CLIPPYFLAGS - if [ -z "$NOHACK" ]; then mkdir -p $HOME/.cargo/bin; export PATH=$HOME/.cargo/bin:$PATH; fi - if [ -z "$NOHACK" ]; then curl -LsSf https://github.com/taiki-e/cargo-hack/releases/latest/download/cargo-hack-${HOST:-$TARGET}.tar.gz | tar xzf - -C ~/.cargo/bin; fi - if [ -z "$NOHACK" ]; then $TOOL hack $ZFLAGS check --target $TARGET --each-feature; fi @@ -30,7 +30,7 @@ test: &TEST << : *BUILD test_script: - . $HOME/.cargo/env || true - - $TOOL test --target $TARGET + - $TOOL test --target $TARGET --all-features # 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 @@ -59,9 +59,9 @@ task: << : *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 + - cargo build --target i686-unknown-freebsd --all-features + - cargo doc --no-deps --target i686-unknown-freebsd --all-features + - cargo test --target i686-unknown-freebsd --all-features i386_feature_script: - . $HOME/.cargo/env - if [ -z "$NOHACK" ]; then cargo hack check --each-feature --target i686-unknown-freebsd; fi From ca49cd83b44ed30fb4aa1b68a628cdf3ccc702c8 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 11 Aug 2023 10:48:46 -0400 Subject: [PATCH 336/358] Add #[inline] to memfd_create to prevent linker errors with dylibs and --no-allow-shlib-undefined --- src/sys/memfd.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sys/memfd.rs b/src/sys/memfd.rs index f349a743ed..516ffd3262 100644 --- a/src/sys/memfd.rs +++ b/src/sys/memfd.rs @@ -40,6 +40,7 @@ libc_bitflags!( /// For more information, see [`memfd_create(2)`]. /// /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html +#[inline] // Delays codegen, preventing linker errors with dylibs and --no-allow-shlib-undefined pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result { let res = unsafe { cfg_if! { From 5d55d8f12f11b8db07210d4ccafc7de6136457fa Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Wed, 30 Nov 2022 15:11:05 -0700 Subject: [PATCH 337/358] Use AsFd in copy_file_range And expose it on FreeBSD --- CHANGELOG.md | 11 ++++++ src/fcntl.rs | 81 +++++++++++++++++++++++++++++--------------- test/test_fcntl.rs | 83 +++++++++++++++++++++++++--------------------- 3 files changed, 112 insertions(+), 63 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 308f929025..44f9ccc1d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added `SO_RTABLE` for OpenBSD and `SO_ACCEPTFILTER` for FreeBSD/NetBSD to `nix::sys::socket::sockopt`. ([#2085](https://github.com/nix-rust/nix/pull/2085)) - Removed `flock` from `::nix::fcntl` on Solaris. ([#2082](https://github.com/nix-rust/nix/pull/2082)) +- Use I/O safety with `copy_file_range`, and expose it on FreeBSD. + (#[1906](https://github.com/nix-rust/nix/pull/1906)) ### Changed @@ -44,6 +46,15 @@ This project adheres to [Semantic Versioning](https://semver.org/). - `nix::socket` and `nix::select` are now available on Redox. ([#2012](https://github.com/nix-rust/nix/pull/2012)) +- Implemented I/O safety. Many public functions argument and return types have + changed: + | Original Type | New Type | + | ------------- | --------------------- | + | AsRawFd | AsFd | + | RawFd | BorrowedFd or OwnedFd | + + (#[1906](https://github.com/nix-rust/nix/pull/1906)) + ### Fixed - Fix: send `ETH_P_ALL` in htons format ([#1925](https://github.com/nix-rust/nix/pull/1925)) diff --git a/src/fcntl.rs b/src/fcntl.rs index 85c8e1a49e..9bfecda5ac 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -5,11 +5,19 @@ use std::ffi::OsString; use std::os::raw; use std::os::unix::ffi::OsStringExt; use std::os::unix::io::RawFd; +// For splice and copy_file_range +#[cfg(any( + target_os = "android", + target_os = "freebsd", + target_os = "linux" +))] +use std::{ + os::unix::io::{AsFd, AsRawFd}, + ptr, +}; #[cfg(feature = "fs")] use crate::{sys::stat::Mode, NixPath, Result}; -#[cfg(any(target_os = "android", target_os = "linux"))] -use std::ptr; // For splice and copy_file_range #[cfg(any( target_os = "linux", @@ -612,44 +620,65 @@ feature! { /// /// The `copy_file_range` system call performs an in-kernel copy between /// file descriptors `fd_in` and `fd_out` without the additional cost of -/// transferring data from the kernel to user space and then back into the -/// kernel. It copies up to `len` bytes of data from file descriptor `fd_in` to -/// file descriptor `fd_out`, overwriting any data that exists within the -/// requested range of the target file. +/// transferring data from the kernel to user space and back again. There may be +/// additional optimizations for specific file systems. It copies up to `len` +/// bytes of data from file descriptor `fd_in` to file descriptor `fd_out`, +/// overwriting any data that exists within the requested range of the target +/// file. /// /// If the `off_in` and/or `off_out` arguments are used, the values /// will be mutated to reflect the new position within the file after -/// copying. If they are not used, the relevant filedescriptors will be seeked +/// copying. If they are not used, the relevant file descriptors will be seeked /// to the new position. /// /// On successful completion the number of bytes actually copied will be /// returned. -#[cfg(any(target_os = "android", target_os = "linux"))] -pub fn copy_file_range( - fd_in: RawFd, - off_in: Option<&mut libc::loff_t>, - fd_out: RawFd, - off_out: Option<&mut libc::loff_t>, +// Note: FreeBSD defines the offset argument as "off_t". Linux and Android +// define it as "loff_t". But on both OSes, on all supported platforms, those +// are 64 bits. So Nix uses i64 to make the docs simple and consistent. +#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] +pub fn copy_file_range( + fd_in: Fd1, + off_in: Option<&mut i64>, + fd_out: Fd2, + off_out: Option<&mut i64>, len: usize, ) -> Result { let off_in = off_in - .map(|offset| offset as *mut libc::loff_t) + .map(|offset| offset as *mut i64) .unwrap_or(ptr::null_mut()); let off_out = off_out - .map(|offset| offset as *mut libc::loff_t) + .map(|offset| offset as *mut i64) .unwrap_or(ptr::null_mut()); - let ret = unsafe { - libc::syscall( - libc::SYS_copy_file_range, - fd_in, - off_in, - fd_out, - off_out, - len, - 0, - ) - }; + cfg_if::cfg_if! { + if #[cfg(target_os = "freebsd")] { + let ret = unsafe { + libc::copy_file_range( + fd_in.as_fd().as_raw_fd(), + off_in, + fd_out.as_fd().as_raw_fd(), + off_out, + len, + 0, + ) + }; + } else { + // May Linux distros still don't include copy_file_range in their + // libc implementations, so we need to make a direct syscall. + let ret = unsafe { + libc::syscall( + libc::SYS_copy_file_range, + fd_in, + off_in, + fd_out.as_fd().as_raw_fd(), + off_out, + len, + 0, + ) + }; + } + } Errno::result(ret).map(|r| r as usize) } diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 31df6d038f..5fef04ba9b 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -26,7 +26,7 @@ use std::io::prelude::*; #[cfg(not(target_os = "redox"))] use std::os::unix::fs; #[cfg(not(target_os = "redox"))] -use tempfile::{self, NamedTempFile}; +use tempfile::NamedTempFile; #[test] #[cfg(not(target_os = "redox"))] @@ -227,6 +227,51 @@ fn test_readlink() { ); } +/// This test creates a temporary file containing the contents +/// 'foobarbaz' and uses the `copy_file_range` call to transfer +/// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The +/// resulting file is read and should contain the contents `bar`. +/// The from_offset should be updated by the call to reflect +/// the 3 bytes read (6). +#[cfg(any( + target_os = "linux", + // Not available until FreeBSD 13.0 + all(target_os = "freebsd", fbsd14), + target_os = "android" +))] +#[test] +// QEMU does not support copy_file_range. Skip under qemu +#[cfg_attr(qemu, ignore)] +fn test_copy_file_range() { + use nix::fcntl::copy_file_range; + use std::os::unix::io::AsFd; + + const CONTENTS: &[u8] = b"foobarbaz"; + + let mut tmp1 = tempfile::tempfile().unwrap(); + let mut tmp2 = tempfile::tempfile().unwrap(); + + tmp1.write_all(CONTENTS).unwrap(); + tmp1.flush().unwrap(); + + let mut from_offset: i64 = 3; + copy_file_range( + tmp1.as_fd(), + Some(&mut from_offset), + tmp2.as_fd(), + None, + 3, + ) + .unwrap(); + + let mut res: String = String::new(); + tmp2.rewind().unwrap(); + tmp2.read_to_string(&mut res).unwrap(); + + assert_eq!(res, String::from("bar")); + assert_eq!(from_offset, 6); +} + #[cfg(any(target_os = "linux", target_os = "android"))] mod linux_android { use libc::loff_t; @@ -243,42 +288,6 @@ mod linux_android { use crate::*; - /// This test creates a temporary file containing the contents - /// 'foobarbaz' and uses the `copy_file_range` call to transfer - /// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The - /// resulting file is read and should contain the contents `bar`. - /// The from_offset should be updated by the call to reflect - /// the 3 bytes read (6). - #[test] - // QEMU does not support copy_file_range. Skip under qemu - #[cfg_attr(qemu, ignore)] - fn test_copy_file_range() { - const CONTENTS: &[u8] = b"foobarbaz"; - - let mut tmp1 = tempfile().unwrap(); - let mut tmp2 = tempfile().unwrap(); - - tmp1.write_all(CONTENTS).unwrap(); - tmp1.flush().unwrap(); - - let mut from_offset: i64 = 3; - copy_file_range( - tmp1.as_raw_fd(), - Some(&mut from_offset), - tmp2.as_raw_fd(), - None, - 3, - ) - .unwrap(); - - let mut res: String = String::new(); - tmp2.rewind().unwrap(); - tmp2.read_to_string(&mut res).unwrap(); - - assert_eq!(res, String::from("bar")); - assert_eq!(from_offset, 6); - } - #[test] fn test_splice() { const CONTENTS: &[u8] = b"abcdef123456"; From 18cbec28a8f569b735a3337bd8ec4512e86c2ff6 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 11 Aug 2023 09:24:01 -0600 Subject: [PATCH 338/358] Clippy cleanup: noop_method_call --- test/sys/test_aio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index fdabaca6aa..c0267aac98 100644 --- a/test/sys/test_aio.rs +++ b/test/sys/test_aio.rs @@ -200,7 +200,7 @@ mod aio_read { assert_eq!(err, Ok(())); assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len()); } - assert_eq!(EXPECT, rbuf.deref().deref()); + assert_eq!(EXPECT, rbuf.deref()); } // Like ok, but allocates the structure on the stack. @@ -223,7 +223,7 @@ mod aio_read { assert_eq!(err, Ok(())); assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len()); } - assert_eq!(EXPECT, rbuf.deref().deref()); + assert_eq!(EXPECT, rbuf.deref()); } } From 5a17e30a5f319c0861feea6b5297634e7754ef6b Mon Sep 17 00:00:00 2001 From: Steven Malis Date: Fri, 11 Aug 2023 11:30:50 -0400 Subject: [PATCH 339/358] Rework unused_imports allow. --- src/lib.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 8649a34d44..af0c67b0f3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,7 +47,43 @@ #![recursion_limit = "500"] #![deny(unused)] #![allow(unused_macros)] -#![cfg_attr(not(feature = "default"), allow(unused_imports))] +#![cfg_attr( + not(all( + feature = "acct", + feature = "aio", + feature = "dir", + feature = "env", + feature = "event", + feature = "feature", + feature = "fs", + feature = "hostname", + feature = "inotify", + feature = "ioctl", + feature = "kmod", + feature = "mman", + feature = "mount", + feature = "mqueue", + feature = "net", + feature = "personality", + feature = "poll", + feature = "process", + feature = "pthread", + feature = "ptrace", + feature = "quota", + feature = "reboot", + feature = "resource", + feature = "sched", + feature = "socket", + feature = "signal", + feature = "term", + feature = "time", + feature = "ucontext", + feature = "uio", + feature = "user", + feature = "zerocopy", + )), + allow(unused_imports) +)] #![deny(unstable_features)] #![deny(missing_copy_implementations)] #![deny(missing_debug_implementations)] From fa71f33eee1e9a69c7383f6390b255f7256b5a85 Mon Sep 17 00:00:00 2001 From: Steven Malis Date: Fri, 11 Aug 2023 11:34:52 -0400 Subject: [PATCH 340/358] Add changelog entry. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 308f929025..283aa183f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#1943](https://github.com/nix-rust/nix/pull/1943)) - `nix::socket` and `nix::select` are now available on Redox. ([#2012](https://github.com/nix-rust/nix/pull/2012)) +- All features have been removed from the default set. Users will need to specify + which features they depend on in their Cargo.toml. + ([#2091](https://github.com/nix-rust/nix/pull/2091)) ### Fixed - Fix: send `ETH_P_ALL` in htons format From c98b13e529ad44646f24a85a2d58fe6a79328489 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 11 Aug 2023 10:05:54 -0600 Subject: [PATCH 341/358] Fix an incorrect lifetime in the return value of recvmsg Fixes #2083 --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 2 +- test/sys/test_socket.rs | 11 ++++------- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 308f929025..7f0e1e01aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). `SockaddrIn6::from`, `IpMembershipRequest::new`, and `Ipv6MembershipRequest::new` with future Rust versions. ([#2061](https://github.com/nix-rust/nix/pull/2061)) +- Fixed an incorrect lifetime returned from `recvmsg`. + ([#2095](https://github.com/nix-rust/nix/pull/2095)) ### Removed diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 2e2897dbb2..4f25b6b69c 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -2058,7 +2058,7 @@ fn pack_mhdr_to_send<'a, I, C, S>( /// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>], mut cmsg_buffer: Option<&'a mut Vec>, - flags: MsgFlags) -> Result> + flags: MsgFlags) -> Result> where S: SockaddrLike + 'a, 'inner: 'outer { diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index f93a7339c3..ed1686e87d 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -239,13 +239,10 @@ pub fn test_recvmsg_sockaddr_un() { // Receive the message let mut recv_buffer = [0u8; 32]; - let received = socket::recvmsg( - sock.as_raw_fd(), - &mut [std::io::IoSliceMut::new(&mut recv_buffer)], - None, - MsgFlags::empty(), - ) - .unwrap(); + let mut iov = [std::io::IoSliceMut::new(&mut recv_buffer)]; + let received = + socket::recvmsg(sock.as_raw_fd(), &mut iov, None, MsgFlags::empty()) + .unwrap(); // Check the address in the received message assert_eq!(sockaddr, received.address.unwrap()); } From c93fe5154eac706f82ec8aac308206b5280b1e75 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 19 Aug 2023 20:20:11 +0000 Subject: [PATCH 342/358] Implemented all `std::os::fd` traits for `mqueue::MqdT`. (#2097) * Implemented all `std::os::fd` traits for `mqueue::MqdT`. * Updated CHANGELOG entry with pull request URL for #2097. * Bumped the minimum rustc version to match that of the `std::os::fd` module. * MSRV bumped to 1.66, including cirrus configs. * Refactored use statement to reduce MSRV back to 1.63. * Converted indents to spaces. * Updated last changes for rust formatter CI. * Actual last format change this time. * Added NetBSD and DragonflyBSD build support. * Removed redundant cfg condition. --- CHANGELOG.md | 2 ++ src/mqueue.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c51d4fb2ea..85bd94b2a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). | RawFd | BorrowedFd or OwnedFd | (#[1906](https://github.com/nix-rust/nix/pull/1906)) +- Implemented AsFd, AsRawFd, FromRawFd, and IntoRawFd for `mqueue::MqdT`. + See ([#2097](https://github.com/nix-rust/nix/pull/2097)) ### Fixed - Fix: send `ETH_P_ALL` in htons format diff --git a/src/mqueue.rs b/src/mqueue.rs index 7ce7d5e8bc..e33797c81f 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -37,6 +37,14 @@ use crate::sys::stat::Mode; use libc::{self, c_char, mqd_t, size_t}; use std::ffi::CStr; use std::mem; +#[cfg(any( + target_os = "linux", + target_os = "netbsd", + target_os = "dragonfly" +))] +use std::os::unix::io::{ + AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd, +}; libc_bitflags! { /// Used with [`mq_open`]. @@ -300,3 +308,43 @@ pub fn mq_remove_nonblock(mqd: &MqdT) -> Result { ); mq_setattr(mqd, &newattr) } + +#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "dragonfly"))] +impl AsFd for MqdT { + /// Borrow the underlying message queue descriptor. + fn as_fd(&self) -> BorrowedFd { + // SAFETY: [MqdT] will only contain a valid fd by construction. + unsafe { BorrowedFd::borrow_raw(self.0) } + } +} + +#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "dragonfly"))] +impl AsRawFd for MqdT { + /// Return the underlying message queue descriptor. + /// + /// Returned descriptor is a "shallow copy" of the descriptor, so it refers + /// to the same underlying kernel object as `self`. + fn as_raw_fd(&self) -> RawFd { + self.0 + } +} + +#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "dragonfly"))] +impl FromRawFd for MqdT { + /// Construct an [MqdT] from [RawFd]. + /// + /// # Safety + /// The `fd` given must be a valid and open file descriptor for a message + /// queue. + unsafe fn from_raw_fd(fd: RawFd) -> MqdT { + MqdT(fd) + } +} + +#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "dragonfly"))] +impl IntoRawFd for MqdT { + /// Consume this [MqdT] and return a [RawFd]. + fn into_raw_fd(self) -> RawFd { + self.0 + } +} From fb242cb84969bdc4ac06d4ebc3036c5004dbda16 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 20 Aug 2023 09:58:12 -0600 Subject: [PATCH 343/358] Economize our Cirrus CI builds Cirrus CI is eliminating unlimited free open source builds. Open source projects will now be limited to about 16,000 CPU-minutes per month. Tweak our CI configuration to reduce its demands: * Eliminate the FreeBSD 12 x86_64, iOS x86_64, macOS x86_64, and Linux powerpc builds. They weren't providing a useful amount of test coverage. * Reduce each task to 1 CPU (except for OSX, where we can't). Our build rarely uses more than a single CPU anyway. * Split the tasks up into two groups. The first group of 8 builds contains broad coverage. Most build failures will be caught by one of these tasks. The second group of 29 tasks will only run after the first group completes. https://cirrus-ci.org/blog/2023/07/17/limiting-free-usage-of-cirrus-ci/ --- .cirrus.yml | 90 +++++++++++++++++++++++++++++++++++++++++++---------- README.md | 14 +++++---- 2 files changed, 82 insertions(+), 22 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 5aba3473c4..dbd0b15aca 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -40,12 +40,10 @@ task: env: TARGET: x86_64-unknown-freebsd matrix: - - name: FreeBSD 12 amd64 & i686 - freebsd_instance: - image: freebsd-12-4-release-amd64 - name: FreeBSD 14 amd64 & i686 freebsd_instance: image_family: freebsd-14-0-snap + cpu: 1 # Enable tests that would fail on FreeBSD 12 RUSTFLAGS: --cfg fbsd14 -D warnings RUSTDOCFLAGS: --cfg fbsd14 @@ -85,6 +83,14 @@ task: # Use cross for QEMU-based testing # cross needs to execute Docker, so we must use Cirrus's Docker Builder task. task: + depends_on: + - FreeBSD 14 amd64 & i686 + - Linux x86_64 + - macOS aarch64 + - Rust Formatter + - OpenBSD x86_64 + - Minver + - Rust Stable env: RUST_TEST_THREADS: 1 # QEMU works best with 1 thread HOME: /tmp/home @@ -141,16 +147,35 @@ task: - name: Linux aarch64 arm_container: image: rust:1.63.0 + cpu: 1 + depends_on: + - FreeBSD 14 amd64 & i686 + - Linux x86_64 + - macOS aarch64 + - Rust Formatter + - OpenBSD x86_64 + - Minver + - Rust Stable env: TARGET: aarch64-unknown-linux-gnu - name: Linux x86_64 container: image: rust:1.63.0 + cpu: 1 env: TARGET: x86_64-unknown-linux-gnu - name: Linux x86_64 musl container: image: rust:1.63.0 + cpu: 1 + depends_on: + - FreeBSD 14 amd64 & i686 + - Linux x86_64 + - macOS aarch64 + - Rust Formatter + - OpenBSD x86_64 + - Minver + - Rust Stable env: TARGET: x86_64-unknown-linux-musl setup_script: @@ -163,6 +188,7 @@ task: name: Rust Stable container: image: rust:latest + cpu: 1 env: TARGET: x86_64-unknown-linux-gnu setup_script: @@ -174,6 +200,15 @@ task: task: container: image: rust:1.63.0 + cpu: 1 + depends_on: + - FreeBSD 14 amd64 & i686 + - Linux x86_64 + - macOS aarch64 + - Rust Formatter + - OpenBSD x86_64 + - Minver + - Rust Stable env: BUILD: check HOST: x86_64-unknown-linux-gnu @@ -211,16 +246,6 @@ task: # cargo hack tries to invoke the iphonesimulator SDK for iOS NOHACK: 1 TARGET: aarch64-apple-ios - - name: iOS x86_64 - env: - # cargo hack tries to invoke the iphonesimulator SDK for iOS - NOHACK: 1 - TARGET: x86_64-apple-ios - # Cross testing on powerpc fails with "undefined reference to renameat2". - # Perhaps cross is using too-old a version? - - name: Linux powerpc - env: - TARGET: powerpc-unknown-linux-gnu # Cross claims to support Linux powerpc64, but it really doesn't. # https://github.com/rust-embedded/cross/issues/441 - name: Linux powerpc64 @@ -232,9 +257,6 @@ task: - name: Linux x32 env: TARGET: x86_64-unknown-linux-gnux32 - - name: macOS x86_64 - env: - TARGET: x86_64-apple-darwin - name: NetBSD x86_64 env: TARGET: x86_64-unknown-netbsd @@ -248,6 +270,15 @@ task: container: # Redox's MSRV policy is unclear. Until they define it, use nightly. image: rustlang/rust:nightly + cpu: 1 + depends_on: + - FreeBSD 14 amd64 & i686 + - Linux x86_64 + - macOS aarch64 + - Rust Formatter + - OpenBSD x86_64 + - Minver + - Rust Stable env: BUILD: check name: Redox x86_64 @@ -265,6 +296,7 @@ task: task: container: image: rustlang/rust:nightly + cpu: 1 env: BUILD: check HOST: x86_64-unknown-linux-gnu @@ -272,15 +304,39 @@ task: CLIPPYFLAGS: -D warnings matrix: - name: DragonFly BSD x86_64 + depends_on: + - FreeBSD 14 amd64 & i686 + - Linux x86_64 + - macOS aarch64 + - Rust Formatter + - OpenBSD x86_64 + - Minver + - Rust Stable env: TARGET: x86_64-unknown-dragonfly - name: OpenBSD x86_64 env: TARGET: x86_64-unknown-openbsd - name: Linux armv7 uclibceabihf + depends_on: + - FreeBSD 14 amd64 & i686 + - Linux x86_64 + - macOS aarch64 + - Rust Formatter + - OpenBSD x86_64 + - Minver + - Rust Stable env: TARGET: armv7-unknown-linux-uclibceabihf - name: Haiku x86_64 + depends_on: + - FreeBSD 14 amd64 & i686 + - Linux x86_64 + - macOS aarch64 + - Rust Formatter + - OpenBSD x86_64 + - Minver + - Rust Stable env: TARGET: x86_64-unknown-haiku setup_script: @@ -297,6 +353,7 @@ task: HOST: x86_64-unknown-linux-gnu container: image: rustlang/rust:nightly + cpu: 1 setup_script: - cargo update -Zminimal-versions check_script: @@ -308,5 +365,6 @@ task: name: Rust Formatter container: image: rust:latest + cpu: 1 setup_script: rustup component add rustfmt test_script: cargo fmt --all -- --check **/*.rs diff --git a/README.md b/README.md index 72f7486d2e..3c528b6665 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ pub fn gethostname() -> Result; ## Supported Platforms -nix target support consists of two tiers. While nix attempts to support all +nix target support consists of three tiers. While nix attempts to support all platforms supported by [libc](https://github.com/rust-lang/libc), only some platforms are actively supported due to either technical or manpower limitations. Support for platforms is split into three tiers: @@ -41,8 +41,12 @@ limitations. Support for platforms is split into three tiers: blocks the inclusion of new code. Tests may be run, but failures in tests don't block the inclusion of new code. * Tier 3 - Builds for this target are run in CI. Failures during the build - *do not* block the inclusion of new code. Testing may be run, but - failures in tests don't block the inclusion of new code. + *do not* necessarily block the inclusion of new code. That is, at + our discretion a Tier 3 target may be dropped at any time, if it + would otherwise block development. + +Platforms not listed are supported on a best-effort basis, relying on our users +to report any problems. The following targets are supported by `nix`: @@ -80,16 +84,14 @@ The following targets are supported by `nix`:
  • arm-unknown-linux-musleabi
  • armv7-linux-androideabi
  • i686-linux-android
  • -
  • powerpc-unknown-linux-gnu
  • s390x-unknown-linux-gnu
  • -
  • x86_64-apple-ios
  • x86_64-linux-android
  • -
  • x86_64-apple-darwin
  • x86_64-unknown-illumos
  • x86_64-unknown-netbsd
  • armv7-unknown-linux-uclibceabihf
  • +
  • powerpc64-unknown-linux-gnu
  • x86_64-fuchsia
  • x86_64-unknown-dragonfly
  • x86_64-unknown-haiku
  • From 0e0e181d96db5b89e78c202b4ae9fdffdec7f31a Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 26 Aug 2023 12:30:07 -0600 Subject: [PATCH 344/358] Tweak the #[cfg()] statements in sys/ioctl/linux a little (#2104) * Tweak the #[cfg()] statements in sys/ioctl/linux a little This should give Nix a better chance of building on architectures that aren't specifically-supported. * Raise MSRV to 1.65.0 Because cross now requires that through a transitive dependency. I don't know how to install cross for CI with a lower Rust version. --- .cirrus.yml | 12 +++---- CHANGELOG.md | 3 +- Cargo.toml | 2 +- README.md | 2 +- src/sys/ioctl/linux.rs | 79 ++++++++++++++++++++---------------------- 5 files changed, 47 insertions(+), 51 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index dbd0b15aca..522bdafcdb 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -9,7 +9,7 @@ env: RUSTFLAGS: -D warnings RUSTDOCFLAGS: -D warnings TOOL: cargo - MSRV: 1.63.0 + MSRV: 1.65.0 ZFLAGS: # Tests that don't require executing the build binaries @@ -137,7 +137,7 @@ task: - curl --proto '=https' --tlsv1.2 -sSf -o rustup.sh https://sh.rustup.rs - sh rustup.sh -y --profile=minimal --default-toolchain $MSRV - . $HOME/.cargo/env - - cargo install cross --version 0.2.1 # cross 0.2.2 bumped the MSRV to 1.58.1 + - cargo install cross --version 0.2.5 << : *TEST before_cache_script: rm -rf $CARGO_HOME/registry/index @@ -146,7 +146,7 @@ task: matrix: - name: Linux aarch64 arm_container: - image: rust:1.63.0 + image: rust:1.65.0 cpu: 1 depends_on: - FreeBSD 14 amd64 & i686 @@ -160,13 +160,13 @@ task: TARGET: aarch64-unknown-linux-gnu - name: Linux x86_64 container: - image: rust:1.63.0 + image: rust:1.65.0 cpu: 1 env: TARGET: x86_64-unknown-linux-gnu - name: Linux x86_64 musl container: - image: rust:1.63.0 + image: rust:1.65.0 cpu: 1 depends_on: - FreeBSD 14 amd64 & i686 @@ -199,7 +199,7 @@ task: # Tasks for cross-compiling, but no testing task: container: - image: rust:1.63.0 + image: rust:1.65.0 cpu: 1 depends_on: - FreeBSD 14 amd64 & i686 diff --git a/CHANGELOG.md b/CHANGELOG.md index 85bd94b2a3..7de03da0bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,8 +32,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Changed -- The MSRV is now 1.63 +- The MSRV is now 1.65 ([#1862](https://github.com/nix-rust/nix/pull/1862)) + ([#2104](https://github.com/nix-rust/nix/pull/2104)) - The epoll interface now uses a type. ([#1882](https://github.com/nix-rust/nix/pull/1882)) - With I/O-safe type applied in `pty::OpenptyResult` and `pty::ForkptyResult`, diff --git a/Cargo.toml b/Cargo.toml index 8cfd38fbc3..010c9f895b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2021" version = "0.26.1" -rust-version = "1.63" +rust-version = "1.65" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" license = "MIT" diff --git a/README.md b/README.md index 3c528b6665..e172de2750 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ The following targets are supported by `nix`: ## Minimum Supported Rust Version (MSRV) -nix is supported on Rust 1.63 and higher. Its MSRV will not be +nix is supported on Rust 1.65 and higher. Its MSRV will not be changed in the future without bumping the major or minor version. ## Contributing diff --git a/src/sys/ioctl/linux.rs b/src/sys/ioctl/linux.rs index 669d517906..610b8ddac0 100644 --- a/src/sys/ioctl/linux.rs +++ b/src/sys/ioctl/linux.rs @@ -1,3 +1,5 @@ +use cfg_if::cfg_if; + /// The datatype used for the ioctl number #[cfg(any(target_os = "android", target_env = "musl"))] #[doc(hidden)] @@ -14,48 +16,41 @@ pub const NRBITS: ioctl_num_type = 8; #[doc(hidden)] pub const TYPEBITS: ioctl_num_type = 8; -#[cfg(any( - target_arch = "mips", - target_arch = "mips64", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "sparc64" -))] -mod consts { - #[doc(hidden)] - pub const NONE: u8 = 1; - #[doc(hidden)] - pub const READ: u8 = 2; - #[doc(hidden)] - pub const WRITE: u8 = 4; - #[doc(hidden)] - pub const SIZEBITS: u8 = 13; - #[doc(hidden)] - pub const DIRBITS: u8 = 3; -} - -// "Generic" ioctl protocol -#[cfg(any( - target_arch = "x86", - target_arch = "arm", - target_arch = "s390x", - target_arch = "x86_64", - target_arch = "aarch64", - target_arch = "riscv32", - target_arch = "riscv64", - target_arch = "loongarch64" -))] -mod consts { - #[doc(hidden)] - pub const NONE: u8 = 0; - #[doc(hidden)] - pub const READ: u8 = 2; - #[doc(hidden)] - pub const WRITE: u8 = 1; - #[doc(hidden)] - pub const SIZEBITS: u8 = 14; - #[doc(hidden)] - pub const DIRBITS: u8 = 2; +cfg_if! { + if #[cfg(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "sparc64" + ))] { + mod consts { + #[doc(hidden)] + pub const NONE: u8 = 1; + #[doc(hidden)] + pub const READ: u8 = 2; + #[doc(hidden)] + pub const WRITE: u8 = 4; + #[doc(hidden)] + pub const SIZEBITS: u8 = 13; + #[doc(hidden)] + pub const DIRBITS: u8 = 3; + } + } else { + // "Generic" ioctl protocol + mod consts { + #[doc(hidden)] + pub const NONE: u8 = 0; + #[doc(hidden)] + pub const READ: u8 = 2; + #[doc(hidden)] + pub const WRITE: u8 = 1; + #[doc(hidden)] + pub const SIZEBITS: u8 = 14; + #[doc(hidden)] + pub const DIRBITS: u8 = 2; + } + } } pub use self::consts::*; From 733ddf1287df0ed2fd4b281686f63c4793e5fb9a Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Sat, 26 Aug 2023 14:30:21 -0400 Subject: [PATCH 345/358] Added `MSG_WAITFORONE` flag to `MsgFlags` (#2014) --- CHANGELOG.md | 3 +++ src/sys/socket/mod.rs | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7de03da0bf..7d7a88d94c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Removed `flock` from `::nix::fcntl` on Solaris. ([#2082](https://github.com/nix-rust/nix/pull/2082)) - Use I/O safety with `copy_file_range`, and expose it on FreeBSD. (#[1906](https://github.com/nix-rust/nix/pull/1906)) +- Added `MSG_WAITFORONE` to `MsgFlags` on Android, Fuchsia, Linux, NetBSD, + FreeBSD, OpenBSD, and Solaris. + ([#2014](https://github.com/nix-rust/nix/pull/2014)) ### Changed diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 4f25b6b69c..e13485ac1b 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -374,6 +374,17 @@ libc_bitflags! { target_os = "solaris"))] #[cfg_attr(docsrs, doc(cfg(all())))] MSG_NOSIGNAL; + /// Turns on [`MSG_DONTWAIT`] after the first message has been received (only for + /// `recvmmsg()`). + #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "linux", + target_os = "netbsd", + target_os = "freebsd", + target_os = "openbsd", + target_os = "solaris"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + MSG_WAITFORONE; } } From a0613ba0e6900242b24af4f8fdb320e61fba8a3d Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 26 Aug 2023 18:30:36 +0000 Subject: [PATCH 346/358] Changed `name` parameter of `mqueue` functions to be generic over `NixPath`. (#2102) * Changed `name` parameter of `mq_open` and `mq_unlink` to be generic over `NixPath`. * Updated with PR link. * Fixed docs example code. * Fixed docs example code for real this time. --- CHANGELOG.md | 2 ++ src/mqueue.rs | 34 +++++++++++++++++++++------------- test/test_mq.rs | 16 +++++++--------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d7a88d94c..32a603beba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1906](https://github.com/nix-rust/nix/pull/1906)) - Implemented AsFd, AsRawFd, FromRawFd, and IntoRawFd for `mqueue::MqdT`. See ([#2097](https://github.com/nix-rust/nix/pull/2097)) +- Refactored `name` parameter of `mq_open` and `mq_unlink` to be generic over + `NixPath`. See ([#2102](https://github.com/nix-rust/nix/pull/2102)). ### Fixed - Fix: send `ETH_P_ALL` in htons format diff --git a/src/mqueue.rs b/src/mqueue.rs index e33797c81f..fb07d2accb 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -9,16 +9,16 @@ //! use nix::sys::stat::Mode; //! //! const MSG_SIZE: mq_attr_member_t = 32; -//! let mq_name= CString::new("/a_nix_test_queue").unwrap(); +//! let mq_name= "/a_nix_test_queue"; //! //! let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; //! let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; -//! let mqd0 = mq_open(&mq_name, oflag0, mode, None).unwrap(); +//! let mqd0 = mq_open(mq_name, oflag0, mode, None).unwrap(); //! let msg_to_send = b"msg_1"; //! mq_send(&mqd0, msg_to_send, 1).unwrap(); //! //! let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY; -//! let mqd1 = mq_open(&mq_name, oflag1, mode, None).unwrap(); +//! let mqd1 = mq_open(mq_name, oflag1, mode, None).unwrap(); //! let mut buf = [0u8; 32]; //! let mut prio = 0u32; //! let len = mq_receive(&mqd1, &mut buf, &mut prio).unwrap(); @@ -31,11 +31,11 @@ //! [Further reading and details on the C API](https://man7.org/linux/man-pages/man7/mq_overview.7.html) use crate::errno::Errno; +use crate::NixPath; use crate::Result; use crate::sys::stat::Mode; use libc::{self, c_char, mqd_t, size_t}; -use std::ffi::CStr; use std::mem; #[cfg(any( target_os = "linux", @@ -149,31 +149,39 @@ impl MqAttr { /// See also [`mq_open(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html) // The mode.bits() cast is only lossless on some OSes #[allow(clippy::cast_lossless)] -pub fn mq_open( - name: &CStr, +pub fn mq_open

    ( + name: &P, oflag: MQ_OFlag, mode: Mode, attr: Option<&MqAttr>, -) -> Result { - let res = match attr { +) -> Result +where + P: ?Sized + NixPath, +{ + let res = name.with_nix_path(|cstr| match attr { Some(mq_attr) => unsafe { libc::mq_open( - name.as_ptr(), + cstr.as_ptr(), oflag.bits(), mode.bits() as libc::c_int, &mq_attr.mq_attr as *const libc::mq_attr, ) }, - None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) }, - }; + None => unsafe { libc::mq_open(cstr.as_ptr(), oflag.bits()) }, + })?; + Errno::result(res).map(MqdT) } /// Remove a message queue /// /// See also [`mq_unlink(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html) -pub fn mq_unlink(name: &CStr) -> Result<()> { - let res = unsafe { libc::mq_unlink(name.as_ptr()) }; +pub fn mq_unlink

    (name: &P) -> Result<()> +where + P: ?Sized + NixPath, +{ + let res = + name.with_nix_path(|cstr| unsafe { libc::mq_unlink(cstr.as_ptr()) })?; Errno::result(res).map(drop) } diff --git a/test/test_mq.rs b/test/test_mq.rs index f232434e12..1fd8929c17 100644 --- a/test/test_mq.rs +++ b/test/test_mq.rs @@ -1,5 +1,4 @@ use cfg_if::cfg_if; -use std::ffi::CString; use std::str; use nix::errno::Errno; @@ -34,7 +33,7 @@ macro_rules! assert_attr_eq { fn test_mq_send_and_receive() { const MSG_SIZE: mq_attr_member_t = 32; let attr = MqAttr::new(0, 10, MSG_SIZE, 0); - let mq_name = &CString::new(b"/a_nix_test_queue".as_ref()).unwrap(); + let mq_name = "/a_nix_test_queue"; let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; @@ -63,7 +62,7 @@ fn test_mq_send_and_receive() { fn test_mq_timedreceive() { const MSG_SIZE: mq_attr_member_t = 32; let attr = MqAttr::new(0, 10, MSG_SIZE, 0); - let mq_name = &CString::new(b"/a_nix_test_queue".as_ref()).unwrap(); + let mq_name = "/a_nix_test_queue"; let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; @@ -95,7 +94,7 @@ fn test_mq_getattr() { use nix::mqueue::mq_getattr; const MSG_SIZE: mq_attr_member_t = 32; let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); - let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); + let mq_name = "/attr_test_get_attr"; let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); @@ -120,7 +119,7 @@ fn test_mq_setattr() { use nix::mqueue::{mq_getattr, mq_setattr}; const MSG_SIZE: mq_attr_member_t = 32; let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); - let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); + let mq_name = "/attr_test_get_attr"; let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); @@ -170,7 +169,7 @@ fn test_mq_set_nonblocking() { use nix::mqueue::{mq_getattr, mq_remove_nonblock, mq_set_nonblock}; const MSG_SIZE: mq_attr_member_t = 32; let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); - let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap(); + let mq_name = "/attr_test_get_attr"; let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; let r = mq_open(mq_name, oflag, mode, Some(&initial_attr)); @@ -194,10 +193,9 @@ fn test_mq_unlink() { use nix::mqueue::mq_unlink; const MSG_SIZE: mq_attr_member_t = 32; let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0); - let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); + let mq_name_opened = "/mq_unlink_test"; #[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))] - let mq_name_not_opened = - &CString::new(b"/mq_unlink_test".as_ref()).unwrap(); + let mq_name_not_opened = "/mq_unlink_test"; let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY; let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH; let r = mq_open(mq_name_opened, oflag, mode, Some(&initial_attr)); From 183be1b776a2baa3dee111ad2e9ce54b851d1b0d Mon Sep 17 00:00:00 2001 From: nat-rix Date: Sat, 26 Aug 2023 21:24:21 +0200 Subject: [PATCH 347/358] Add NFLOG and generic netlink families (#2092) * Add NFLOG and generic netlink families * Add netlink sock protocol changes to CHANGELOG --- CHANGELOG.md | 2 ++ src/sys/socket/mod.rs | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32a603beba..b99255ca82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1662](https://github.com/nix-rust/nix/pull/1662)) - Added `CanRaw` to `SockProtocol` and `CanBcm` as a separate `SocProtocol` constant. ([#1912](https://github.com/nix-rust/nix/pull/1912)) +- Added `Generic` and `NFLOG` to `SockProtocol`. + ([#2092](https://github.com/nix-rust/nix/pull/2092)) - Added `mq_timedreceive` to `::nix::mqueue`. ([#1966])(https://github.com/nix-rust/nix/pull/1966) - Added `LocalPeerPid` to `nix::sys::socket::sockopt` for macOS. ([#1967](https://github.com/nix-rust/nix/pull/1967)) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index e13485ac1b..78dd617c55 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -158,6 +158,11 @@ pub enum SockProtocol { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkSockDiag = libc::NETLINK_SOCK_DIAG, + /// Netfilter/iptables ULOG. + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkNFLOG = libc::NETLINK_NFLOG, /// SELinux event notifications. /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) #[cfg(any(target_os = "android", target_os = "linux"))] @@ -208,6 +213,11 @@ pub enum SockProtocol { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT, + /// Generic netlink family for simplified netlink usage. + /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + NetlinkGeneric = libc::NETLINK_GENERIC, /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow /// configuration of the kernel crypto API. /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) From cc73638cc44dbb1009fd3dacdf6b2fe6ffab28af Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 26 Aug 2023 17:53:44 -0600 Subject: [PATCH 348/358] Allow setting kevent_flags on struct sigevent (#1731) * Allow setting kevent_flags on struct sigevent Also, disallow using SigevNotify::SigevThreadId on musl. I don't think it ever worked. Depends on https://github.com/rust-lang/libc/pull/2813 Blocks https://github.com/tokio-rs/tokio/issues/4728 * Inline libc::sigevent Because the PR to libc is stalled for over one year, with no sign of progress. --- src/sys/signal.rs | 260 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 211 insertions(+), 49 deletions(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 8580f32d01..34f60e2c82 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -1022,7 +1022,7 @@ feature! { #[cfg(target_os = "freebsd")] pub type type_of_thread_id = libc::lwpid_t; /// Identifies a thread for [`SigevNotify::SigevThreadId`] -#[cfg(target_os = "linux")] +#[cfg(any(target_env = "gnu", target_env = "uclibc"))] pub type type_of_thread_id = libc::pid_t; /// Specifies the notification method used by a [`SigEvent`] @@ -1042,8 +1042,7 @@ pub enum SigevNotify { /// 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. + // Note: SIGEV_THREAD is not implemented, but could be if desired. /// Notify by delivering an event to a kqueue. #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] @@ -1053,8 +1052,24 @@ pub enum SigevNotify { /// Will be contained in the kevent's `udata` field. udata: libc::intptr_t }, + /// Notify by delivering an event to a kqueue, with optional event flags set + #[cfg(target_os = "freebsd")] + #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(feature = "event")] + SigevKeventFlags { + /// File descriptor of the kqueue to notify. + kq: RawFd, + /// Will be contained in the kevent's `udata` field. + udata: libc::intptr_t, + /// Flags that will be set on the delivered event. See `kevent(2)`. + flags: crate::sys::event::EventFlag + }, /// Notify by delivering a signal to a thread. - #[cfg(any(target_os = "freebsd", target_os = "linux"))] + #[cfg(any( + target_os = "freebsd", + target_env = "gnu", + target_env = "uclibc", + ))] #[cfg_attr(docsrs, doc(cfg(all())))] SigevThreadId { /// Signal to send @@ -1079,17 +1094,139 @@ mod sigevent { #![any(feature = "aio", feature = "signal")] use std::mem; - use std::ptr; use super::SigevNotify; - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - use super::type_of_thread_id; + + #[cfg(target_os = "freebsd")] + pub(crate) use ffi::sigevent as libc_sigevent; + #[cfg(not(target_os = "freebsd"))] + pub(crate) use libc::sigevent as libc_sigevent; + + // For FreeBSD only, we define the C structure here. Because the structure + // defined in libc isn't correct. The real sigevent contains union fields, + // but libc could not represent those when sigevent was originally added, so + // instead libc simply defined the most useful field. Now that Rust can + // represent unions, there's a PR to libc to fix it. However, it's stuck + // forever due to backwards compatibility concerns. Even though there's a + // workaround, libc refuses to merge it. I think it's just too complicated + // for them to want to think about right now, because that project is + // short-staffed. So we define it here instead, so we won't have to wait on + // libc. + // https://github.com/rust-lang/libc/pull/2813 + #[cfg(target_os = "freebsd")] + mod ffi { + use std::{fmt, hash}; + + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + #[repr(C)] + pub struct __c_anonymous_sigev_thread { + pub _function: *mut libc::c_void, // Actually a function pointer + pub _attribute: *mut libc::pthread_attr_t, + } + #[derive(Clone, Copy)] + // This will never be used on its own, and its parent has a Debug impl, + // so it doesn't need one. + #[allow(missing_debug_implementations)] + #[repr(C)] + pub union __c_anonymous_sigev_un { + pub _threadid: libc::__lwpid_t, + pub _sigev_thread: __c_anonymous_sigev_thread, + pub _kevent_flags: libc::c_ushort, + __spare__: [libc::c_long; 8], + } + + #[derive(Clone, Copy)] + #[repr(C)] + pub struct sigevent { + pub sigev_notify: libc::c_int, + pub sigev_signo: libc::c_int, + pub sigev_value: libc::sigval, + pub _sigev_un: __c_anonymous_sigev_un, + } + + impl fmt::Debug for sigevent { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut ds = f.debug_struct("sigevent"); + ds.field("sigev_notify", &self.sigev_notify) + .field("sigev_signo", &self.sigev_signo) + .field("sigev_value", &self.sigev_value); + // Safe because we check the sigev_notify discriminant + unsafe { + match self.sigev_notify { + libc::SIGEV_KEVENT => { + ds.field("sigev_notify_kevent_flags", &self._sigev_un._kevent_flags); + } + libc::SIGEV_THREAD_ID => { + ds.field("sigev_notify_thread_id", &self._sigev_un._threadid); + } + libc::SIGEV_THREAD => { + ds.field("sigev_notify_function", &self._sigev_un._sigev_thread._function); + ds.field("sigev_notify_attributes", &self._sigev_un._sigev_thread._attribute); + } + _ => () + }; + } + ds.finish() + } + } + + impl PartialEq for sigevent { + fn eq(&self, other: &Self) -> bool { + let mut equals = self.sigev_notify == other.sigev_notify; + equals &= self.sigev_signo == other.sigev_signo; + equals &= self.sigev_value == other.sigev_value; + // Safe because we check the sigev_notify discriminant + unsafe { + match self.sigev_notify { + libc::SIGEV_KEVENT => { + equals &= self._sigev_un._kevent_flags == other._sigev_un._kevent_flags; + } + libc::SIGEV_THREAD_ID => { + equals &= self._sigev_un._threadid == other._sigev_un._threadid; + } + libc::SIGEV_THREAD => { + equals &= self._sigev_un._sigev_thread == other._sigev_un._sigev_thread; + } + _ => /* The union field is don't care */ () + } + } + equals + } + } + + impl Eq for sigevent {} + + impl hash::Hash for sigevent { + fn hash(&self, s: &mut H) { + self.sigev_notify.hash(s); + self.sigev_signo.hash(s); + self.sigev_value.hash(s); + // Safe because we check the sigev_notify discriminant + unsafe { + match self.sigev_notify { + libc::SIGEV_KEVENT => { + self._sigev_un._kevent_flags.hash(s); + } + libc::SIGEV_THREAD_ID => { + self._sigev_un._threadid.hash(s); + } + libc::SIGEV_THREAD => { + self._sigev_un._sigev_thread.hash(s); + } + _ => /* The union field is don't care */ () + } + } + } + } + } /// Used to request asynchronous notification of the completion of certain /// events, such as POSIX AIO and timers. #[repr(C)] - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + #[derive(Clone, Debug, Eq, Hash, PartialEq)] + // It can't be Copy on all platforms. + #[allow(missing_copy_implementations)] pub struct SigEvent { - sigevent: libc::sigevent + sigevent: libc_sigevent } impl SigEvent { @@ -1107,65 +1244,90 @@ mod sigevent { /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the /// more genuinely useful `sigev_notify_thread_id` pub fn new(sigev_notify: SigevNotify) -> SigEvent { - let mut sev = unsafe { mem::MaybeUninit::::zeroed().assume_init() }; - sev.sigev_notify = match sigev_notify { - SigevNotify::SigevNone => libc::SIGEV_NONE, - SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL, + let mut sev: libc_sigevent = unsafe { mem::zeroed() }; + match sigev_notify { + SigevNotify::SigevNone => { + sev.sigev_notify = libc::SIGEV_NONE; + }, + SigevNotify::SigevSignal{signal, si_value} => { + sev.sigev_notify = libc::SIGEV_SIGNAL; + sev.sigev_signo = signal as libc::c_int; + sev.sigev_value.sival_ptr = si_value as *mut libc::c_void + }, #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT, + SigevNotify::SigevKevent{kq, udata} => { + sev.sigev_notify = libc::SIGEV_KEVENT; + sev.sigev_signo = kq; + sev.sigev_value.sival_ptr = udata as *mut libc::c_void; + }, #[cfg(target_os = "freebsd")] - SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, - #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))] - SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, - #[cfg(all(target_os = "linux", target_env = "uclibc", not(target_arch = "mips")))] - SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, - #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))] - SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined - }; - sev.sigev_signo = match sigev_notify { - SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevNotify::SigevKevent{ kq, ..} => kq, - #[cfg(any(target_os = "linux", target_os = "freebsd"))] - SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int, - _ => 0 - }; - sev.sigev_value.sival_ptr = match sigev_notify { - SigevNotify::SigevNone => ptr::null_mut::(), - SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void, - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void, - }; - SigEvent::set_tid(&mut sev, &sigev_notify); + #[cfg(feature = "event")] + SigevNotify::SigevKeventFlags{kq, udata, flags} => { + sev.sigev_notify = libc::SIGEV_KEVENT; + sev.sigev_signo = kq; + sev.sigev_value.sival_ptr = udata as *mut libc::c_void; + sev._sigev_un._kevent_flags = flags.bits(); + }, + #[cfg(target_os = "freebsd")] + SigevNotify::SigevThreadId{signal, thread_id, si_value} => { + sev.sigev_notify = libc::SIGEV_THREAD_ID; + sev.sigev_signo = signal as libc::c_int; + sev.sigev_value.sival_ptr = si_value as *mut libc::c_void; + sev._sigev_un._threadid = thread_id; + } + #[cfg(any(target_env = "gnu", target_env = "uclibc"))] + SigevNotify::SigevThreadId{signal, thread_id, si_value} => { + sev.sigev_notify = libc::SIGEV_THREAD_ID; + sev.sigev_signo = signal as libc::c_int; + sev.sigev_value.sival_ptr = si_value as *mut libc::c_void; + sev.sigev_notify_thread_id = thread_id; + } + } SigEvent{sigevent: sev} } - #[cfg(any(target_os = "freebsd", target_os = "linux"))] - fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) { - sev.sigev_notify_thread_id = match *sigev_notify { - SigevNotify::SigevThreadId { thread_id, .. } => thread_id, - _ => 0 as type_of_thread_id - }; - } - - #[cfg(not(any(target_os = "freebsd", target_os = "linux")))] - fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) { + /// Return a copy of the inner structure + #[cfg(target_os = "freebsd")] + pub fn sigevent(&self) -> libc::sigevent { + // Safe because they're really the same structure. See + // https://github.com/rust-lang/libc/pull/2813 + unsafe { + mem::transmute::(self.sigevent) + } } /// Return a copy of the inner structure + #[cfg(not(target_os = "freebsd"))] pub fn sigevent(&self) -> libc::sigevent { self.sigevent } /// Returns a mutable pointer to the `sigevent` wrapped by `self` + #[cfg(target_os = "freebsd")] + pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent { + // Safe because they're really the same structure. See + // https://github.com/rust-lang/libc/pull/2813 + &mut self.sigevent as *mut libc_sigevent as *mut libc::sigevent + } + + /// Returns a mutable pointer to the `sigevent` wrapped by `self` + #[cfg(not(target_os = "freebsd"))] pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent { &mut self.sigevent } } impl<'a> From<&'a libc::sigevent> for SigEvent { + #[cfg(target_os = "freebsd")] + fn from(sigevent: &libc::sigevent) -> Self { + // Safe because they're really the same structure. See + // https://github.com/rust-lang/libc/pull/2813 + let sigevent = unsafe { + mem::transmute::(*sigevent) + }; + SigEvent{ sigevent } + } + #[cfg(not(target_os = "freebsd"))] fn from(sigevent: &libc::sigevent) -> Self { SigEvent{ sigevent: *sigevent } } From 93d43a70b75ae7911aed1ccb24ddff8b13d38853 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 27 Aug 2023 00:53:55 +0100 Subject: [PATCH 349/358] introduces FreeBSD's SO_TS_CLOCK into net::sys::socket::sockopt. (#2093) * introduces FreeBSD's SO_TS_CLOCK into net::sys::socket::sockopt. close GH-2058. * CHANGELOG entry * changes from feedback --- CHANGELOG.md | 2 ++ src/sys/socket/sockopt.rs | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b99255ca82..43da4107a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added `MSG_WAITFORONE` to `MsgFlags` on Android, Fuchsia, Linux, NetBSD, FreeBSD, OpenBSD, and Solaris. ([#2014](https://github.com/nix-rust/nix/pull/2014)) +- Added `SO_TS_CLOCK` for FreeBSD to `nix::sys::socket::sockopt`. + ([#2093](https://github.com/nix-rust/nix/pull/2093)) ### Changed diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index ba380a86b3..44f3ebbc1d 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -711,6 +711,16 @@ sockopt_impl!( libc::SO_TIMESTAMPNS, bool ); +#[cfg(target_os = "freebsd")] +sockopt_impl!( + /// Sets a specific timestamp format instead of the classic `SCM_TIMESTAMP`, + /// to follow up after `SO_TIMESTAMP` is set. + TsClock, + Both, + libc::SOL_SOCKET, + libc::SO_TS_CLOCK, + i32 +); #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg(feature = "net")] sockopt_impl!( From 56e1277d4992b11e213c1b2ea9e60618025b40b6 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Sun, 27 Aug 2023 17:34:10 -0400 Subject: [PATCH 350/358] Make `clone` unsafe (#1993) * Make `clone` unsafe There are many features of `clone` that may cause memory unsafety when called. This documents one of them and references `fork()`, which is already unsafe to call. * Adjust the clone entry in the CHANGELOG --------- Co-authored-by: Alan Somers --- CHANGELOG.md | 2 ++ src/sched.rs | 38 +++++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43da4107a5..c436d146c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). See ([#2097](https://github.com/nix-rust/nix/pull/2097)) - Refactored `name` parameter of `mq_open` and `mq_unlink` to be generic over `NixPath`. See ([#2102](https://github.com/nix-rust/nix/pull/2102)). +- Made `clone` unsafe, like `fork`. + ([#1993](https://github.com/nix-rust/nix/pull/1993)) ### Fixed - Fix: send `ETH_P_ALL` in htons format diff --git a/src/sched.rs b/src/sched.rs index 0515e30f29..c9d5d6d8a1 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -95,7 +95,17 @@ mod sched_linux_like { /// address need not be the highest address of the region. Nix will take /// care of that requirement. The user only needs to provide a reference to /// a normally allocated buffer. - pub fn clone( + /// + /// # Safety + /// + /// Because `clone` creates a child process with its stack located in + /// `stack` without specifying the size of the stack, special care must be + /// taken to ensure that the child process does not overflow the provided + /// stack space. + /// + /// See [`fork`](crate::unistd::fork) for additional safety concerns related + /// to executing child processes. + pub unsafe fn clone( mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags, @@ -106,20 +116,18 @@ mod sched_linux_like { (*cb)() as c_int } - let res = unsafe { - let combined = flags.bits() | signal.unwrap_or(0); - let ptr = stack.as_mut_ptr().add(stack.len()); - let ptr_aligned = ptr.sub(ptr as usize % 16); - libc::clone( - mem::transmute( - callback - as extern "C" fn(*mut Box isize>) -> i32, - ), - ptr_aligned as *mut c_void, - combined, - &mut cb as *mut _ as *mut c_void, - ) - }; + let combined = flags.bits() | signal.unwrap_or(0); + let ptr = stack.as_mut_ptr().add(stack.len()); + let ptr_aligned = ptr.sub(ptr as usize % 16); + let res = libc::clone( + mem::transmute( + callback + as extern "C" fn(*mut Box isize>) -> i32, + ), + ptr_aligned as *mut c_void, + combined, + &mut cb as *mut _ as *mut c_void, + ); Errno::result(res).map(Pid::from_raw) } From d59d2353e42c7aa408f455a3d8149011e989228c Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 27 Aug 2023 15:34:26 -0600 Subject: [PATCH 351/358] Eliminate the lazy_static dev dependency (#2107) It's no longer needed, because for several versions now AtomicBool::new and parking_lot::Mutex::new are const functions. Fixes #1791 --- Cargo.toml | 1 - src/sys/aio.rs | 5 +---- src/sys/signal.rs | 5 +---- test/sys/test_aio.rs | 4 +--- test/sys/test_signal.rs | 4 +--- test/test.rs | 36 ++++++++++++++++-------------------- 6 files changed, 20 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 010c9f895b..f15a932f61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,6 @@ zerocopy = ["fs", "uio"] [dev-dependencies] assert-impl = "0.1" -lazy_static = "1.4" parking_lot = "0.12" rand = "0.8" tempfile = "3.7.1" diff --git a/src/sys/aio.rs b/src/sys/aio.rs index bd4c122916..5471177e3e 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -1142,14 +1142,11 @@ pub fn aio_suspend( /// # use std::sync::atomic::{AtomicBool, Ordering}; /// # use std::thread; /// # use std::time; -/// # use lazy_static::lazy_static; /// # use nix::errno::Errno; /// # use nix::sys::aio::*; /// # use nix::sys::signal::*; /// # use tempfile::tempfile; -/// lazy_static! { -/// pub static ref SIGNALED: AtomicBool = AtomicBool::new(false); -/// } +/// pub static SIGNALED: AtomicBool = AtomicBool::new(false); /// /// extern fn sigfunc(_: c_int) { /// SIGNALED.store(true, Ordering::Relaxed); diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 34f60e2c82..c946e4a0b1 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -841,13 +841,10 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result(f: Fd, buf: &mut [u8]) { } } -lazy_static! { - /// Any test that changes the process's current working directory must grab - /// the RwLock exclusively. Any process that cares about the current - /// working directory must grab it shared. - pub static ref CWD_LOCK: RwLock<()> = RwLock::new(()); - /// Any test that creates child processes must grab this mutex, regardless - /// of what it does with those children. - pub static ref FORK_MTX: Mutex<()> = Mutex::new(()); - /// Any test that changes the process's supplementary groups must grab this - /// mutex - pub static ref GROUPS_MTX: Mutex<()> = Mutex::new(()); - /// Any tests that loads or unloads kernel modules must grab this mutex - pub static ref KMOD_MTX: Mutex<()> = Mutex::new(()); - /// Any test that calls ptsname(3) must grab this mutex. - pub static ref PTSNAME_MTX: Mutex<()> = Mutex::new(()); - /// Any test that alters signal handling must grab this mutex. - pub static ref SIGNAL_MTX: Mutex<()> = Mutex::new(()); -} +/// Any test that creates child processes must grab this mutex, regardless +/// of what it does with those children. +pub static FORK_MTX: std::sync::Mutex<()> = std::sync::Mutex::new(()); +/// Any test that changes the process's current working directory must grab +/// the RwLock exclusively. Any process that cares about the current +/// working directory must grab it shared. +pub static CWD_LOCK: RwLock<()> = RwLock::new(()); +/// Any test that changes the process's supplementary groups must grab this +/// mutex +pub static GROUPS_MTX: Mutex<()> = Mutex::new(()); +/// Any tests that loads or unloads kernel modules must grab this mutex +pub static KMOD_MTX: Mutex<()> = Mutex::new(()); +/// Any test that calls ptsname(3) must grab this mutex. +pub static PTSNAME_MTX: Mutex<()> = Mutex::new(()); +/// Any test that alters signal handling must grab this mutex. +pub static SIGNAL_MTX: Mutex<()> = Mutex::new(()); /// RAII object that restores a test's original directory on drop struct DirRestore<'a> { From 3a4037c8b903542a5c26c4094a4dedee90e27441 Mon Sep 17 00:00:00 2001 From: Daniel Ohlsson <2997226+DOhlsson@users.noreply.github.com> Date: Sun, 27 Aug 2023 23:34:43 +0200 Subject: [PATCH 352/358] Added support for prctl in Linux (#1550) --- CHANGELOG.md | 3 + Cargo.toml | 4 + src/sys/mod.rs | 6 ++ src/sys/prctl.rs | 208 +++++++++++++++++++++++++++++++++++++++++ test/sys/test_prctl.rs | 125 +++++++++++++++++++++++++ 5 files changed, 346 insertions(+) create mode 100644 src/sys/prctl.rs create mode 100644 test/sys/test_prctl.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index c436d146c3..4b1ba8c764 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#2014](https://github.com/nix-rust/nix/pull/2014)) - Added `SO_TS_CLOCK` for FreeBSD to `nix::sys::socket::sockopt`. ([#2093](https://github.com/nix-rust/nix/pull/2093)) +- Added support for prctl in Linux. + (#[1550](https://github.com/nix-rust/nix/pull/1550)) + ### Changed diff --git a/Cargo.toml b/Cargo.toml index f15a932f61..f0073c1648 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,3 +98,7 @@ path = "test/test_clearenv.rs" name = "test-mount" path = "test/test_mount.rs" harness = false + +[[test]] +name = "test-prctl" +path = "test/sys/test_prctl.rs" diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 9bba1c4e9e..bf047b3dda 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -67,6 +67,12 @@ feature! { pub mod personality; } +#[cfg(target_os = "linux")] +feature! { + #![feature = "process"] + pub mod prctl; +} + feature! { #![feature = "pthread"] pub mod pthread; diff --git a/src/sys/prctl.rs b/src/sys/prctl.rs new file mode 100644 index 0000000000..995382cb0c --- /dev/null +++ b/src/sys/prctl.rs @@ -0,0 +1,208 @@ +//! prctl is a Linux-only API for performing operations on a process or thread. +//! +//! Note that careless use of some prctl() operations can confuse the user-space run-time +//! environment, so these operations should be used with care. +//! +//! For more documentation, please read [prctl(2)](https://man7.org/linux/man-pages/man2/prctl.2.html). + +use crate::errno::Errno; +use crate::sys::signal::Signal; +use crate::Result; + +use libc::{c_int, c_ulong}; +use std::convert::TryFrom; +use std::ffi::{CStr, CString}; + +libc_enum! { + /// The type of hardware memory corruption kill policy for the thread. + + #[repr(i32)] + #[non_exhaustive] + #[allow(non_camel_case_types)] + pub enum PrctlMCEKillPolicy { + /// The thread will receive SIGBUS as soon as a memory corruption is detected. + PR_MCE_KILL_EARLY, + /// The process is killed only when it accesses a corrupted page. + PR_MCE_KILL_LATE, + /// Uses the system-wide default. + PR_MCE_KILL_DEFAULT, + } + impl TryFrom +} + +fn prctl_set_bool(option: c_int, status: bool) -> Result<()> { + let res = unsafe { libc::prctl(option, status as c_ulong, 0, 0, 0) }; + Errno::result(res).map(drop) +} + +fn prctl_get_bool(option: c_int) -> Result { + let res = unsafe { libc::prctl(option, 0, 0, 0, 0) }; + Errno::result(res).map(|res| res != 0) +} + +/// Set the "child subreaper" attribute for this process +pub fn set_child_subreaper(attribute: bool) -> Result<()> { + prctl_set_bool(libc::PR_SET_CHILD_SUBREAPER, attribute) +} + +/// Get the "child subreaper" attribute for this process +pub fn get_child_subreaper() -> Result { + // prctl writes into this var + let mut subreaper: c_int = 0; + + let res = unsafe { libc::prctl(libc::PR_GET_CHILD_SUBREAPER, &mut subreaper, 0, 0, 0) }; + + Errno::result(res).map(|_| subreaper != 0) +} + +/// Set the dumpable attribute which determines if core dumps are created for this process. +pub fn set_dumpable(attribute: bool) -> Result<()> { + prctl_set_bool(libc::PR_SET_DUMPABLE, attribute) +} + +/// Get the dumpable attribute for this process. +pub fn get_dumpable() -> Result { + prctl_get_bool(libc::PR_GET_DUMPABLE) +} + +/// Set the "keep capabilities" attribute for this process. This causes the thread to retain +/// capabilities even if it switches its UID to a nonzero value. +pub fn set_keepcaps(attribute: bool) -> Result<()> { + prctl_set_bool(libc::PR_SET_KEEPCAPS, attribute) +} + +/// Get the "keep capabilities" attribute for this process +pub fn get_keepcaps() -> Result { + prctl_get_bool(libc::PR_GET_KEEPCAPS) +} + +/// Clear the thread memory corruption kill policy and use the system-wide default +pub fn clear_mce_kill() -> Result<()> { + let res = unsafe { libc::prctl(libc::PR_MCE_KILL, libc::PR_MCE_KILL_CLEAR, 0, 0, 0) }; + + Errno::result(res).map(drop) +} + +/// Set the thread memory corruption kill policy +pub fn set_mce_kill(policy: PrctlMCEKillPolicy) -> Result<()> { + let res = unsafe { + libc::prctl( + libc::PR_MCE_KILL, + libc::PR_MCE_KILL_SET, + policy as c_ulong, + 0, + 0, + ) + }; + + Errno::result(res).map(drop) +} + +/// Get the thread memory corruption kill policy +pub fn get_mce_kill() -> Result { + let res = unsafe { libc::prctl(libc::PR_MCE_KILL_GET, 0, 0, 0, 0) }; + + match Errno::result(res) { + Ok(val) => Ok(PrctlMCEKillPolicy::try_from(val)?), + Err(e) => Err(e), + } +} + +/// Set the parent-death signal of the calling process. This is the signal that the calling process +/// will get when its parent dies. +pub fn set_pdeathsig>>(signal: T) -> Result<()> { + let sig = match signal.into() { + Some(s) => s as c_int, + None => 0, + }; + + let res = unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, sig, 0, 0, 0) }; + + Errno::result(res).map(drop) +} + +/// Returns the current parent-death signal +pub fn get_pdeathsig() -> Result> { + // prctl writes into this var + let mut sig: c_int = 0; + + let res = unsafe { libc::prctl(libc::PR_GET_PDEATHSIG, &mut sig, 0, 0, 0) }; + + match Errno::result(res) { + Ok(_) => Ok(match sig { + 0 => None, + _ => Some(Signal::try_from(sig)?), + }), + Err(e) => Err(e), + } +} + +/// Set the name of the calling thread. Strings longer than 15 bytes will be truncated. +pub fn set_name(name: &CStr) -> Result<()> { + let res = unsafe { libc::prctl(libc::PR_SET_NAME, name.as_ptr(), 0, 0, 0) }; + + Errno::result(res).map(drop) +} + +/// Return the name of the calling thread +pub fn get_name() -> Result { + // Size of buffer determined by linux/sched.h TASK_COMM_LEN + let buf = [0u8; 16]; + + let res = unsafe { libc::prctl(libc::PR_GET_NAME, &buf, 0, 0, 0) }; + + let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len()); + let name = CStr::from_bytes_with_nul(&buf[..=len]).map_err(|_| Errno::EINVAL)?; + + Errno::result(res).map(|_| name.to_owned()) +} + +/// Sets the timer slack value for the calling thread. Timer slack is used by the kernel to group +/// timer expirations and make them the supplied amount of nanoseconds late. +pub fn set_timerslack(ns: u64) -> Result<()> { + let res = unsafe { libc::prctl(libc::PR_SET_TIMERSLACK, ns, 0, 0, 0) }; + + Errno::result(res).map(drop) +} + +/// Get the timerslack for the calling thread. +pub fn get_timerslack() -> Result { + let res = unsafe { libc::prctl(libc::PR_GET_TIMERSLACK, 0, 0, 0, 0) }; + + Errno::result(res) +} + +/// Disable all performance counters attached to the calling process. +pub fn task_perf_events_disable() -> Result<()> { + let res = unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_DISABLE, 0, 0, 0, 0) }; + + Errno::result(res).map(drop) +} + +/// Enable all performance counters attached to the calling process. +pub fn task_perf_events_enable() -> Result<()> { + let res = unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_ENABLE, 0, 0, 0, 0) }; + + Errno::result(res).map(drop) +} + +/// Set the calling threads "no new privs" attribute. Once set this option can not be unset. +pub fn set_no_new_privs() -> Result<()> { + prctl_set_bool(libc::PR_SET_NO_NEW_PRIVS, true) // Cannot be unset +} + +/// Get the "no new privs" attribute for the calling thread. +pub fn get_no_new_privs() -> Result { + prctl_get_bool(libc::PR_GET_NO_NEW_PRIVS) +} + +/// Set the state of the "THP disable" flag for the calling thread. Setting this disables +/// transparent huge pages. +pub fn set_thp_disable(flag: bool) -> Result<()> { + prctl_set_bool(libc::PR_SET_THP_DISABLE, flag) +} + +/// Get the "THP disable" flag for the calling thread. +pub fn get_thp_disable() -> Result { + prctl_get_bool(libc::PR_GET_THP_DISABLE) +} diff --git a/test/sys/test_prctl.rs b/test/sys/test_prctl.rs new file mode 100644 index 0000000000..351213b7ef --- /dev/null +++ b/test/sys/test_prctl.rs @@ -0,0 +1,125 @@ +#[cfg(target_os = "linux")] +#[cfg(feature = "process")] +mod test_prctl { + use std::ffi::CStr; + + use nix::sys::prctl; + + #[cfg_attr(qemu, ignore)] + #[test] + fn test_get_set_subreaper() { + let original = prctl::get_child_subreaper().unwrap(); + + prctl::set_child_subreaper(true).unwrap(); + let subreaper = prctl::get_child_subreaper().unwrap(); + assert!(subreaper); + + prctl::set_child_subreaper(original).unwrap(); + } + + #[test] + fn test_get_set_dumpable() { + let original = prctl::get_dumpable().unwrap(); + + prctl::set_dumpable(false).unwrap(); + let dumpable = prctl::get_dumpable().unwrap(); + assert!(!dumpable); + + prctl::set_dumpable(original).unwrap(); + } + + #[test] + fn test_get_set_keepcaps() { + let original = prctl::get_keepcaps().unwrap(); + + prctl::set_keepcaps(true).unwrap(); + let keepcaps = prctl::get_keepcaps().unwrap(); + assert!(keepcaps); + + prctl::set_keepcaps(original).unwrap(); + } + + #[test] + fn test_get_set_clear_mce_kill() { + use prctl::PrctlMCEKillPolicy::*; + + prctl::set_mce_kill(PR_MCE_KILL_LATE).unwrap(); + let mce = prctl::get_mce_kill().unwrap(); + assert_eq!(mce, PR_MCE_KILL_LATE); + + prctl::clear_mce_kill().unwrap(); + let mce = prctl::get_mce_kill().unwrap(); + assert_eq!(mce, PR_MCE_KILL_DEFAULT); + } + + #[cfg_attr(qemu, ignore)] + #[test] + fn test_get_set_pdeathsig() { + use nix::sys::signal::Signal; + + let original = prctl::get_pdeathsig().unwrap(); + + prctl::set_pdeathsig(Signal::SIGUSR1).unwrap(); + let sig = prctl::get_pdeathsig().unwrap(); + assert_eq!(sig, Some(Signal::SIGUSR1)); + + prctl::set_pdeathsig(original).unwrap(); + } + + #[test] + fn test_get_set_name() { + let original = prctl::get_name().unwrap(); + + let long_name = + CStr::from_bytes_with_nul(b"0123456789abcdefghijklmn\0").unwrap(); + prctl::set_name(long_name).unwrap(); + let res = prctl::get_name().unwrap(); + + // name truncated by kernel to TASK_COMM_LEN + assert_eq!(&long_name.to_str().unwrap()[..15], res.to_str().unwrap()); + + let short_name = CStr::from_bytes_with_nul(b"01234567\0").unwrap(); + prctl::set_name(short_name).unwrap(); + let res = prctl::get_name().unwrap(); + assert_eq!(short_name.to_str().unwrap(), res.to_str().unwrap()); + + prctl::set_name(&original).unwrap(); + } + + #[cfg_attr(qemu, ignore)] + #[test] + fn test_get_set_timerslack() { + let original = prctl::get_timerslack().unwrap(); + + let slack = 60_000; + prctl::set_timerslack(slack).unwrap(); + let res = prctl::get_timerslack().unwrap(); + assert_eq!(slack, res as u64); + + prctl::set_timerslack(original as u64).unwrap(); + } + + #[test] + fn test_disable_enable_perf_events() { + prctl::task_perf_events_disable().unwrap(); + prctl::task_perf_events_enable().unwrap(); + } + + #[test] + fn test_get_set_no_new_privs() { + prctl::set_no_new_privs().unwrap(); + let no_new_privs = prctl::get_no_new_privs().unwrap(); + assert!(no_new_privs); + } + + #[test] + fn test_get_set_thp_disable() { + let original = prctl::get_thp_disable().unwrap(); + + prctl::set_thp_disable(true).unwrap(); + let thp_disable = prctl::get_thp_disable().unwrap(); + assert!(thp_disable); + + prctl::set_thp_disable(original).unwrap(); + } +} From a2a9a711034830ac9bd84d6cb505e0002bfb2152 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 27 Aug 2023 17:28:15 -0600 Subject: [PATCH 353/358] release.toml: compatibility with cargo-release 0.22 (#2108) which no longer supports dev-version. [skip ci] --- release.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/release.toml b/release.toml index a47a0f8271..23488fbfa5 100644 --- a/release.toml +++ b/release.toml @@ -1,4 +1,3 @@ -dev-version = false pre-release-replacements = [ { file="CHANGELOG.md", search="Unreleased", replace="{{version}}" }, { file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}" } From d491f877791f5fcc831c7bb8c3b23ee79842a753 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 27 Aug 2023 18:04:35 -0600 Subject: [PATCH 354/358] Edit CHANGELOG (#2109) * Add entry for 0.26.3, released from a separate branch * Reorder some entries, and tweak a few for consistency. * Change the crate version to 0.26.3 --- CHANGELOG.md | 74 +++++++++++++++++++++++++++------------------------- Cargo.toml | 2 +- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b1ba8c764..a5dda9d857 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,9 +28,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#2085](https://github.com/nix-rust/nix/pull/2085)) - Added `SO_RTABLE` for OpenBSD and `SO_ACCEPTFILTER` for FreeBSD/NetBSD to `nix::sys::socket::sockopt`. ([#2085](https://github.com/nix-rust/nix/pull/2085)) -- Removed `flock` from `::nix::fcntl` on Solaris. ([#2082](https://github.com/nix-rust/nix/pull/2082)) -- Use I/O safety with `copy_file_range`, and expose it on FreeBSD. - (#[1906](https://github.com/nix-rust/nix/pull/1906)) - Added `MSG_WAITFORONE` to `MsgFlags` on Android, Fuchsia, Linux, NetBSD, FreeBSD, OpenBSD, and Solaris. ([#2014](https://github.com/nix-rust/nix/pull/2014)) @@ -38,10 +35,28 @@ This project adheres to [Semantic Versioning](https://semver.org/). ([#2093](https://github.com/nix-rust/nix/pull/2093)) - Added support for prctl in Linux. (#[1550](https://github.com/nix-rust/nix/pull/1550)) - +- `nix::socket` and `nix::select` are now available on Redox. + ([#2012](https://github.com/nix-rust/nix/pull/2012)) +- Implemented AsFd, AsRawFd, FromRawFd, and IntoRawFd for `mqueue::MqdT`. + ([#2097](https://github.com/nix-rust/nix/pull/2097)) +- Add the ability to set `kevent_flags` on `SigEvent`. + ([#1731](https://github.com/nix-rust/nix/pull/1731)) ### Changed +- All Cargo features have been removed from the default set. Users will need to + specify which features they depend on in their Cargo.toml. + ([#2091](https://github.com/nix-rust/nix/pull/2091)) +- Implemented I/O safety for many, but not all, of Nix's APIs. Many public + functions argument and return types have changed: + | Original Type | New Type | + | ------------- | --------------------- | + | AsRawFd | AsFd | + | RawFd | BorrowedFd or OwnedFd | + + (#[1906](https://github.com/nix-rust/nix/pull/1906)) +- Use I/O safety with `copy_file_range`, and expose it on FreeBSD. + (#[1906](https://github.com/nix-rust/nix/pull/1906)) - The MSRV is now 1.65 ([#1862](https://github.com/nix-rust/nix/pull/1862)) ([#2104](https://github.com/nix-rust/nix/pull/2104)) @@ -50,30 +65,31 @@ This project adheres to [Semantic Versioning](https://semver.org/). - With I/O-safe type applied in `pty::OpenptyResult` and `pty::ForkptyResult`, users no longer need to manually close the file descriptors in these types. ([#1921](https://github.com/nix-rust/nix/pull/1921)) +- Refactored `name` parameter of `mq_open` and `mq_unlink` to be generic over + `NixPath`. + ([#2102](https://github.com/nix-rust/nix/pull/2102)). +- Made `clone` unsafe, like `fork`. + ([#1993](https://github.com/nix-rust/nix/pull/1993)) + +### Removed + - `sys::event::{kevent, kevent_ts}` are deprecated in favor of `sys::kevent::Kqueue::kevent`, and `sys::event::kqueue` is deprecated in favor of `sys::kevent::Kqueue::new`. ([#1943](https://github.com/nix-rust/nix/pull/1943)) -- `nix::socket` and `nix::select` are now available on Redox. - ([#2012](https://github.com/nix-rust/nix/pull/2012)) -- All features have been removed from the default set. Users will need to specify - which features they depend on in their Cargo.toml. - ([#2091](https://github.com/nix-rust/nix/pull/2091)) - -- Implemented I/O safety. Many public functions argument and return types have - changed: - | Original Type | New Type | - | ------------- | --------------------- | - | AsRawFd | AsFd | - | RawFd | BorrowedFd or OwnedFd | +- Removed deprecated IoVec API. + ([#1855](https://github.com/nix-rust/nix/pull/1855)) +- Removed deprecated net APIs. + ([#1861](https://github.com/nix-rust/nix/pull/1861)) +- `nix::sys::signalfd::signalfd` is deprecated. Use + `nix::sys::signalfd::SignalFd` instead. + ([#1938](https://github.com/nix-rust/nix/pull/1938)) +- Removed `SigEvent` support on Fuchsia, where it was unsound. + ([#2079](https://github.com/nix-rust/nix/pull/2079)) +- Removed `flock` from `::nix::fcntl` on Solaris. + ([#2082](https://github.com/nix-rust/nix/pull/2082)) - (#[1906](https://github.com/nix-rust/nix/pull/1906)) -- Implemented AsFd, AsRawFd, FromRawFd, and IntoRawFd for `mqueue::MqdT`. - See ([#2097](https://github.com/nix-rust/nix/pull/2097)) -- Refactored `name` parameter of `mq_open` and `mq_unlink` to be generic over - `NixPath`. See ([#2102](https://github.com/nix-rust/nix/pull/2102)). -- Made `clone` unsafe, like `fork`. - ([#1993](https://github.com/nix-rust/nix/pull/1993)) +## [0.26.3] - 2023-08-27 ### Fixed - Fix: send `ETH_P_ALL` in htons format @@ -88,18 +104,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed an incorrect lifetime returned from `recvmsg`. ([#2095](https://github.com/nix-rust/nix/pull/2095)) -### Removed - -- Removed deprecated IoVec API. - ([#1855](https://github.com/nix-rust/nix/pull/1855)) -- Removed deprecated net APIs. - ([#1861](https://github.com/nix-rust/nix/pull/1861)) -- `nix::sys::signalfd::signalfd` is deprecated. Use - `nix::sys::signalfd::SignalFd` instead. - ([#1938](https://github.com/nix-rust/nix/pull/1938)) -- Removed `SigEvent` support on Fuchsia, where it was unsound. - ([#2079](https://github.com/nix-rust/nix/pull/2079)) - ## [0.26.2] - 2023-01-18 ### Fixed diff --git a/Cargo.toml b/Cargo.toml index f0073c1648..8d76229a66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2021" -version = "0.26.1" +version = "0.26.3" rust-version = "1.65" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" From 842142f9dd61dfc3261ffefce90faa278f42f37c Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 27 Aug 2023 19:20:33 -0600 Subject: [PATCH 355/358] chore: Release nix version 0.27.0 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5dda9d857..4aba1468ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). -## [Unreleased] - ReleaseDate +## [0.27.0] - 2023-08-28 ### Added - Added `AT_EACCESS` to `AtFlags` on all platforms but android ([#1995](https://github.com/nix-rust/nix/pull/1995)) diff --git a/Cargo.toml b/Cargo.toml index 8d76229a66..1290067d53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2021" -version = "0.26.3" +version = "0.27.0" rust-version = "1.65" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" From b2e45a930acc636ea14c8ee4c8c13f0c92448d16 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 28 Aug 2023 07:04:53 -0600 Subject: [PATCH 356/358] Enable all features when building on docs.rs (#2111) Fixes #2110 [skip ci] --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 1290067d53..a8c77f7683 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ categories = ["os::unix-apis"] include = ["src/**/*", "test/**/*", "LICENSE", "README.md", "CHANGELOG.md"] [package.metadata.docs.rs] +all-features = true rustdoc-args = ["--cfg", "docsrs"] targets = [ "x86_64-unknown-linux-gnu", From a513f313d90a29ecc8003b693a628c972fadce44 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 28 Aug 2023 07:50:16 -0600 Subject: [PATCH 357/358] Update CHANGELOG for PR #2111 [skip ci] --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4aba1468ae..07edfbf114 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +## [Unreleased] - ReleaseDate + +### Fixed + +- Fixed generating the documentation on docs.rs. + ([#2111](https://github.com/nix-rust/nix/pull/2111)) + ## [0.27.0] - 2023-08-28 ### Added - Added `AT_EACCESS` to `AtFlags` on all platforms but android From 996db47d542ae20f09eb344b9fcb88c40ae38e3d Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 28 Aug 2023 07:52:24 -0600 Subject: [PATCH 358/358] chore: Release nix version 0.27.1 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07edfbf114..3a171afd68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). -## [Unreleased] - ReleaseDate +## [0.27.1] - 2023-08-28 ### Fixed diff --git a/Cargo.toml b/Cargo.toml index a8c77f7683..5a7806075a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2021" -version = "0.27.0" +version = "0.27.1" rust-version = "1.65" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix"