diff options
author | Jeffrey Vander Stoep <jeffv@google.com> | 2023-01-17 18:17:47 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2023-01-17 18:17:47 +0000 |
commit | 7c087f1848f54cd2d6f34318d1e6bf479d8cf8a3 (patch) | |
tree | a8592552e0ad623519128851864362b1b67bfd7c | |
parent | 4ede6a59c9cca46d5443f791c98679ef8546da36 (diff) | |
parent | f62f670293e33956eb7343a3ff1104d2abf05a7f (diff) | |
download | nix-main-16k-with-phones.tar.gz |
Merge "Upgrade nix to 0.26.1"main-16k-with-phones
73 files changed, 4239 insertions, 2173 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index c99e6c8..1448400 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "4d4754a14b080b32b1af16de54dfb822b28b5f06" + "sha1": "e7a646ddff63b912b3a5afab6464465d800de350" }, "path_in_vcs": "" }
\ No newline at end of file @@ -26,7 +26,7 @@ rust_library { host_supported: true, crate_name: "nix", cargo_env_compat: true, - cargo_pkg_version: "0.25.0", + cargo_pkg_version: "0.26.1", srcs: ["src/lib.rs"], edition: "2018", features: [ @@ -72,6 +72,7 @@ rust_library { "liblibc", "libmemoffset", "libpin_utils", + "libstatic_assertions", ], apex_available: [ "//apex_available:platform", diff --git a/CHANGELOG.md b/CHANGELOG.md index f06e412..a332bc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,84 @@ 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 +### 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 +### Added + +- 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)) +- 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. + ([#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)) +- 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)) +- 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)) +- 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)) +- 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)) +- added `IP_MTU` (`IpMtu`) `IPPROTO_IP` sockopt on Linux and Android. + ([#1865](https://github.com/nix-rust/nix/pull/1865)) + +### Changed + +- 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<NonZeroUsize>`. + ([#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 + +- 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 + 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)) +- Workaround XNU bug causing netmasks returned by `getifaddrs` to misbehave. + ([#1788](https://github.com/nix-rust/nix/pull/1788)) + +### Removed + +- Removed deprecated error constants and conversions. + ([#1860](https://github.com/nix-rust/nix/pull/1860)) + ## [0.25.0] - 2022-08-13 ### Added @@ -44,6 +122,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. @@ -313,6 +394,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)) @@ -338,8 +443,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 @@ -395,6 +511,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 @@ -458,8 +588,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 @@ -572,22 +700,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 @@ -715,8 +837,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 @@ -741,8 +861,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. @@ -811,6 +929,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. @@ -828,14 +963,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 @@ -887,7 +1038,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 @@ -11,9 +11,9 @@ [package] edition = "2018" -rust-version = "1.46" +rust-version = "1.56" name = "nix" -version = "0.25.0" +version = "0.26.1" authors = ["The nix-rust Project Developers"] include = [ "src/**/*", @@ -75,13 +75,16 @@ version = "1.1" version = "1.0" [dependencies.libc] -version = "0.2.127" +version = "0.2.137" features = ["extra_traits"] [dependencies.pin-utils] version = "0.1.0" optional = true +[dependencies.static_assertions] +version = "1" + [dev-dependencies.assert-impl] version = "0.1" @@ -89,7 +92,7 @@ version = "0.1" version = "1.4" [dev-dependencies.parking_lot] -version = "0.11.2" +version = "0.12" [dev-dependencies.rand] version = "0.8" @@ -100,9 +103,6 @@ version = "1.0.7" [dev-dependencies.tempfile] version = "3.3.0" -[build-dependencies.autocfg] -version = "1.1.0" - [features] acct = [] aio = ["pin-utils"] @@ -178,7 +178,7 @@ zerocopy = [ version = "0.5.3" [target."cfg(not(target_os = \"redox\"))".dependencies.memoffset] -version = "0.6.3" +version = "0.7" optional = true [target."cfg(target_os = \"freebsd\")".dev-dependencies.sysctl] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 1d96efe..cfe20d8 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -2,8 +2,8 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2018" -version = "0.25.0" -rust-version = "1.46" +version = "0.26.1" +rust-version = "1.56" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" license = "MIT" @@ -27,16 +27,14 @@ targets = [ ] [dependencies] -libc = { version = "0.2.127", 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 } +static_assertions = "1" [target.'cfg(not(target_os = "redox"))'.dependencies] -memoffset = { version = "0.6.3", optional = true } - -[build-dependencies] -autocfg = "1.1.0" +memoffset = { version = "0.7", optional = true } [features] default = [ @@ -83,7 +81,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" @@ -1,3 +1,7 @@ +# This project was upgraded with external_updater. +# Usage: tools/external_updater/updater.sh update rust/crates/nix +# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md + name: "nix" description: "Rust friendly bindings to *nix APIs" third_party { @@ -7,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/nix/nix-0.25.0.crate" + value: "https://static.crates.io/crates/nix/nix-0.26.1.crate" } - version: "0.25.0" + version: "0.26.1" license_type: NOTICE last_upgrade_date { year: 2022 - month: 10 - day: 6 + month: 12 + day: 12 } } @@ -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 @@ -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<libc::DIR> -); +pub struct Dir(ptr::NonNull<libc::DIR>); impl Dir { /// Opens the given path as with `fcntl::open`. - pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, - mode: sys::stat::Mode) -> Result<Self> { + pub fn open<P: ?Sized + NixPath>( + path: &P, + oflag: OFlag, + mode: sys::stat::Mode, + ) -> Result<Self> { let fd = fcntl::open(path, oflag, mode)?; Dir::from_fd(fd) } /// Opens the given path as with `fcntl::openat`. - pub fn openat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P, oflag: OFlag, - mode: sys::stat::Mode) -> Result<Self> { + pub fn openat<P: ?Sized + NixPath>( + dirfd: RawFd, + path: &P, + oflag: OFlag, + mode: sys::stat::Mode, + ) -> Result<Self> { let fd = fcntl::openat(dirfd, path, oflag, mode)?; Dir::from_fd(fd) } @@ -55,13 +60,15 @@ 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<Self> { - 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<Result<Entry>> { // Probably fine here too then. let mut ent = std::mem::MaybeUninit::<dirent>::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,9 @@ 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 { cfg_if! { if #[cfg(any(target_os = "android", @@ -238,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<Type> { - #[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), @@ -251,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/errno.rs b/src/errno.rs index 912fb94..d8ad28d 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; @@ -47,38 +47,10 @@ fn clear() { /// Returns the platform-specific value of errno pub fn errno() -> i32 { - unsafe { (*errno_location()) as i32 } + unsafe { *errno_location() } } 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<Self> { - 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; diff --git a/src/fcntl.rs b/src/fcntl.rs index 160b022..6508283 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/features.rs b/src/features.rs index d2adc16..39d1760 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<usize> { 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 f834d30..70b50b0 100644 --- a/src/ifaddrs.rs +++ b/src/ifaddrs.rs @@ -4,14 +4,16 @@ //! 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; 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)] @@ -42,12 +44,52 @@ 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<SockaddrStorage> { + let src_sock = info.ifa_netmask; + if src_sock.is_null() { + return None; + } + + let mut dst_sock = mem::MaybeUninit::<libc::sockaddr_storage>::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::<libc::sockaddr_storage>()).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) }; - let netmask = unsafe { SockaddrStorage::from_raw(info.ifa_netmask, 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 { interface_name: ifname.to_string_lossy().to_string(), flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32), @@ -144,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?"); + } } diff --git a/src/kmod.rs b/src/kmod.rs index c42068c..1fa6c17 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<T: AsRawFd>(fd: &T, param_values: &CStr, flags: ModuleInitFlags) -> Result<()> { +pub fn finit_module<T: AsRawFd>( + 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) } @@ -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 109522f..d124f1f 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd.rs @@ -1,19 +1,17 @@ -use crate::{ - Error, - Errno, - NixPath, - Result, -}; -use libc::{c_char, c_int, c_uint, c_void}; +#[cfg(target_os = "freebsd")] +use crate::Error; +use crate::{Errno, NixPath, Result}; +use libc::c_int; +#[cfg(target_os = "freebsd")] +use libc::{c_char, c_uint, c_void}; +#[cfg(target_os = "freebsd")] use std::{ borrow::Cow, - ffi::{CString, CStr}, - fmt, - io, + ffi::{CStr, CString}, + fmt, io, marker::PhantomData, }; - libc_bitflags!( /// Used with [`Nmount::nmount`]. pub struct MntFlags: c_int { @@ -105,17 +103,18 @@ libc_bitflags!( } ); - /// The Error type of [`Nmount::nmount`]. /// /// 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<String> + errmsg: Option<String>, } +#[cfg(target_os = "freebsd")] impl NmountError { /// Returns the additional error string sometimes generated by `nmount(2)`. pub fn errmsg(&self) -> Option<&str> { @@ -130,13 +129,15 @@ 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), } } } +#[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 +148,7 @@ impl fmt::Display for NmountError { } } +#[cfg(target_os = "freebsd")] impl From<NmountError> for io::Error { fn from(err: NmountError) -> Self { err.errno.into() @@ -154,6 +156,7 @@ impl From<NmountError> for io::Error { } /// Result type of [`Nmount::nmount`]. +#[cfg(target_os = "freebsd")] pub type NmountResult = std::result::Result<(), NmountError>; /// Mount a FreeBSD file system. @@ -187,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(); /// ``` /// @@ -197,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. @@ -219,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, @@ -234,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. @@ -268,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 @@ -309,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<P: ?Sized + NixPath>(&mut self, name: &P) -> &mut Self - { + pub fn null_opt_owned<P: ?Sized + NixPath>( + &mut self, + name: &P, + ) -> &mut Self { self.push_nix_path(name); self.push_slice(&[], false); self @@ -328,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 @@ -355,8 +360,9 @@ impl<'a> Nmount<'a> { /// .str_opt_owned("fspath", mountpoint.to_str().unwrap()); /// ``` pub fn str_opt_owned<P1, P2>(&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); @@ -386,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) => { @@ -425,18 +429,24 @@ 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<P>(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 4c976dc..cf6a60b 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<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<()> { - +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, T, F>(p: Option<&P>, f: F) -> Result<T> - 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<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P } pub fn umount<P: ?Sized + NixPath>(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<P: ?Sized + NixPath>(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 e89c1a0..e98b49c 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 e3c0c43..33599bf 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::<libc::mq_attr>::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<MqdT> { +pub fn mq_open( + name: &CStr, + oflag: MQ_OFlag, + mode: Mode, + attr: Option<&MqAttr>, +) -> Result<MqdT> { 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<usize> { +pub fn mq_receive( + mqdes: &MqdT, + message: &mut [u8], + msg_prio: &mut u32, +) -> Result<usize> { 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<MqAttr> { let mut attr = mem::MaybeUninit::<libc::mq_attr>::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<MqAttr> { pub fn mq_setattr(mqd: &MqdT, newattr: &MqAttr) -> Result<MqAttr> { let mut attr = mem::MaybeUninit::<libc::mq_attr>::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<MqAttr> { 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<MqAttr> { /// Returns the old attributes pub fn mq_remove_nonblock(mqd: &MqdT) -> Result<MqAttr> { 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 045efad..b2423bc 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<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> { - 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 3004d24..6f227fe 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`. /// @@ -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<bool> { + 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<bool> { + 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() @@ -134,9 +154,11 @@ libc_bitflags! { /// ready. pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> { 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) @@ -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<PtyMaster> { - 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<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>(winsize: T, termios: U) -> Result<OpenptyResult> { +pub fn openpty< + 'a, + 'b, + T: Into<Option<&'a Winsize>>, + U: Into<Option<&'b Termios>>, +>( + winsize: T, + termios: U, +) -> Result<OpenptyResult> { use std::ptr; let mut slave = mem::MaybeUninit::<libc::c_int>::uninit(); @@ -267,17 +271,15 @@ pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios> ) } } - (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<Option<&'a Winsize>>, U: Into<Option<&'b Termios> ) } } - (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 e9a326e..d5b1233 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<dyn FnMut() -> isize>) -> i32, + callback + as extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32, ), ptr_aligned as *mut c_void, combined, @@ -142,25 +143,38 @@ 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; use crate::unistd::Pid; use crate::Result; + use std::mem; /// CpuSet represent a bit-mask of CPUs. /// CpuSets are used by sched_setaffinity and /// 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 { @@ -187,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(()) } } @@ -198,14 +214,21 @@ 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(()) } } /// Return the maximum number of CPU in CpuSet pub const fn count() -> usize { - 8 * mem::size_of::<libc::cpu_set_t>() + #[cfg(not(target_os = "freebsd"))] + let bytes = mem::size_of::<libc::cpu_set_t>(); + #[cfg(target_os = "freebsd")] + let bytes = mem::size_of::<libc::cpuset_t>(); + + 8 * bytes } } @@ -282,6 +305,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<usize> { + let res = unsafe { libc::sched_getcpu() }; + + Errno::result(res).map(|int| int as usize) + } } /// Explicitly yield the processor to other threads. diff --git a/src/sys/aio.rs b/src/sys/aio.rs index 6ff8846..e2ce19b 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<libc::aiocb> 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<libc::aiocb> 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<libc::aiocb> 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<libc::aiocb> 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<TimeSpec>, ) -> Result<()> { let p = list as *const [&dyn AsRef<libc::aiocb>] - 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::<libc::timespec>(), 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<libc::aiocb>>] - 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 8141ff5..58def2e 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<RawFd> { } #[inline] -pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result<()> - where T: Into<Option<&'a mut EpollEvent>> +pub fn epoll_ctl<'a, T>( + epfd: RawFd, + op: EpollOp, + fd: RawFd, + event: T, +) -> Result<()> +where + T: Into<Option<&'a mut EpollEvent>>, { 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<usize> { +pub fn epoll_wait( + epfd: RawFd, + events: &mut [EpollEvent], + timeout_ms: isize, +) -> Result<usize> { 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 0d0d23a..d8ad628 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<type_of_event_filter> } -#[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<RawFd> { 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<usize> { - +pub fn kevent( + kq: RawFd, + changelist: &[KEvent], + eventlist: &mut [KEvent], + timeout_ms: usize, +) -> Result<usize> { // 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<timespec>) -> Result<usize> { - +pub fn kevent_ts( + kq: RawFd, + changelist: &[KEvent], + eventlist: &mut [KEvent], + timeout_opt: Option<timespec>, +) -> Result<usize> { 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 c54f952..cd90672 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 b19dbe1..84356ec 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<OsString> + pub name: Option<OsString>, } 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<Inotify> { - 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<P: ?Sized + NixPath>(self, - path: &P, - mask: AddWatchFlags) - -> Result<WatchDescriptor> - { - let res = path.with_nix_path(|cstr| { - unsafe { - libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits()) - } + pub fn add_watch<P: ?Sized + NixPath>( + self, + path: &P, + mask: AddWatchFlags, + ) -> Result<WatchDescriptor> { + 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 642676b..ad9345e 100644 --- a/src/sys/memfd.rs +++ b/src/sys/memfd.rs @@ -1,8 +1,10 @@ //! Interfaces for managing memory-backed files. +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!( @@ -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<RawFd> { 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/mman.rs b/src/sys/mman.rs index 700e231..2bee091 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 std::os::unix::io::RawFd; +use libc::{self, c_int, c_void, off_t, size_t}; +use std::{os::unix::io::RawFd, num::NonZeroUsize}; -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,8 +416,20 @@ 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> { - let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset); +pub unsafe fn mmap( + addr: Option<NonZeroUsize>, + length: NonZeroUsize, + prot: ProtFlags, + flags: MapFlags, + 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); if ret == libc::MAP_FAILED { Err(Errno::last()) @@ -439,10 +451,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 +468,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 +497,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) } @@ -498,8 +520,9 @@ pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> /// # 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(ptr::null_mut(), 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) @@ -508,7 +531,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 +547,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 +592,8 @@ pub fn shm_open<P>( /// [`shm_unlink(3)`]: https://man7.org/linux/man-pages/man3/shm_unlink.3.html #[cfg(not(target_os = "android"))] pub fn shm_unlink<P: ?Sized + NixPath>(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/mod.rs b/src/sys/mod.rs index 979d623..2065059 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; diff --git a/src/sys/personality.rs b/src/sys/personality.rs index 9e285ae..f295a05 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<Persona> { - 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<Persona> { /// personality::set(pers | Persona::ADDR_NO_RANDOMIZE).unwrap(); /// ``` pub fn set(persona: Persona) -> Result<Persona> { - 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/pthread.rs b/src/sys/pthread.rs index fd81f3e..6bad03a 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<T>(thread: Pthread, signal: T) -> Result<()> where T: Into<Option<crate::sys::signal::Signal>> diff --git a/src/sys/ptrace/bsd.rs b/src/sys/ptrace/bsd.rs index c4cc740..ba267c6 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<T: Into<Option<Signal>>>(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<T: Into<Option<Signal>>>(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 1d9b241..9687e05 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<c_long> { +fn ptrace_peek( + request: Request, + pid: Pid, + addr: AddressType, + data: *mut c_void, +) -> Result<c_long> { 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<user_regs_struct> { ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid) @@ -203,16 +216,22 @@ pub fn getregs(pid: Pid) -> Result<user_regs_struct> { /// 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::<c_void>(), - ®s as *const _ as *const c_void) + libc::ptrace( + Request::PTRACE_SETREGS as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::<c_void>(), + ®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<T>(request: Request, pid: Pid) -> Result<T> { let mut data = mem::MaybeUninit::uninit(); let res = unsafe { - libc::ptrace(request as RequestType, - libc::pid_t::from(pid), - ptr::null_mut::<T>(), - data.as_mut_ptr() as *const _ as *const c_void) + libc::ptrace( + request as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::<T>(), + 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<c_long> { - 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<c_long> { + 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::<c_void>(), - options.bits() as *mut c_void) + libc::ptrace( + Request::PTRACE_SETOPTIONS as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::<c_void>(), + options.bits() as *mut c_void, + ) }; Errno::result(res).map(drop) } @@ -260,12 +294,14 @@ pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> { /// 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::<c_void>(), - sig as *const _ as *const c_void) + libc::ptrace( + Request::PTRACE_SETSIGINFO as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::<c_void>(), + 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<T: Into<Option<Signal>>>(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<T: Into<Option<Signal>>>(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<T: Into<Option<Signal>>>(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<T: Into<Option<Signal>>>(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<T: Into<Option<Signal>>>(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<T: Into<Option<Signal>>>(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<T: Into<Option<Signal>>>(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<T: Into<Option<Signal>>>(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<T: Into<Option<Signal>>>(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<c_long> { 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<c_long> { 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 782c304..2b121c0 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 f3b4c02..b3c44ca 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<u64> { - 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<u64> { - 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<u64> { - 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<u64> { - 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<u64> { - 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<u64> { - 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<u64> { - 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<u64> { - 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<P: ?Sized + NixPath>(cmd: QuotaCmd, special: Option<&P>, id: c_int, addr: *mut c_char) -> Result<()> { +fn quotactl<P: ?Sized + NixPath>( + 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<P: ?Sized + NixPath>(cmd: QuotaCmd, special: Option<&P>, id: c_int, } /// Turn on disk quotas for a block device. -pub fn quotactl_on<P: ?Sized + NixPath>(which: QuotaType, special: &P, format: QuotaFmt, quota_file: &P) -> Result<()> { +pub fn quotactl_on<P: ?Sized + NixPath>( + 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<P: ?Sized + NixPath>(which: QuotaType, special: &P) -> Result<()> { - quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which), Some(special), 0, ptr::null_mut()) +pub fn quotactl_off<P: ?Sized + NixPath>( + 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<P: ?Sized + NixPath>(which: QuotaType, special: Option<&P>) -> Result<()> { - quotactl(QuotaCmd(QuotaSubCmd::Q_SYNC, which), special, 0, ptr::null_mut()) +pub fn quotactl_sync<P: ?Sized + NixPath>( + 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<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int) -> Result<Dqblk> { +pub fn quotactl_get<P: ?Sized + NixPath>( + which: QuotaType, + special: &P, + id: c_int, +) -> Result<Dqblk> { 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<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int, dqblk: &Dqblk, fields: QuotaValidFlags) -> Result<()> { +pub fn quotactl_set<P: ?Sized + NixPath>( + 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 2a8009e..02d9816 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<Infallible> { - 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 e9a11d9..8927737 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 @@ -244,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, @@ -426,7 +431,8 @@ mod test { // thing away. Replace the assert with test::black_box once stabilized. assert_eq!(numbers[100..200].iter().sum::<i32>(), 30_100); - let usage = getrusage(UsageWho::RUSAGE_SELF).expect("Failed to call getrusage for SELF"); + let 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 ab4f68f..7a94cff 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<c_int> + timeout: T, +) -> Result<c_int> where N: Into<Option<c_int>>, R: Into<Option<&'a mut FdSet>>, @@ -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 2ebcdf4..fb293a4 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/signal.rs b/src/sys/signal.rs index 0da9c74..d3746e6 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) }; @@ -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/signalfd.rs b/src/sys/signalfd.rs index 166bb9d..095e590 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::<siginfo>(); /// 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<RawFd> { 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 ad917cd..8b23b10 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1,55 +1,61 @@ +#[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)) +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) } } @@ -75,11 +81,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 +144,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 +180,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 +197,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 +215,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 +248,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 +423,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 +751,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 +777,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 +800,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 +812,41 @@ impl<'a> UnixAddrKind<'a> { impl UnixAddr { /// Create a new sockaddr_un representing a filesystem path. pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> { - 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,27 +862,43 @@ 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)) } } + /// 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 { + 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(); + + 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. @@ -840,8 +910,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", @@ -882,6 +955,14 @@ 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) + } + /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)` #[inline] pub fn path_len(&self) -> usize { @@ -898,8 +979,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,31 +997,36 @@ 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<libc::socklen_t>) - -> Option<Self> where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option<libc::socklen_t>, + ) -> Option<Self> + 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; } } - 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(); 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 +1043,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::<libc::sockaddr_un>() as libc::socklen_t } } @@ -1037,8 +1126,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<libc::socklen_t>) - -> Option<Self> where Self: Sized; + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option<libc::socklen_t>, + ) -> Option<Self> + where + Self: Sized; /// Return the address family of this socket /// @@ -1058,11 +1151,9 @@ pub trait SockaddrLike: private::SockaddrLikePriv { fn family(&self) -> Option<AddressFamily> { // 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 +1192,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::<Self>() as libc::socklen_t } } @@ -1121,8 +1215,12 @@ impl SockaddrLike for () { ptr::null() } - unsafe fn from_raw(_: *const libc::sockaddr, _: Option<libc::socklen_t>) - -> Option<Self> where Self: Sized + unsafe fn from_raw( + _: *const libc::sockaddr, + _: Option<libc::socklen_t>, + ) -> Option<Self> + where + Self: Sized, { None } @@ -1156,20 +1254,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,15 +1284,19 @@ impl SockaddrIn { impl private::SockaddrLikePriv for SockaddrIn {} #[cfg(feature = "net")] impl SockaddrLike for SockaddrIn { - unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) - -> Option<Self> where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option<libc::socklen_t>, + ) -> Option<Self> + where + Self: Sized, { if let Some(l) = len { if l != mem::size_of::<libc::sockaddr_in>() as libc::socklen_t { 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 _))) @@ -1211,28 +1315,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<net::SocketAddrV4> 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::<libc::sockaddr_in>() 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 +1355,7 @@ impl From<SockaddrIn> 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,15 +1403,19 @@ impl SockaddrIn6 { impl private::SockaddrLikePriv for SockaddrIn6 {} #[cfg(feature = "net")] impl SockaddrLike for SockaddrIn6 { - unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) - -> Option<Self> where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option<libc::socklen_t>, + ) -> Option<Self> + where + Self: Sized, { if let Some(l) = len { if l != mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t { 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 _))) @@ -1317,8 +1434,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 +1447,25 @@ impl fmt::Display for SockaddrIn6 { #[cfg(feature = "net")] impl From<net::SocketAddrV6> 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::<libc::sockaddr_in6>() 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 +1477,7 @@ impl From<SockaddrIn6> 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 +1491,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 +1520,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 +1534,42 @@ 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<libc::socklen_t>) - -> Option<Self> where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + l: Option<libc::socklen_t>, + ) -> Option<Self> + 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::<libc::sockaddr_storage>() { + if ulen < offset_of!(libc::sockaddr, sa_data) + || ulen > mem::size_of::<libc::sockaddr_storage>() + { 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}) + #[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 { // If length is not available and addr is of a fixed-length type, @@ -1432,46 +1577,74 @@ 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, } } } + + #[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 { @@ -1481,15 +1654,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 +1669,128 @@ 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 { + /// 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::<libc::sockaddr_un>() { + 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::<libc::sockaddr_un>() { + 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} + 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 +1798,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 +1813,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 +1839,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), - _ => "<Address family unspecified>".fmt(f) + _ => "<Address family unspecified>".fmt(f), } } } @@ -1650,20 +1887,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 +1913,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 +1929,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 +1983,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 +1997,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 +2023,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 +2074,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 +2114,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<SockAddr> { + pub(crate) unsafe fn from_libc_sockaddr( + addr: *const libc::sockaddr, + ) -> Option<SockAddr> { if addr.is_null() { None } else { @@ -1870,40 +2124,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 +2189,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 +2217,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 +2225,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 +2272,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 +2289,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 +2321,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<libc::socklen_t>) - -> Option<Self> - { + unsafe fn from_raw( + addr: *const libc::sockaddr, + _len: Option<libc::socklen_t>, + ) -> Option<Self> { Self::from_libc_sockaddr(addr) } } @@ -2054,10 +2332,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,15 +2371,19 @@ pub mod netlink { impl private::SockaddrLikePriv for NetlinkAddr {} impl SockaddrLike for NetlinkAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) - -> Option<Self> where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option<libc::socklen_t>, + ) -> Option<Self> + where + Self: Sized, { if let Some(l) = len { if l != mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t { 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 _))) @@ -2124,11 +2406,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,15 +2419,20 @@ pub mod alg { impl private::SockaddrLikePriv for AlgAddr {} impl SockaddrLike for AlgAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, l: Option<libc::socklen_t>) - -> Option<Self> where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + l: Option<libc::socklen_t>, + ) -> Option<Self> + where + Self: Sized, { if let Some(l) = l { - if l != mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t { + if l != mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t + { 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 _))) @@ -2162,8 +2449,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 +2470,14 @@ pub mod alg { impl Hash for AlgAddr { fn hash<H: Hasher>(&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 +2486,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() + ) } } @@ -2244,7 +2557,7 @@ pub mod sys_control { /// /// # References /// - /// https://developer.apple.com/documentation/kernel/sockaddr_ctl + /// <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); @@ -2259,7 +2572,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 _))) @@ -2323,7 +2636,6 @@ pub mod sys_control { } } - #[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))] #[cfg_attr(docsrs, doc(cfg(all())))] mod datalink { @@ -2366,12 +2678,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 +2714,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 _))) @@ -2418,14 +2730,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! { @@ -2477,6 +2791,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 +2838,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 _))) @@ -2541,11 +2857,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 /// @@ -2558,15 +2874,19 @@ pub mod vsock { impl private::SockaddrLikePriv for VsockAddr {} impl SockaddrLike for VsockAddr { - unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) - -> Option<Self> where Self: Sized + unsafe fn from_raw( + addr: *const libc::sockaddr, + len: Option<libc::socklen_t>, + ) -> Option<Self> + where + Self: Sized, { if let Some(l) = len { if l != mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t { 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 _))) @@ -2582,8 +2902,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) } } @@ -2653,33 +2973,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, @@ -2687,67 +3013,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"), } } @@ -2766,27 +3100,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::<libc::sockaddr_dl>(); #[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::<libc::sockaddr_ll>(); - assert_eq!( LinkAddr::size() as usize, l); + assert_eq!(LinkAddr::size() as usize, l); } } @@ -2803,8 +3142,10 @@ mod tests { #[test] fn size() { - assert_eq!(mem::size_of::<libc::sockaddr_in>(), - SockaddrIn::size() as usize); + assert_eq!( + mem::size_of::<libc::sockaddr_in>(), + SockaddrIn::size() as usize + ); } } @@ -2821,8 +3162,47 @@ mod tests { #[test] fn size() { - assert_eq!(mem::size_of::<libc::sockaddr_in6>(), - SockaddrIn6::size() as usize); + assert_eq!( + mem::size_of::<libc::sockaddr_in6>(), + SockaddrIn6::size() as usize + ); + } + } + + 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 ua = UnixAddr::new_unnamed(); + 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()); } } @@ -2835,15 +3215,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::<libc::sockaddr_un>(), - UnixAddr::size() as usize); + assert_eq!( + mem::size_of::<libc::sockaddr_un>(), + UnixAddr::size() as usize + ); } } } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index ecbf30a..2d7159a 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::{TryFrom, 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}; @@ -121,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<i32> for SockType { + type Error = crate::Error; + + fn try_from(x: i32) -> Result<Self> { + 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. @@ -132,6 +136,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"))] @@ -245,7 +251,7 @@ libc_bitflags! { } } -libc_bitflags!{ +libc_bitflags! { /// Additional socket options pub struct SockFlag: c_int { /// Set non-blocking mode on the new socket @@ -280,20 +286,23 @@ 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 /// (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,8 +314,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), @@ -316,15 +327,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 @@ -340,6 +354,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)). @@ -354,6 +369,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; } } @@ -462,7 +478,7 @@ cfg_if! { } } -cfg_if!{ +cfg_if! { if #[cfg(any( target_os = "dragonfly", target_os = "freebsd", @@ -581,15 +597,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<S>, 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 { @@ -839,6 +860,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) { @@ -1459,31 +1482,13 @@ pub fn sendmsg<S>(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()) }; 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<S>, - 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 @@ -1508,51 +1513,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<Item=&'a SendMmsgData<'a, I, C, S>>, + data: &'a mut MultiHeaders<S>, + slices: XS, + // one address per group of slices + addrs: AS, + // shared across all the messages + cmsgs: C, flags: MsgFlags -) -> Result<Vec<usize>> +) -> crate::Result<MultiResults<'a, S>> where + XS: IntoIterator<Item = &'a I>, + AS: AsRef<[Option<S>]>, 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::<libc::mmsghdr>::with_capacity(reserve_items); - let mut cmsgs_buffers = Vec::<Vec<u8>>::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) } @@ -1563,134 +1583,347 @@ 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<S> { + // preallocated boxed slice of mmsghdr + items: Box<[libc::mmsghdr]>, + addresses: Box<[mem::MaybeUninit<S>]>, + // 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<Box<[u8]>>, + msg_controllen: usize, +} + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", +))] +impl<S> MultiHeaders<S> { + /// 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<Vec<u8>>) -> Self where - I: AsRef<[IoSliceMut<'a>]> + 'a, -{ - pub iov: I, - pub cmsg_buffer: Option<&'a mut Vec<u8>>, + 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::<Vec<_>>(); + + 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. +/// An extension of recvmsg that allows the caller to receive multiple messages from a socket using a single system call. /// -/// `iov` and `cmsg_buffer` should be constructed similarly to `recvmsg` +/// This has performance benefits for some applications. /// -/// Multiple allocations are performed +/// This method performs no allocations. /// -/// # Arguments -/// -/// * `fd`: Socket file descriptor -/// * `data`: Struct that implements `IntoIterator` with `RecvMmsgData` items -/// * `flags`: Optional flags passed directly to the operating system. -/// -/// # RecvMmsgData -/// -/// * `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. + +// 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", 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<Item=&'a mut RecvMmsgData<'a, I>, - IntoIter=impl ExactSizeIterator + Iterator<Item=&'a mut RecvMmsgData<'a, I>>>, + data: &'a mut MultiHeaders<S>, + slices: XS, flags: MsgFlags, - timeout: Option<crate::sys::time::TimeSpec> -) -> Result<Vec<RecvMsg<'a, S>>> - where - I: AsRef<[IoSliceMut<'a>]> + 'a, - S: Copy + SockaddrLike + 'a + mut timeout: Option<crate::sys::time::TimeSpec>, +) -> crate::Result<MultiResults<'a, S>> +where + XS: IntoIterator<Item = &'a I>, + I: AsRef<[IoSliceMut<'a>]> + 'a, { - let iter = data.into_iter(); + 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 num_messages = iter.len(); + let timeout_ptr = timeout + .as_mut() + .map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec); - let mut output: Vec<libc::mmsghdr> = Vec::with_capacity(num_messages); + let received = Errno::result(unsafe { + libc::recvmmsg( + fd, + data.items.as_mut_ptr(), + count as _, + flags.bits() as _, + timeout_ptr, + ) + })? as usize; - // 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(); + 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<S>, + 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>; - let results: Vec<_> = iter.enumerate().map(|(i, d)| { - let (msg_controllen, mhdr) = unsafe { - pack_mhdr_to_receive( - d.iov.as_ref(), - &mut d.cmsg_buffer, - addresses[i].as_mut_ptr(), + // The cast is not unnecessary on all platforms. + #[allow(clippy::unnecessary_cast)] + fn next(&mut self) -> Option<Self::Item> { + 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<Self::Item> { + 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, &mut d.cmsg_buffer) - }).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 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, cmsg_buffer))| { - unsafe { - read_mhdr( - mmsghdr.msg_hdr, - mmsghdr.msg_len as isize, - msg_controllen, - address, - cmsg_buffer - ) + let sbuf = (0..400).map(|i| i as u8).collect::<Vec<_>>(); + + let mut recv_buf = vec![0; 1024]; + + let mut recv_iovs = Vec::new(); + let mut pkt_iovs = Vec::new(); + + for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() { + pkt_iovs.push(IoSliceMut::new(chunk)); + if ix % 2 == 1 { + recv_iovs.push(pkt_iovs); + pkt_iovs = Vec::new(); } - }) - .collect()) -} + } + 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(any(qemu, target_arch = "aarch64")))] + let mut saw_time = false; + let mut recvd = 0; + for cmsg in rmsg.cmsgs() { + if let ControlMessageOwned::ScmTimestampsns(timestamps) = cmsg { + let ts = timestamps.system; + + let sys_time = + 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(any(qemu, target_arch = "aarch64")))] + { + saw_time = true; + } + } + } + + #[cfg(not(any(qemu, target_arch = "aarch64")))] + assert!(saw_time); -unsafe fn read_mhdr<'a, 'b, S>( + 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, - cmsg_buffer: &'a mut Option<&'b mut Vec<u8>> -) -> RecvMsg<'b, S> +) -> RecvMsg<'a, 'i, 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) @@ -1705,38 +1938,43 @@ unsafe fn read_mhdr<'a, 'b, S>( address: Some(address), flags: MsgFlags::from_bits_truncate(mhdr.msg_flags), mhdr, + iobufs: std::marker::PhantomData, } } -unsafe fn pack_mhdr_to_receive<'outer, 'inner, I, S>( - iov: I, - cmsg_buffer: &mut Option<&mut Vec<u8>>, +/// 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<S>( + iov_buffer: *const IoSliceMut, + iov_buffer_len: usize, + cmsg_buffer: *const u8, + cmsg_capacity: usize, address: *mut S, -) -> (usize, msghdr) +) -> msghdr where - I: AsRef<[IoSliceMut<'inner>]> + 'outer, - S: SockaddrLike + 'outer + S: SockaddrLike { - 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::<msghdr>::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::<msghdr>::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_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; + mhdr.assume_init() } fn pack_mhdr_to_send<'a, I, C, S>( @@ -1808,24 +2046,27 @@ 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<u8>>, - flags: MsgFlags) -> Result<RecvMsg<'a, S>> - where S: SockaddrLike + 'a + flags: MsgFlags) -> Result<RecvMsg<'a, 'inner, S>> + where S: SockaddrLike + 'a, + 'inner: 'outer { 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(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)?; - 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 @@ -1836,7 +2077,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<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result<RawFd> { +pub fn socket<T: Into<Option<SockProtocol>>>( + domain: AddressFamily, + ty: SockType, + flags: SockFlag, + protocol: T, +) -> Result<RawFd> { let protocol = match protocol.into() { None => 0, Some(p) => p as c_int, @@ -1856,8 +2102,12 @@ pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType /// Create a pair of connected sockets /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html) -pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, protocol: T, - flags: SockFlag) -> Result<(RawFd, RawFd)> { +pub fn socketpair<T: Into<Option<SockProtocol>>>( + domain: AddressFamily, + ty: SockType, + protocol: T, + flags: SockFlag, +) -> Result<(RawFd, RawFd)> { let protocol = match protocol.into() { None => 0, Some(p) => p as c_int, @@ -1871,7 +2121,9 @@ pub fn socketpair<T: Into<Option<SockProtocol>>>(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])) @@ -1890,9 +2142,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) } @@ -1909,24 +2159,28 @@ pub fn accept(sockfd: RawFd) -> Result<RawFd> { /// 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<RawFd> { - 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) } @@ -1935,9 +2189,7 @@ pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> { /// /// [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) } @@ -1952,7 +2204,8 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> { 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) } @@ -1963,9 +2216,10 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> { /// address of the sender. /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html) -pub fn recvfrom<T:SockaddrLike>(sockfd: RawFd, buf: &mut [u8]) - -> Result<(usize, Option<T>)> -{ +pub fn recvfrom<T: SockaddrLike>( + sockfd: RawFd, + buf: &mut [u8], +) -> Result<(usize, Option<T>)> { unsafe { let mut addr = mem::MaybeUninit::<T>::uninit(); let mut len = mem::size_of_val(&addr) as socklen_t; @@ -1976,11 +2230,15 @@ pub fn recvfrom<T:SockaddrLike>(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), + ), )) } } @@ -1988,7 +2246,12 @@ pub fn recvfrom<T:SockaddrLike>(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<usize> { +pub fn sendto( + fd: RawFd, + buf: &[u8], + addr: &dyn SockaddrLike, + flags: MsgFlags, +) -> Result<usize> { let ret = unsafe { libc::sendto( fd, @@ -1996,7 +2259,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(), ) }; @@ -2008,7 +2271,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<usize> { 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) @@ -2021,7 +2289,7 @@ pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> { */ /// 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. @@ -2029,7 +2297,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. @@ -2060,7 +2328,11 @@ pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> { /// let res = setsockopt(fd, KeepAlive, &true); /// assert!(res.is_ok()); /// ``` -pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> { +pub fn setsockopt<O: SetSockOpt>( + fd: RawFd, + opt: O, + val: &O::Val, +) -> Result<()> { opt.set(fd, val) } @@ -2075,13 +2347,12 @@ pub fn getpeername<T: SockaddrLike>(fd: RawFd) -> Result<T> { 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) } } @@ -2096,13 +2367,12 @@ pub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> { 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) } } @@ -2121,8 +2391,8 @@ pub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> { #[allow(deprecated)] pub fn sockaddr_storage_to_addr( addr: &sockaddr_storage, - len: usize) -> Result<SockAddr> { - + len: usize, +) -> Result<SockAddr> { assert!(len <= mem::size_of::<sockaddr_storage>()); if len < mem::size_of_val(&addr.ss_family) { return Err(Errno::ENOTCONN); @@ -2131,7 +2401,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::<sockaddr_in>()); + assert!(len >= mem::size_of::<sockaddr_in>()); let sin = unsafe { *(addr as *const sockaddr_storage as *const sockaddr_in) }; @@ -2139,19 +2409,15 @@ pub fn sockaddr_storage_to_addr( } #[cfg(feature = "net")] libc::AF_INET6 => { - assert!(len as usize >= mem::size_of::<sockaddr_in6>()); - let sin6 = unsafe { - *(addr as *const _ as *const sockaddr_in6) - }; + assert!(len >= mem::size_of::<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 => { @@ -2160,40 +2426,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. @@ -2212,9 +2469,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) diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 1cbb223..06e9ee4 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -1,18 +1,18 @@ //! 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::{ + convert::TryFrom, + 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 +51,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 +96,23 @@ 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()) + match <$ty>::try_from(getter.assume_init()) { + Err(_) => Err(Errno::EINVAL), + Ok(r) => Ok(r) + } } } } - } + }; } /// Helper to generate the sockopt accessors. See @@ -248,13 +259,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 +285,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 +360,180 @@ 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(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!( #[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 +551,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 +585,194 @@ 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, + GetStruct<i32> +); 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 +785,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 +805,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 +823,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 +841,146 @@ 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 = "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 /// 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 +989,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 +1010,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 +1036,21 @@ impl<T> Default for AlgSetKey<T> { } #[cfg(any(target_os = "android", target_os = "linux"))] -impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone { +impl<T> SetSockOpt for AlgSetKey<T> +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 +1111,11 @@ impl<T> Get<T> for GetStruct<T> { } unsafe fn assume_init(self) -> T { - assert_eq!(self.len as usize, mem::size_of::<T>(), "invalid getsockopt implementation"); + assert_eq!( + self.len as usize, + mem::size_of::<T>(), + "invalid getsockopt implementation" + ); self.val.assume_init() } } @@ -804,7 +1162,11 @@ impl Get<bool> for GetBool { } unsafe fn assume_init(self) -> bool { - assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation"); + assert_eq!( + self.len as usize, + mem::size_of::<c_int>(), + "invalid getsockopt implementation" + ); self.val.assume_init() != 0 } } @@ -816,7 +1178,9 @@ 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 { @@ -851,7 +1215,11 @@ impl Get<u8> for GetU8 { } unsafe fn assume_init(self) -> u8 { - assert_eq!(self.len as usize, mem::size_of::<u8>(), "invalid getsockopt implementation"); + assert_eq!( + self.len as usize, + mem::size_of::<u8>(), + "invalid getsockopt implementation" + ); self.val.assume_init() } } @@ -863,7 +1231,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 { @@ -898,7 +1266,11 @@ impl Get<usize> for GetUsize { } unsafe fn assume_init(self) -> usize { - assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation"); + assert_eq!( + self.len as usize, + mem::size_of::<c_int>(), + "invalid getsockopt implementation" + ); self.val.assume_init() as usize } } @@ -958,7 +1330,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 +1344,6 @@ impl<'a> Set<'a, OsString> for SetOsString<'a> { } } - #[cfg(test)] mod test { #[cfg(any(target_os = "android", target_os = "linux"))] @@ -978,7 +1351,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 +1369,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 +1387,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 +1419,4 @@ mod test { assert!(s_listening2); close(s).unwrap(); } - } diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 8b7627d..78203bf 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. @@ -33,25 +33,39 @@ 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; } } -#[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 +170,12 @@ libc_bitflags! { } /// Create a special or ordinary file, by pathname. -pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> { +pub fn mknod<P: ?Sized + NixPath>( + 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 +184,12 @@ pub fn mknod<P: ?Sized + NixPath>(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<P: ?Sized + NixPath>( dirfd: RawFd, @@ -175,7 +199,12 @@ pub fn mknodat<P: ?Sized + NixPath>( 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 +213,22 @@ pub fn mknodat<P: ?Sized + NixPath>( #[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 +238,24 @@ pub fn umask(mode: Mode) -> Mode { pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> { 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<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> { 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<FileStat> { @@ -241,20 +264,29 @@ pub fn fstat(fd: RawFd) -> Result<FileStat> { 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<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> { +pub fn fstatat<P: ?Sized + NixPath>( + dirfd: RawFd, + pathname: &P, + f: AtFlags, +) -> Result<FileStat> { 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 +331,10 @@ pub fn fchmodat<P: ?Sized + NixPath>( 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 +357,11 @@ pub fn fchmodat<P: ?Sized + NixPath>( /// # References /// /// [utimes(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). -pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> { +pub fn utimes<P: ?Sized + NixPath>( + 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 +380,20 @@ pub fn utimes<P: ?Sized + NixPath>(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<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> { +pub fn lutimes<P: ?Sized + NixPath>( + 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 +446,12 @@ pub fn utimensat<P: ?Sized + NixPath>( 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 +467,13 @@ pub fn utimensat<P: ?Sized + NixPath>( #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] -pub fn mkdirat<P: ?Sized + NixPath>(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<P: ?Sized + NixPath>( + 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 e8c06e4..9be8ca6 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -1,13 +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 crate::{NixPath, Result, errno::Errno}; +use cfg_if::cfg_if; + +#[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")] @@ -18,10 +33,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; @@ -33,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. @@ -42,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); @@ -51,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); @@ -84,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); @@ -150,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); @@ -201,11 +281,21 @@ 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") +))] +#[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 @@ -260,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 @@ -320,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 @@ -347,6 +451,32 @@ 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())))] @@ -376,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 @@ -395,7 +532,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 { @@ -410,24 +549,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 } @@ -437,7 +561,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 { @@ -452,29 +578,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 @@ -495,24 +612,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 } @@ -522,7 +624,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 { @@ -537,33 +641,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 { @@ -585,24 +676,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 } @@ -614,16 +690,27 @@ 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() } } @@ -637,8 +724,10 @@ impl Debug for Statfs { /// `path` - Path to any file within the file system to describe pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> { unsafe { - let mut stat = mem::MaybeUninit::<libc::statfs>::uninit(); - let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), stat.as_mut_ptr()))?; + let mut stat = mem::MaybeUninit::<type_of_statfs>::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())) } } @@ -653,8 +742,8 @@ pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> { /// `fd` - File descriptor of any open file within the file system to describe pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> { unsafe { - let mut stat = mem::MaybeUninit::<libc::statfs>::uninit(); - Errno::result(libc::fstatfs(fd.as_raw_fd(), stat.as_mut_ptr())) + let mut stat = mem::MaybeUninit::<type_of_statfs>::uninit(); + Errno::result(LIBC_FSTATFS(fd.as_raw_fd(), stat.as_mut_ptr())) .map(|_| Statfs(stat.assume_init())) } } @@ -702,6 +791,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); @@ -749,6 +840,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/statvfs.rs b/src/sys/statvfs.rs index 38b1fdc..8de369f 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<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> { unsafe { Errno::clear(); let mut stat = mem::MaybeUninit::<libc::statvfs>::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<T: AsRawFd>(fd: &T) -> Result<Statvfs> { #[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/sysinfo.rs b/src/sys/sysinfo.rs index 96f0433..e8aa00b 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 c5b27d2..fba2cd8 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; @@ -181,6 +245,12 @@ 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 +266,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 +292,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 +312,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 +332,12 @@ impl From<libc::termios> 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, } } } @@ -248,7 +348,7 @@ impl From<Termios> 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 @@ -363,12 +463,14 @@ libc_enum!{ impl TryFrom<libc::speed_t> } -#[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<BaudRate> for u32 { fn from(b: BaudRate) -> u32 { b as u32 @@ -382,7 +484,6 @@ impl From<BaudRate> for u8 { } } - // TODO: Add TCSASOFT, which will require treating this as a bitfield. libc_enum! { /// Specify when a port configuration change should occur. @@ -499,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; @@ -883,7 +989,7 @@ libc_bitflags! { } } -cfg_if!{ +cfg_if! { if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", @@ -894,6 +1000,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 } @@ -903,6 +1011,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 } @@ -1051,7 +1161,10 @@ pub fn tcgetattr(fd: RawFd) -> Result<Termios> { /// *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/time.rs b/src/sys/time.rs index 0cac7e8..0042c45 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::<timespec>()]) } +} + #[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,20 +290,22 @@ 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. + #[allow(clippy::unnecessary_cast)] fn num_seconds(&self) -> i64 { if self.tv_sec() < 0 && self.tv_nsec() > 0 { (self.tv_sec() + 1) as i64 @@ -319,9 +319,11 @@ impl TimeValLike for TimeSpec { } fn num_microseconds(&self) -> i64 { - self.num_nanoseconds() / 1_000_000_000 + 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(); @@ -333,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 { @@ -356,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 { @@ -549,6 +551,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 +565,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/timer.rs b/src/sys/timer.rs index 45ce0e5..e1a3405 100644 --- a/src/sys/timer.rs +++ b/src/sys/timer.rs @@ -70,9 +70,10 @@ 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<Self> { - let mut timer_id: mem::MaybeUninit<libc::timer_t> = mem::MaybeUninit::uninit(); + let mut timer_id: mem::MaybeUninit<libc::timer_t> = + mem::MaybeUninit::uninit(); Errno::result(unsafe { libc::timer_create( clockid.as_raw(), @@ -123,8 +124,12 @@ 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<()> { + #[doc(alias("timer_settime"))] + pub fn set( + &mut self, + expiration: Expiration, + flags: TimerSetTimeFlags, + ) -> Result<()> { let timerspec: TimerSpec = expiration.into(); Errno::result(unsafe { libc::timer_settime( @@ -138,10 +143,13 @@ 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<Option<Expiration>> { 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 @@ -161,7 +169,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 4286065..a35fc92 100644 --- a/src/sys/timerfd.rs +++ b/src/sys/timerfd.rs @@ -92,10 +92,12 @@ 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<Self> { - 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. @@ -134,8 +136,12 @@ 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<()> { + #[doc(alias("timerfd_settime"))] + pub fn set( + &self, + expiration: Expiration, + flags: TimerSetTimeFlags, + ) -> Result<()> { let timerspec: TimerSpec = expiration.into(); Errno::result(unsafe { libc::timerfd_settime( @@ -149,10 +155,13 @@ 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<Option<Expiration>> { 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 @@ -166,7 +175,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/sys/uio.rs b/src/sys/uio.rs index 1908973..b31c306 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<usize> { // 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<usize> { /// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html) pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> { // 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<usize> { /// 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<usize> { - +pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result<usize> { #[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<usize> { +pub fn preadv( + fd: RawFd, + iov: &mut [IoSliceMut<'_>], + offset: off_t, +) -> Result<usize> { #[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<usize> { 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<usize> { /// /// See also [pread(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html) // TODO: move to unistd -pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{ +pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize> { let res = unsafe { - libc::pread(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t, - 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<T> IoVec<T> { use std::slice; unsafe { - slice::from_raw_parts( - self.0.iov_base as *const u8, - self.0.iov_len as usize) + slice::from_raw_parts(self.0.iov_base as *const u8, self.0.iov_len) } } } @@ -161,30 +182,30 @@ impl<T> IoVec<T> { #[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 5bd3a53..b48ed9f 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)] @@ -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 @@ -47,10 +53,12 @@ pub fn uname() -> Result<UtsName> { } 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 5fb2075..b6524e8 100644 --- a/src/sys/wait.rs +++ b/src/sys/wait.rs @@ -135,7 +135,9 @@ impl WaitStatus { pub fn pid(&self) -> Option<Pid> { 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<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Result<WaitStatus> { +pub fn waitpid<P: Into<Option<Pid>>>( + pid: P, + options: Option<WaitPidFlag>, +) -> Result<WaitStatus> { use self::WaitStatus::*; let mut status: i32 = 0; diff --git a/src/time.rs b/src/time.rs index 6a385b9..2e03c46 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<TimeSpec> { let mut c_time: MaybeUninit<libc::timespec> = 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<TimeSpec> { /// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)). pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> { let mut c_time: MaybeUninit<libc::timespec> = 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<TimeSpec> { )))] #[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<ClockId> { let mut clk_id: MaybeUninit<libc::clockid_t> = 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 f2338bd..b2a39f7 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::<libc::ucontext_t>::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) } } } diff --git a/src/unistd.rs b/src/unistd.rs index 8cdb54b..ca07b34 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() } @@ -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 @@ -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) @@ -2196,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 <newline>. + /// trailing newline. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] #[cfg_attr(docsrs, doc(cfg(all())))] LINE_MAX = libc::_SC_LINE_MAX, @@ -2910,9 +2921,8 @@ pub fn access<P: ?Sized + NixPath>(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<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: AccessFlags, flags: AtFlags) -> Result<()> { let res = path.with_nix_path(|cstr| { unsafe { @@ -2921,6 +2931,27 @@ pub fn faccessat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, 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<P: ?Sized + NixPath>(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! { @@ -3143,7 +3174,10 @@ impl User { /// assert_eq!(res.name, "root"); /// ``` pub fn from_name(name: &str) -> Result<Option<Self>> { - 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 +3302,10 @@ impl Group { /// assert!(res.name == "root"); /// ``` pub fn from_name(name: &str) -> Result<Option<Self>> { - 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) } }) diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index 6a36f3e..84086f8 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/sys/test_ioctl.rs b/test/sys/test_ioctl.rs index 7a603c5..40f60cf 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_mman.rs b/test/sys/test_mman.rs index 75cbf6c..e748427 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( - std::ptr::null_mut(), - 1, + None, + 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( - std::ptr::null_mut(), - ONE_K, + None, + 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( - std::ptr::null_mut(), - 10 * ONE_K, + None, + 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, diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index b4ca279..5adc77e 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(); @@ -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) +#[cfg(any(target_os = "android", target_os = "linux"))] +#[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); + + assert!(addr.as_abstract().is_none()); +} + #[test] pub fn test_getsockname() { use nix::sys::socket::bind; @@ -501,31 +517,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 +593,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::<SockaddrIn>::preallocate(msgs.len(), None); let res: Vec<RecvMsg<SockaddrIn>> = - 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 +669,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::<SockaddrIn>::preallocate( + NUM_MESSAGES_SENT + 2, + None, + ); - let res: Vec<RecvMsg<SockaddrIn>> = - recvmmsg(rsock, &mut msgs, MsgFlags::MSG_DONTWAIT, None) - .expect("recvmmsg"); + let res: Vec<RecvMsg<SockaddrIn>> = 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() { @@ -1481,7 +1500,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { // 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}; @@ -1524,6 +1543,59 @@ pub fn test_unixdomain() { assert_eq!(&buf[..], b"hello"); } +// 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}; + 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()); + + 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] @@ -2205,14 +2277,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<RecvMsg<()>> = - 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"), diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 2ddbf77..34bef94 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. @@ -237,6 +264,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() { let fd4 = socket( @@ -327,3 +381,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); +} diff --git a/test/sys/test_stat.rs b/test/sys/test_stat.rs index 2f26e78..426b4b6 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/sys/test_timerfd.rs b/test/sys/test_timerfd.rs index 927cc70..08e2921 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()); } diff --git a/test/test.rs b/test/test.rs index f725ef9..6b42aad 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; diff --git a/test/test_dir.rs b/test/test_dir.rs index f662992..2af4aa5 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 f4adee2..e51044a 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), @@ -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(); @@ -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")); diff --git a/test/test_kmod/mod.rs b/test/test_kmod/mod.rs index 5ebc242..6f9aaa8 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_mount.rs b/test/test_mount.rs index febcadf..2fd612e 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() diff --git a/test/test_sched.rs b/test/test_sched.rs index ebf346d..c52616b 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(); } diff --git a/test/test_unistd.rs b/test/test_unistd.rs index eee1010..9e20f97 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 = @@ -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"); +} |