Upgrade nix to 0.28.0 am: 33265a2e3a am: 716864b0c3

Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/nix/+/3032729

Change-Id: I59e318c690556d3c1f62347e7b96d8d2ca096d2c
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 02451fb..dca7eba 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "996db47d542ae20f09eb344b9fcb88c40ae38e3d"
+    "sha1": "21ab06ef23de214174ddb039be5b5f08750d19e6"
   },
   "path_in_vcs": ""
 }
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index ddbca61..b6beb09 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,5 +1,6 @@
 // This file is generated by cargo_embargo.
-// Do not modify this file as changes will be overridden on upgrade.
+// Do not modify this file as most changes will be overridden on upgrade.
+// Content before the first "rust_*" or "genrule" module is preserved.
 
 package {
     default_applicable_licenses: ["external_rust_crates_nix_license"],
@@ -26,7 +27,7 @@
     host_supported: true,
     crate_name: "nix",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.27.1",
+    cargo_pkg_version: "0.28.0",
     srcs: ["src/lib.rs"],
     edition: "2021",
     features: [
@@ -61,4 +62,20 @@
     product_available: true,
     vendor_available: true,
     min_sdk_version: "29",
+    // Manually translated build.rs cfg aliases.
+    target: {
+        host_linux: {
+            cfgs: [
+                "linux",
+                "linux_android",
+            ],
+        },
+        android: {
+            cfgs: [
+                "android",
+                "linux_android",
+            ],
+        },
+    },
+
 }
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3a171af..37e4ab2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,205 @@
-# Change Log
-
 All notable changes to this project will be documented in this file.
 This project adheres to [Semantic Versioning](https://semver.org/).
 
+# Change Log
+
+## [0.28.0] - 2024-02-24
+
+
+### Added
+
+- Added `mkdtemp` wrapper ([#1297](https://github.com/nix-rust/nix/pull/1297))
+- Add associated constants `UTIME_OMIT` `UTIME_NOW` for `TimeSpec`
+  ([#1879](https://github.com/nix-rust/nix/pull/1879))
+- Added `EventFd` type. ([#1945](https://github.com/nix-rust/nix/pull/1945))
+- - Added `impl From<Signal> for SigSet`.
+  - Added `impl std::ops::BitOr for SigSet`.
+  - Added `impl std::ops::BitOr for Signal`.
+  - Added `impl std::ops::BitOr<Signal> for SigSet`
+
+  ([#1959](https://github.com/nix-rust/nix/pull/1959))
+- Added `TlsGetRecordType` control message type and corresponding enum for
+  linux ([#2065](https://github.com/nix-rust/nix/pull/2065))
+- Added `Ipv6HopLimit` to `::nix::sys::socket::ControlMessage` for Linux,
+  MacOS, FreeBSD, DragonflyBSD, Android, iOS and Haiku.
+  ([#2074](https://github.com/nix-rust/nix/pull/2074))
+- Added `Icmp` and `IcmpV6` to `SockProtocol`
+  ([#2103](https://github.com/nix-rust/nix/pull/2103))
+- Added rfork support for FreeBSD in `unistd`
+  ([#2121](https://github.com/nix-rust/nix/pull/2121))
+- Added `MapFlags::map_hugetlb_with_size_log2` method for Linux targets
+  ([#2125](https://github.com/nix-rust/nix/pull/2125))
+- Added `mmap_anonymous` function
+  ([#2127](https://github.com/nix-rust/nix/pull/2127))
+- Added `mips32r6` and `mips64r6` support for signal, ioctl and ptrace
+  ([#2138](https://github.com/nix-rust/nix/pull/2138))
+- Added `F_GETPATH` FcntlFlags entry on Apple/NetBSD/DragonflyBSD for
+  `::nix::fcntl`. ([#2142](https://github.com/nix-rust/nix/pull/2142))
+- Added `F_KINFO` FcntlFlags entry on FreeBSD for `::nix::fcntl`.
+  ([#2152](https://github.com/nix-rust/nix/pull/2152))
+- Added `F_GETPATH_NOFIRMLINK` and `F_BARRIERFSYNC` FcntlFlags entry
+  on Apple for `::nix::fcntl`.
+  ([#2155](https://github.com/nix-rust/nix/pull/2155))
+- Added newtype `Flock` to automatically unlock a held flock upon drop.
+  Added `Flockable` trait to represent valid types for `Flock`.
+  ([#2170](https://github.com/nix-rust/nix/pull/2170))
+- Added `SetSockOpt` impls to enable Linux Kernel TLS on a TCP socket and to
+  import TLS parameters. ([#2175](https://github.com/nix-rust/nix/pull/2175))
+- - Added the `::nix::sys::socket::SocketTimestamp` enum for configuring the
+  `TsClock` (a.k.a `SO_TS_CLOCK`) sockopt
+  - Added FreeBSD's `ScmRealtime` and `ScmMonotonic` as new options in
+  `::nix::sys::socket::ControlMessageOwned`
+
+  ([#2187](https://github.com/nix-rust/nix/pull/2187))
+- Added new fanotify API: wrappers for `fanotify_init` and `fanotify_mark`
+  ([#2194](https://github.com/nix-rust/nix/pull/2194))
+- Added `SpecialCharacterindices` support for haiku.
+  ([#2195](https://github.com/nix-rust/nix/pull/2195))
+- Added `sys::sendfile` support for solaris/illumos.
+  ([#2198](https://github.com/nix-rust/nix/pull/2198))
+- impl Display for InterfaceFlags
+  ([#2206](https://github.com/nix-rust/nix/pull/2206))
+- Added `sendfilev` in sys::sendfile for solarish
+  ([#2207](https://github.com/nix-rust/nix/pull/2207))
+- Added `fctrl::SealFlag::F_SEAL_FUTURE_WRITE`
+  ([#2213](https://github.com/nix-rust/nix/pull/2213))
+- Added `Ipv6MulticastHops` as socket option to set and read.
+  ([#2234](https://github.com/nix-rust/nix/pull/2234))
+- Enable `ControlMessageOwned::Ipv4RecvIf` and
+  `ControlMessageOwned::Ipv4RecvDstAddr` for DragonFlyBSD
+  ([#2240](https://github.com/nix-rust/nix/pull/2240))
+- `ClockId::set_time()` and `time::clock_settime()` are now enabled on macOS
+  ([#2241](https://github.com/nix-rust/nix/pull/2241))
+- Added `IpBindAddressNoPort` sockopt to support `IP_BIND_ADDRESS_NO_PORT`
+  available on linux. ([#2244](https://github.com/nix-rust/nix/pull/2244))
+- Enable `MapFlags::map_hugetlb_with_size_log2` method for Android/Fuchsia
+  ([#2245](https://github.com/nix-rust/nix/pull/2245))
+- Added `TcpFastOpenConnect` sockopt to support `TCP_FASTOPEN_CONNECT`
+  available on linux. ([#2247](https://github.com/nix-rust/nix/pull/2247))
+- Add `reboot(2)` for OpenBSD/NetBSD
+  ([#2251](https://github.com/nix-rust/nix/pull/2251))
+- Added new `MemFdCreateFlag` constants to `sys::memfd` on Linux and Android
+  related to hugetlbfs support.
+  ([#2252](https://github.com/nix-rust/nix/pull/2252))
+- Expose the inner fd of `Kqueue` through:
+
+  * impl AsFd for Kqueue
+  * impl From\<Kqueue\> for OwnedFd
+
+  ([#2258](https://github.com/nix-rust/nix/pull/2258))
+- Added `sys::eventfd` support on FreeBSD
+  ([#2259](https://github.com/nix-rust/nix/pull/2259))
+- Added `MmapFlags::MAP_FIXED` constant in `sys::mman` for netbsd and openbsd
+  ([#2260](https://github.com/nix-rust/nix/pull/2260))
+- Added the `SO_LISTENQLIMIT` sockopt.
+  ([#2263](https://github.com/nix-rust/nix/pull/2263))
+- Enable the `AT_EMPTY_PATH` flag for the `fchownat()` function
+  ([#2267](https://github.com/nix-rust/nix/pull/2267))
+- Add `AtFlags::AT_EMPTY_PATH` for FreeBSD and Hurd
+  ([#2270](https://github.com/nix-rust/nix/pull/2270))
+- Enable `OFlag::O_DIRECTORY for Solarish
+  ([#2275](https://github.com/nix-rust/nix/pull/2275))
+- Added the `Backlog` wrapper type for the `listen` call.
+  ([#2276](https://github.com/nix-rust/nix/pull/2276))
+- Add `clock_nanosleep()` ([#2277](https://github.com/nix-rust/nix/pull/2277))
+- Enabled `O_DIRECT` in `fcntl::OFlags` for solarish
+  ([#2278](https://github.com/nix-rust/nix/pull/2278))
+- Added a new API sigsuspend.
+  ([#2279](https://github.com/nix-rust/nix/pull/2279))
+- - Added `errno::Errno::set` function
+  - Added `errno::Errno::set_raw` function
+  - Added `errno::Errno::last_raw` function
+  - Added `errno::Errno::from_raw` function
+
+  ([#2283](https://github.com/nix-rust/nix/pull/2283))
+- Enable the `AT_EMPTY_PATH` flag for the `linkat()` function
+  ([#2284](https://github.com/nix-rust/nix/pull/2284))
+- Enable unistd::{sync, syncfs} for Android
+  ([#2296](https://github.com/nix-rust/nix/pull/2296))
+
+### Changed
+
+- `poll` now takes `PollTimeout` replacing `libc::c_int`.
+  ([#1876](https://github.com/nix-rust/nix/pull/1876))
+- Deprecated `sys::eventfd::eventfd`.
+  ([#1945](https://github.com/nix-rust/nix/pull/1945))
+- `mmap`, `mmap_anonymous`, `munmap`, `mremap`, `madvise`, `msync`, `mprotect`,
+  `munlock` and `mlock` updated to use `NonNull`.
+  ([#2000](https://github.com/nix-rust/nix/pull/2000))
+- `mmap` function now accepts `F` instead of `Option<F>`
+  ([#2127](https://github.com/nix-rust/nix/pull/2127))
+- `PollFd::new` now takes a `BorrowedFd` argument, with relaxed lifetime
+    requirements relative to the previous version.
+  ([#2134](https://github.com/nix-rust/nix/pull/2134))
+- `FdSet::{insert, remove, contains}` now take `BorrowedFd` arguments, and have
+  relaxed lifetime requirements relative to 0.27.1.
+  ([#2136](https://github.com/nix-rust/nix/pull/2136))
+- The following APIs now take an implementation of `AsFd` rather than a
+    `RawFd`:
+
+    - `unistd::tcgetpgrp`
+    - `unistd::tcsetpgrp`
+    - `unistd::fpathconf`
+    - `unistd::ttyname`
+    - `unistd::getpeereid` ([#2137](https://github.com/nix-rust/nix/pull/2137))
+- Changed `openat()` and `Dir::openat()`, now take optional `dirfd`s
+  ([#2139](https://github.com/nix-rust/nix/pull/2139))
+- The MSRV is now 1.69 ([#2144](https://github.com/nix-rust/nix/pull/2144))
+- Changed function `SockaddrIn::ip()` to return `net::Ipv4Addr` and refactored
+  `SocketAddrV6::ip()` to be `const`
+  ([#2151](https://github.com/nix-rust/nix/pull/2151))
+- The following APIs now take optional `dirfd`s:
+
+  - `readlinkat()`
+  - `fstatat()`
+  - `mknodat()`
+  - `mkdirat()`
+  - `execveat()`
+
+  ([#2157](https://github.com/nix-rust/nix/pull/2157))
+- `Epoll::wait` now takes `EpollTimeout` replacing `isize`.
+  ([#2202](https://github.com/nix-rust/nix/pull/2202))
+- - Deprecated `errno::errno()` function (use `Errno::last_raw()`)
+  - Deprecated `errno::from_i32()` function (use `Errno::from_raw()`)
+  - Deprecated `errno::Errno::from_i32()` function (use `Errno::from_raw()`)
+
+  ([#2283](https://github.com/nix-rust/nix/pull/2283))
+
+### Fixed
+
+- Fix `SigSet` incorrect implementation of `Eq`, `PartialEq` and `Hash`
+  ([#1946](https://github.com/nix-rust/nix/pull/1946))
+- Fixed `::sys::socket::sockopt::IpMulticastTtl` by fixing the value of optlen
+  passed to `libc::setsockopt` and added tests.
+  ([#2072](https://github.com/nix-rust/nix/pull/2072))
+- Fixed the function signature of `recvmmsg`, potentially causing UB
+  ([#2119](https://github.com/nix-rust/nix/pull/2119))
+- Fix `SignalFd::set_mask`.  In 0.27.0 it would actually close the file
+  descriptor. ([#2141](https://github.com/nix-rust/nix/pull/2141))
+- Fixed UnixAddr::new for haiku, it did not record the `sun_len` value as
+  needed.
+  Fixed `sys::socket::addr::from_raw_parts` and
+  `sys::socket::Sockaddrlike::len` build for solaris.
+  ([#2242](https://github.com/nix-rust/nix/pull/2242))
+- Fixed solaris build globally.
+  ([#2248](https://github.com/nix-rust/nix/pull/2248))
+- Changed the `dup3` wrapper to perform a real call to `dup3` instead of
+  emulating it via `dup2` and `fcntl` to get rid of race condition
+  ([#2268](https://github.com/nix-rust/nix/pull/2268))
+- Fixed `::unistd::Group::members` using read_unaligned to avoid crash on
+  misaligned pointers ([#2311](https://github.com/nix-rust/nix/pull/2311))
+
+### Removed
+
+- The `FchownatFlags` type has been deprecated, please use `AtFlags` instead.
+  ([#2267](https://github.com/nix-rust/nix/pull/2267))
+- Removed the `dup3` wrapper on macOS, which was emulated via `dup2` and
+  `fcntl` and could cause a race condition. The `dup3` system call is not
+  supported on macOS. ([#2268](https://github.com/nix-rust/nix/pull/2268))
+- The `LinkatFlags` type has been deprecated, please use `AtFlags` instead.
+  ([#2284](https://github.com/nix-rust/nix/pull/2284))
+
+
 ## [0.27.1] - 2023-08-28
 
 ### Fixed
@@ -99,7 +296,7 @@
 ## [0.26.3] - 2023-08-27
 
 ### Fixed
-- Fix: send `ETH_P_ALL` in htons format 
+- Fix: send `ETH_P_ALL` in htons format
   ([#1925](https://github.com/nix-rust/nix/pull/1925))
 - Fix: `recvmsg` now sets the length of the received `sockaddr_un` field
   correctly on Linux platforms. ([#2041](https://github.com/nix-rust/nix/pull/2041))
@@ -187,7 +384,7 @@
   ([#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.
diff --git a/Cargo.toml b/Cargo.toml
index bb04ab2..34bc897 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,11 +11,12 @@
 
 [package]
 edition = "2021"
-rust-version = "1.65"
+rust-version = "1.69"
 name = "nix"
-version = "0.27.1"
+version = "0.28.0"
 authors = ["The nix-rust Project Developers"]
 include = [
+    "build.rs",
     "src/**/*",
     "test/**/*",
     "LICENSE",
@@ -61,11 +62,6 @@
 path = "test/test_clearenv.rs"
 
 [[test]]
-name = "test-mount"
-path = "test/test_mount.rs"
-harness = false
-
-[[test]]
 name = "test-prctl"
 path = "test/sys/test_prctl.rs"
 
@@ -76,7 +72,7 @@
 version = "1.0"
 
 [dependencies.libc]
-version = "0.2.147"
+version = "0.2.153"
 features = ["extra_traits"]
 
 [dependencies.memoffset]
@@ -102,6 +98,9 @@
 [dev-dependencies.tempfile]
 version = "3.7.1"
 
+[build-dependencies.cfg_aliases]
+version = "0.1.1"
+
 [features]
 acct = []
 aio = ["pin-utils"]
@@ -109,6 +108,7 @@
 dir = ["fs"]
 env = []
 event = []
+fanotify = []
 feature = []
 fs = []
 hostname = []
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 5a78060..d8176a7 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -2,13 +2,13 @@
 name        = "nix"
 description = "Rust friendly bindings to *nix APIs"
 edition     = "2021"
-version     = "0.27.1"
-rust-version = "1.65"
+version     = "0.28.0"
+rust-version = "1.69"
 authors     = ["The nix-rust Project Developers"]
 repository  = "https://github.com/nix-rust/nix"
 license     = "MIT"
 categories  = ["os::unix-apis"]
-include = ["src/**/*", "test/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
+include = ["build.rs", "src/**/*", "test/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
 
 [package.metadata.docs.rs]
 all-features = true
@@ -28,7 +28,7 @@
 ]
 
 [dependencies]
-libc = { version = "0.2.147", features = ["extra_traits"] }
+libc = { version = "0.2.153", features = ["extra_traits"] }
 bitflags = "2.3.1"
 cfg-if = "1.0"
 pin-utils = { version = "0.1.0", optional = true }
@@ -42,6 +42,7 @@
 dir = ["fs"]
 env = []
 event = []
+fanotify = []
 feature = []
 fs = []
 hostname = []
@@ -83,6 +84,9 @@
 [target.'cfg(target_os = "freebsd")'.dev-dependencies]
 sysctl = "0.4"
 
+[build-dependencies]
+cfg_aliases = "0.1.1"
+
 [[test]]
 name = "test"
 path = "test/test.rs"
@@ -96,10 +100,5 @@
 path = "test/test_clearenv.rs"
 
 [[test]]
-name = "test-mount"
-path = "test/test_mount.rs"
-harness = false
-
-[[test]]
 name = "test-prctl"
 path = "test/sys/test_prctl.rs"
diff --git a/METADATA b/METADATA
index 54b6c34..5505720 100644
--- a/METADATA
+++ b/METADATA
@@ -1,23 +1,20 @@
 # This project was upgraded with external_updater.
-# Usage: tools/external_updater/updater.sh update rust/crates/nix
+# Usage: tools/external_updater/updater.sh update external/rust/crates/nix
 # For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
 
 name: "nix"
 description: "Rust friendly bindings to *nix APIs"
 third_party {
-  url {
-    type: HOMEPAGE
-    value: "https://crates.io/crates/nix"
-  }
-  url {
-    type: ARCHIVE
-    value: "https://static.crates.io/crates/nix/nix-0.27.1.crate"
-  }
-  version: "0.27.1"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2023
-    month: 11
-    day: 14
+    year: 2024
+    month: 4
+    day: 8
+  }
+  homepage: "https://crates.io/crates/nix"
+  identifier {
+    type: "Archive"
+    value: "https://static.crates.io/crates/nix/nix-0.28.0.crate"
+    version: "0.28.0"
   }
 }
diff --git a/README.md b/README.md
index e172de2..fb9f84c 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,7 @@
 
 [![Cirrus Build Status](https://api.cirrus-ci.com/github/nix-rust/nix.svg)](https://cirrus-ci.com/github/nix-rust/nix)
 [![crates.io](https://img.shields.io/crates/v/nix.svg)](https://crates.io/crates/nix)
+[![maintenance-status](https://img.shields.io/badge/maintenance-looking--for--maintainer-orange.svg)](https://github.com/nix-rust/nix/issues/2132)
 
 [Documentation (Releases)](https://docs.rs/nix/)
 
@@ -98,13 +99,14 @@
     <li>x86_64-unknown-linux-gnux32</li>
     <li>x86_64-unknown-openbsd</li>
     <li>x86_64-unknown-redox</li>
+    <li>i686-unknown-hurd-gnu</li>
    </td>
   </tr>
 </table>
 
 ## Minimum Supported Rust Version (MSRV)
 
-nix is supported on Rust 1.65 and higher.  Its MSRV will not be
+nix is supported on Rust 1.69 and higher.  Its MSRV will not be
 changed in the future without bumping the major or minor version.
 
 ## Contributing
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..4535af1
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,25 @@
+use cfg_aliases::cfg_aliases;
+
+fn main() {
+    cfg_aliases! {
+        android: { target_os = "android" },
+        dragonfly: { target_os = "dragonfly" },
+        ios: { target_os = "ios" },
+        freebsd: { target_os = "freebsd" },
+        illumos: { target_os = "illumos" },
+        linux: { target_os = "linux" },
+        macos: { target_os = "macos" },
+        netbsd: { target_os = "netbsd" },
+        openbsd: { target_os = "openbsd" },
+        solaris: { target_os = "solaris" },
+        watchos: { target_os = "watchos" },
+        tvos: { target_os = "tvos" },
+
+        apple_targets: { any(ios, macos, watchos, tvos) },
+        bsd: { any(freebsd, dragonfly, netbsd, openbsd, apple_targets) },
+        linux_android: { any(android, linux) },
+        freebsdlike: { any(dragonfly, freebsd) },
+        netbsdlike: { any(netbsd, openbsd) },
+        solarish: { any(illumos, solaris) },
+    }
+}
diff --git a/cargo_embargo.json b/cargo_embargo.json
index 6df39c1..0ae7394 100644
--- a/cargo_embargo.json
+++ b/cargo_embargo.json
@@ -17,5 +17,10 @@
     "user"
   ],
   "min_sdk_version": "29",
-  "run_cargo": false
+  "run_cargo": false,
+  "package": {
+    "nix": {
+      "add_module_block": "module_block.bp.fragment"
+    }
+  }
 }
diff --git a/module_block.bp.fragment b/module_block.bp.fragment
new file mode 100644
index 0000000..63f9136
--- /dev/null
+++ b/module_block.bp.fragment
@@ -0,0 +1,15 @@
+    // Manually translated build.rs cfg aliases.
+    target: {
+        host_linux: {
+            cfgs: [
+                "linux",
+                "linux_android",
+            ],
+        },
+        android: {
+            cfgs: [
+                "android",
+                "linux_android",
+            ],
+        },
+    }
diff --git a/src/dir.rs b/src/dir.rs
index 96a5843..ab70f06 100644
--- a/src/dir.rs
+++ b/src/dir.rs
@@ -44,7 +44,7 @@
 
     /// Opens the given path as with `fcntl::openat`.
     pub fn openat<P: ?Sized + NixPath>(
-        dirfd: RawFd,
+        dirfd: Option<RawFd>,
         path: &P,
         oflag: OFlag,
         mode: sys::stat::Mode,
@@ -225,16 +225,13 @@
     pub fn ino(&self) -> u64 {
         cfg_if! {
             if #[cfg(any(target_os = "aix",
-                         target_os = "android",
                          target_os = "emscripten",
                          target_os = "fuchsia",
                          target_os = "haiku",
-                         target_os = "illumos",
-                         target_os = "ios",
-                         target_os = "l4re",
-                         target_os = "linux",
-                         target_os = "macos",
-                         target_os = "solaris"))] {
+                         target_os = "hurd",
+                         solarish,
+                         linux_android,
+                         apple_targets))] {
                 self.0.d_ino as u64
             } else {
                 u64::from(self.0.d_fileno)
@@ -253,12 +250,7 @@
     /// 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 = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "haiku"
-        )))]
+        #[cfg(not(any(solarish, target_os = "aix", target_os = "haiku")))]
         match self.0.d_type {
             libc::DT_FIFO => Some(Type::Fifo),
             libc::DT_CHR => Some(Type::CharacterDevice),
@@ -271,12 +263,7 @@
         }
 
         // illumos, Solaris, and Haiku systems do not have the d_type member at all:
-        #[cfg(any(
-            target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "haiku"
-        ))]
+        #[cfg(any(solarish, target_os = "aix", target_os = "haiku"))]
         None
     }
 }
diff --git a/src/env.rs b/src/env.rs
index 95177a1..510bbb0 100644
--- a/src/env.rs
+++ b/src/env.rs
@@ -40,13 +40,12 @@
 ///  thread safety must still be upheld.
 pub unsafe fn clearenv() -> std::result::Result<(), ClearEnvError> {
     cfg_if! {
-        if #[cfg(any(target_os = "fuchsia",
+        if #[cfg(any(linux_android,
+                     target_os = "fuchsia",
                      target_os = "wasi",
                      target_env = "uclibc",
-                     target_os = "linux",
-                     target_os = "android",
                      target_os = "emscripten"))] {
-            let ret = libc::clearenv();
+            let ret = unsafe { libc::clearenv() };
         } else {
             use std::env;
             for (name, _) in env::vars_os() {
diff --git a/src/errno.rs b/src/errno.rs
index 50b3524..2e74a84 100644
--- a/src/errno.rs
+++ b/src/errno.rs
@@ -1,74 +1,127 @@
+//! Safe wrappers around errno functions
+//!
+//! # Example
+//! ```
+//! use nix::errno::Errno;
+//!
+//! Errno::EIO.set();
+//! assert_eq!(Errno::last(), Errno::EIO);
+//!
+//! Errno::clear();
+//! assert_eq!(Errno::last(), Errno::from_raw(0));
+//! ```
+
 use crate::Result;
 use cfg_if::cfg_if;
 use libc::{c_int, c_void};
-use std::convert::TryFrom;
 use std::{error, fmt, io};
 
 pub use self::consts::*;
 
 cfg_if! {
     if #[cfg(any(target_os = "freebsd",
-                 target_os = "ios",
-                 target_os = "macos"))] {
+                 apple_targets,))] {
         unsafe fn errno_location() -> *mut c_int {
-            libc::__error()
+            unsafe { libc::__error() }
         }
-    } else if #[cfg(any(target_os = "android",
-                        target_os = "netbsd",
-                        target_os = "openbsd"))] {
+    } else if #[cfg(any(target_os = "android", netbsdlike))] {
         unsafe fn errno_location() -> *mut c_int {
-            libc::__errno()
+            unsafe { libc::__errno() }
         }
     } else if #[cfg(any(target_os = "linux",
                         target_os = "redox",
                         target_os = "dragonfly",
-                        target_os = "fuchsia"))] {
+                        target_os = "fuchsia",
+                        target_os = "hurd"))] {
         unsafe fn errno_location() -> *mut c_int {
-            libc::__errno_location()
+            unsafe { libc::__errno_location() }
         }
-    } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
+    } else if #[cfg(solarish)] {
         unsafe fn errno_location() -> *mut c_int {
-            libc::___errno()
+            unsafe { libc::___errno() }
         }
     } else if #[cfg(any(target_os = "haiku",))] {
         unsafe fn errno_location() -> *mut c_int {
-            libc::_errnop()
+            unsafe { libc::_errnop() }
         }
     } else if #[cfg(any(target_os = "aix"))] {
         unsafe fn errno_location() -> *mut c_int {
-            libc::_Errno()
+            unsafe { libc::_Errno() }
         }
     }
 }
 
-/// Sets the platform-specific errno to no-error
-fn clear() {
-    // Safe because errno is a thread-local variable
-    unsafe {
-        *errno_location() = 0;
-    }
-}
-
 /// Returns the platform-specific value of errno
+#[deprecated(since = "0.28.0", note = "please use `Errno::last_raw()` instead")]
 pub fn errno() -> i32 {
-    unsafe { *errno_location() }
+    Errno::last_raw()
 }
 
 impl Errno {
+    /// Returns the current value of errno
     pub fn last() -> Self {
-        last()
+        Self::from_raw(Self::last_raw())
+    }
+
+    /// Returns the current raw i32 value of errno
+    pub fn last_raw() -> i32 {
+        unsafe { *errno_location() }
+    }
+
+    /// Sets the value of errno.
+    ///
+    /// # Example
+    /// ```
+    /// use nix::errno::Errno;
+    ///
+    /// Errno::EIO.set();
+    ///
+    /// assert_eq!(Errno::last(), Errno::EIO);
+    /// ```
+    pub fn set(self) {
+        Self::set_raw(self as i32)
+    }
+
+    /// Sets the raw i32 value of errno.
+    pub fn set_raw(errno: i32) {
+        // Safe because errno is a thread-local variable
+        unsafe {
+            *errno_location() = errno;
+        }
+    }
+
+    #[deprecated(
+        since = "0.28.0",
+        note = "please use `Errno::from_raw()` instead"
+    )]
+    pub const fn from_i32(err: i32) -> Errno {
+        Self::from_raw(err)
+    }
+
+    pub const fn from_raw(err: i32) -> Errno {
+        #[allow(deprecated)]
+        from_i32(err)
     }
 
     pub fn desc(self) -> &'static str {
         desc(self)
     }
 
-    pub const fn from_i32(err: i32) -> Errno {
-        from_i32(err)
-    }
-
+    /// Sets the platform-specific errno to no-error
+    ///
+    /// ```
+    /// use nix::errno::Errno;
+    ///
+    /// Errno::EIO.set();
+    ///
+    /// Errno::clear();
+    ///
+    /// let err = Errno::last();
+    /// assert_ne!(err, Errno::EIO);
+    /// assert_eq!(err, Errno::from_raw(0));
+    /// ```
     pub fn clear() {
-        clear()
+        Self::set_raw(0)
     }
 
     /// Returns `Ok(value)` if it does not contain the sentinel value. This
@@ -137,14 +190,10 @@
     type Error = io::Error;
 
     fn try_from(ioerror: io::Error) -> std::result::Result<Self, io::Error> {
-        ioerror.raw_os_error().map(Errno::from_i32).ok_or(ioerror)
+        ioerror.raw_os_error().map(Errno::from_raw).ok_or(ioerror)
     }
 }
 
-fn last() -> Errno {
-    Errno::from_i32(errno())
-}
-
 fn desc(errno: Errno) -> &'static str {
     use self::Errno::*;
     match errno {
@@ -225,467 +274,270 @@
         EHOSTUNREACH => "No route to host",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "fuchsia"
         ))]
         ECHRNG => "Channel number out of range",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "fuchsia"
         ))]
         EL2NSYNC => "Level 2 not synchronized",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "fuchsia"
         ))]
         EL3HLT => "Level 3 halted",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "fuchsia"
         ))]
         EL3RST => "Level 3 reset",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "fuchsia"
         ))]
         ELNRNG => "Link number out of range",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "fuchsia"
         ))]
         EUNATCH => "Protocol driver not attached",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "fuchsia"
         ))]
         ENOCSI => "No CSI structure available",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "fuchsia"
         ))]
         EL2HLT => "Level 2 halted",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         EBADE => "Invalid exchange",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         EBADR => "Invalid request descriptor",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         EXFULL => "Exchange full",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         ENOANO => "No anode",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         EBADRQC => "Invalid request code",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         EBADSLT => "Invalid slot",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         EBFONT => "Bad font file format",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
+            linux_android,
+            solarish,
+            target_os = "fuchsia",
+            target_os = "hurd"
         ))]
         ENOSTR => "Device not a stream",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
+            linux_android,
+            solarish,
+            target_os = "fuchsia",
+            target_os = "hurd"
         ))]
         ENODATA => "No data available",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
+            linux_android,
+            solarish,
+            target_os = "fuchsia",
+            target_os = "hurd"
         ))]
         ETIME => "Timer expired",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
+            linux_android,
+            solarish,
+            target_os = "fuchsia",
+            target_os = "hurd"
         ))]
         ENOSR => "Out of streams resources",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         ENONET => "Machine is not on the network",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         ENOPKG => "Package not installed",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
+            linux_android,
+            solarish,
+            target_os = "fuchsia",
+            target_os = "hurd"
         ))]
         EREMOTE => "Object is remote",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "fuchsia"
         ))]
         ENOLINK => "Link has been severed",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         EADV => "Advertise error",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         ESRMNT => "Srmount error",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         ECOMM => "Communication error on send",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
+            target_os = "fuchsia",
         ))]
         EPROTO => "Protocol error",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "fuchsia"
         ))]
         EMULTIHOP => "Multihop attempted",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         EDOTDOT => "RFS specific error",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "aix",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "aix", target_os = "fuchsia"))]
         EBADMSG => "Not a data message",
 
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
+        #[cfg(solarish)]
         EBADMSG => "Trying to read unreadable message",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
             target_os = "aix",
             target_os = "fuchsia",
-            target_os = "haiku"
+            target_os = "haiku",
+            target_os = "hurd"
         ))]
         EOVERFLOW => "Value too large for defined data type",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         ENOTUNIQ => "Name not unique on network",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         EBADFD => "File descriptor in bad state",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         EREMCHG => "Remote address changed",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         ELIBACC => "Can not access a needed shared library",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         ELIBBAD => "Accessing a corrupted shared library",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         ELIBSCN => ".lib section in a.out corrupted",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         ELIBMAX => "Attempting to link in too many shared libraries",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
+            linux_android,
+            solarish,
+            target_os = "fuchsia",
+            target_os = "hurd"
         ))]
         ELIBEXEC => "Cannot exec a shared library directly",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "fuchsia",
             target_os = "openbsd"
         ))]
         EILSEQ => "Illegal byte sequence",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
+            solarish,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "fuchsia"
         ))]
         ERESTART => "Interrupted system call should be restarted",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         ESTRPIPE => "Streams pipe error",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
         EUSERS => "Too many users",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
             target_os = "fuchsia",
             target_os = "netbsd",
             target_os = "redox"
         ))]
         EOPNOTSUPP => "Operation not supported on transport endpoint",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "fuchsia", target_os = "hurd"))]
         ESTALE => "Stale file handle",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         EUCLEAN => "Structure needs cleaning",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         ENOTNAM => "Not a XENIX named type file",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         ENAVAIL => "No XENIX semaphores available",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         EISNAM => "Is a named type file",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         EREMOTEIO => "Remote I/O error",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         EDQUOT => "Quota exceeded",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
             target_os = "fuchsia",
             target_os = "openbsd",
             target_os = "dragonfly"
@@ -693,71 +545,47 @@
         ENOMEDIUM => "No medium found",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
             target_os = "fuchsia",
             target_os = "openbsd"
         ))]
         EMEDIUMTYPE => "Wrong medium type",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "illumos",
-            target_os = "solaris",
+            linux_android,
+            solarish,
             target_os = "fuchsia",
             target_os = "haiku"
         ))]
         ECANCELED => "Operation canceled",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         ENOKEY => "Required key not available",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         EKEYEXPIRED => "Key has expired",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         EKEYREVOKED => "Key has been revoked",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         EKEYREJECTED => "Key was rejected by service",
 
         #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
+            linux_android,
             target_os = "aix",
-            target_os = "fuchsia"
+            target_os = "fuchsia",
+            target_os = "hurd"
         ))]
         EOWNERDEAD => "Owner died",
 
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
+        #[cfg(solarish)]
         EOWNERDEAD => "Process died with lock",
 
-        #[cfg(any(
-            target_os = "linux",
-            target_os = "android",
-            target_os = "aix",
-            target_os = "fuchsia"
-        ))]
+        #[cfg(any(linux_android, target_os = "aix", target_os = "fuchsia"))]
         ENOTRECOVERABLE => "State not recoverable",
 
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
+        #[cfg(solarish)]
         ENOTRECOVERABLE => "Lock is not recoverable",
 
         #[cfg(any(
@@ -772,21 +600,13 @@
         ))]
         EHWPOISON => "Memory page has hardware error",
 
-        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+        #[cfg(freebsdlike)]
         EDOOFUS => "Programming error",
 
-        #[cfg(any(
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "redox"
-        ))]
+        #[cfg(any(freebsdlike, target_os = "hurd", target_os = "redox"))]
         EMULTIHOP => "Multihop attempted",
 
-        #[cfg(any(
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "redox"
-        ))]
+        #[cfg(any(freebsdlike, target_os = "hurd", target_os = "redox"))]
         ENOLINK => "Link has been severed",
 
         #[cfg(target_os = "freebsd")]
@@ -795,300 +615,157 @@
         #[cfg(target_os = "freebsd")]
         ECAPMODE => "Not permitted in capability mode",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd"
-        ))]
+        #[cfg(any(bsd, target_os = "hurd"))]
         ENEEDAUTH => "Need authenticator",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd",
-            target_os = "redox",
-            target_os = "illumos",
-            target_os = "solaris"
-        ))]
+        #[cfg(any(bsd, target_os = "redox", solarish))]
         EOVERFLOW => "Value too large to be stored in data type",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
+            freebsdlike,
+            apple_targets,
             target_os = "netbsd",
             target_os = "redox",
-            target_os = "haiku"
+            target_os = "haiku",
+            target_os = "hurd"
         ))]
         EILSEQ => "Illegal byte sequence",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd",
-            target_os = "haiku"
-        ))]
+        #[cfg(any(bsd, target_os = "haiku"))]
         ENOATTR => "Attribute not found",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd",
+            bsd,
             target_os = "redox",
-            target_os = "haiku"
+            target_os = "haiku",
+            target_os = "hurd"
         ))]
         EBADMSG => "Bad message",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd",
-            target_os = "redox",
-            target_os = "haiku"
+            bsd,
+            target_os = "haiku",
+            target_os = "hurd",
+            target_os = "redox"
         ))]
         EPROTO => "Protocol error",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd"
+            freebsdlike,
+            apple_targets,
+            target_os = "openbsd",
+            target_os = "hurd"
         ))]
         ENOTRECOVERABLE => "State not recoverable",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd"
-        ))]
+        #[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))]
         EOWNERDEAD => "Previous owner died",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd",
+            bsd,
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "haiku"
+            solarish,
+            target_os = "haiku",
+            target_os = "hurd"
         ))]
         ENOTSUP => "Operation not supported",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "aix",
-            target_os = "openbsd",
-            target_os = "netbsd"
-        ))]
+        #[cfg(any(bsd, target_os = "aix", target_os = "hurd"))]
         EPROCLIM => "Too many processes",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
+            bsd,
             target_os = "aix",
-            target_os = "openbsd",
-            target_os = "netbsd",
+            target_os = "hurd",
             target_os = "redox"
         ))]
         EUSERS => "Too many users",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd",
+            bsd,
+            solarish,
             target_os = "redox",
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
-            target_os = "haiku"
+            target_os = "haiku",
+            target_os = "hurd"
         ))]
         EDQUOT => "Disc quota exceeded",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd",
+            bsd,
+            solarish,
             target_os = "redox",
             target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris",
             target_os = "haiku"
         ))]
         ESTALE => "Stale NFS file handle",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "aix",
-            target_os = "openbsd",
-            target_os = "netbsd",
-            target_os = "redox"
-        ))]
+        #[cfg(any(bsd, target_os = "aix", target_os = "redox"))]
         EREMOTE => "Too many levels of remote in path",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd"
-        ))]
+        #[cfg(any(bsd, target_os = "hurd"))]
         EBADRPC => "RPC struct is bad",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd"
-        ))]
+        #[cfg(any(bsd, target_os = "hurd"))]
         ERPCMISMATCH => "RPC version wrong",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd"
-        ))]
+        #[cfg(any(bsd, target_os = "hurd"))]
         EPROGUNAVAIL => "RPC prog. not avail",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd"
-        ))]
+        #[cfg(any(bsd, target_os = "hurd"))]
         EPROGMISMATCH => "Program version wrong",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd"
-        ))]
+        #[cfg(any(bsd, target_os = "hurd"))]
         EPROCUNAVAIL => "Bad procedure for program",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd"
-        ))]
+        #[cfg(any(bsd, target_os = "hurd"))]
         EFTYPE => "Inappropriate file type or format",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
-            target_os = "openbsd",
-            target_os = "netbsd"
-        ))]
+        #[cfg(any(bsd, target_os = "hurd"))]
         EAUTH => "Authentication error",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "freebsd",
-            target_os = "dragonfly",
-            target_os = "ios",
+            bsd,
             target_os = "aix",
-            target_os = "openbsd",
-            target_os = "netbsd",
+            target_os = "hurd",
             target_os = "redox"
         ))]
         ECANCELED => "Operation canceled",
 
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         EPWROFF => "Device power is off",
 
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         EDEVERR => "Device error, e.g. paper out",
 
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         EBADEXEC => "Bad executable",
 
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         EBADARCH => "Bad CPU type in executable",
 
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         ESHLIBVERS => "Shared library version mismatch",
 
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         EBADMACHO => "Malformed Macho file",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "ios",
-            target_os = "netbsd",
-            target_os = "haiku"
-        ))]
+        #[cfg(any(apple_targets, target_os = "netbsd", target_os = "haiku"))]
         EMULTIHOP => "Reserved",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "ios",
+            apple_targets,
             target_os = "aix",
             target_os = "netbsd",
             target_os = "redox"
         ))]
         ENODATA => "No message available on STREAM",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "ios",
-            target_os = "netbsd",
-            target_os = "haiku"
-        ))]
+        #[cfg(any(apple_targets, target_os = "netbsd", target_os = "haiku"))]
         ENOLINK => "Reserved",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "ios",
+            apple_targets,
             target_os = "aix",
             target_os = "netbsd",
             target_os = "redox"
@@ -1096,8 +773,7 @@
         ENOSR => "No STREAM resources",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "ios",
+            apple_targets,
             target_os = "aix",
             target_os = "netbsd",
             target_os = "redox"
@@ -1105,30 +781,23 @@
         ENOSTR => "Not a STREAM",
 
         #[cfg(any(
-            target_os = "macos",
-            target_os = "ios",
+            apple_targets,
             target_os = "aix",
             target_os = "netbsd",
             target_os = "redox"
         ))]
         ETIME => "STREAM ioctl timeout",
 
-        #[cfg(any(
-            target_os = "macos",
-            target_os = "ios",
-            target_os = "aix",
-            target_os = "illumos",
-            target_os = "solaris"
-        ))]
+        #[cfg(any(apple_targets, solarish, target_os = "aix"))]
         EOPNOTSUPP => "Operation not supported on socket",
 
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         ENOPOLICY => "No such policy registered",
 
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         EQFULL => "Interface output queue is full",
 
-        #[cfg(target_os = "openbsd")]
+        #[cfg(any(target_os = "openbsd", target_os = "hurd"))]
         EOPNOTSUPP => "Operation not supported",
 
         #[cfg(target_os = "openbsd")]
@@ -1137,18 +806,33 @@
         #[cfg(target_os = "dragonfly")]
         EASYNC => "Async",
 
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
+        #[cfg(solarish)]
         EDEADLOCK => "Resource deadlock would occur",
 
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
+        #[cfg(solarish)]
         ELOCKUNMAPPED => "Locked lock was unmapped",
 
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
+        #[cfg(solarish)]
         ENOTACTIVE => "Facility is not active",
+
+        #[cfg(target_os = "hurd")]
+        EBACKGROUND => "Inappropriate operation for background process",
+
+        #[cfg(target_os = "hurd")]
+        EDIED => "Translator died",
+
+        #[cfg(target_os = "hurd")]
+        EGREGIOUS => "You really blew it this time",
+
+        #[cfg(target_os = "hurd")]
+        EIEIO => "Computer bought the farm",
+
+        #[cfg(target_os = "hurd")]
+        EGRATUITOUS => "Gratuitous error",
     }
 }
 
-#[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))]
+#[cfg(any(linux_android, target_os = "fuchsia"))]
 mod consts {
     #[derive(Clone, Copy, Debug, Eq, PartialEq)]
     #[repr(i32)]
@@ -1296,6 +980,10 @@
         pub const ENOTSUP: Errno = Errno::EOPNOTSUPP;
     }
 
+    #[deprecated(
+        since = "0.28.0",
+        note = "please use `Errno::from_raw()` instead"
+    )]
     pub const fn from_i32(e: i32) -> Errno {
         use self::Errno::*;
 
@@ -1438,7 +1126,7 @@
     }
 }
 
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(apple_targets)]
 mod consts {
     #[derive(Clone, Copy, Debug, Eq, PartialEq)]
     #[repr(i32)]
@@ -1559,6 +1247,10 @@
         pub const EDEADLOCK: Errno = Errno::EDEADLK;
     }
 
+    #[deprecated(
+        since = "0.28.0",
+        note = "please use `Errno::from_raw()` instead"
+    )]
     pub const fn from_i32(e: i32) -> Errno {
         use self::Errno::*;
 
@@ -1786,6 +1478,10 @@
         pub const EOPNOTSUPP: Errno = Errno::ENOTSUP;
     }
 
+    #[deprecated(
+        since = "0.28.0",
+        note = "please use `Errno::from_raw()` instead"
+    )]
     pub const fn from_i32(e: i32) -> Errno {
         use self::Errno::*;
 
@@ -2003,6 +1699,10 @@
         pub const EOPNOTSUPP: Errno = Errno::ENOTSUP;
     }
 
+    #[deprecated(
+        since = "0.28.0",
+        note = "please use `Errno::from_raw()` instead"
+    )]
     pub const fn from_i32(e: i32) -> Errno {
         use self::Errno::*;
 
@@ -2215,6 +1915,10 @@
         pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
     }
 
+    #[deprecated(
+        since = "0.28.0",
+        note = "please use `Errno::from_raw()` instead"
+    )]
     pub const fn from_i32(e: i32) -> Errno {
         use self::Errno::*;
 
@@ -2429,6 +2133,10 @@
         pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
     }
 
+    #[deprecated(
+        since = "0.28.0",
+        note = "please use `Errno::from_raw()` instead"
+    )]
     pub const fn from_i32(e: i32) -> Errno {
         use self::Errno::*;
 
@@ -2632,6 +2340,10 @@
         pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
     }
 
+    #[deprecated(
+        since = "0.28.0",
+        note = "please use `Errno::from_raw()` instead"
+    )]
     pub const fn from_i32(e: i32) -> Errno {
         use self::Errno::*;
 
@@ -2726,7 +2438,7 @@
     }
 }
 
-#[cfg(any(target_os = "illumos", target_os = "solaris"))]
+#[cfg(solarish)]
 mod consts {
     #[derive(Clone, Copy, Debug, Eq, PartialEq)]
     #[repr(i32)]
@@ -2861,6 +2573,10 @@
         pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
     }
 
+    #[deprecated(
+        since = "0.28.0",
+        note = "please use `Errno::from_raw()` instead"
+    )]
     pub const fn from_i32(e: i32) -> Errno {
         use self::Errno::*;
 
@@ -3081,6 +2797,10 @@
         pub const EOPNOTSUPP: Errno = Errno::ENOTSUP;
     }
 
+    #[deprecated(
+        since = "0.28.0",
+        note = "please use `Errno::from_raw()` instead"
+    )]
     pub const fn from_i32(e: i32) -> Errno {
         use self::Errno::*;
 
@@ -3272,6 +2992,10 @@
         EOPNOTSUPP = libc::EOPNOTSUPP,
     }
 
+    #[deprecated(
+        since = "0.28.0",
+        note = "please use `Errno::from_raw()` instead"
+    )]
     pub const fn from_i32(e: i32) -> Errno {
         use self::Errno::*;
 
@@ -3378,3 +3102,235 @@
         }
     }
 }
+
+#[cfg(target_os = "hurd")]
+mod consts {
+    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+    #[repr(i32)]
+    #[non_exhaustive]
+    pub enum Errno {
+        UnknownErrno = 0,
+        EPERM = libc::EPERM,
+        ENOENT = libc::ENOENT,
+        ESRCH = libc::ESRCH,
+        EINTR = libc::EINTR,
+        EIO = libc::EIO,
+        ENXIO = libc::ENXIO,
+        E2BIG = libc::E2BIG,
+        ENOEXEC = libc::ENOEXEC,
+        EBADF = libc::EBADF,
+        ECHILD = libc::ECHILD,
+        EDEADLK = libc::EDEADLK,
+        ENOMEM = libc::ENOMEM,
+        EACCES = libc::EACCES,
+        EFAULT = libc::EFAULT,
+        ENOTBLK = libc::ENOTBLK,
+        EBUSY = libc::EBUSY,
+        EEXIST = libc::EEXIST,
+        EXDEV = libc::EXDEV,
+        ENODEV = libc::ENODEV,
+        ENOTDIR = libc::ENOTDIR,
+        EISDIR = libc::EISDIR,
+        EINVAL = libc::EINVAL,
+        EMFILE = libc::EMFILE,
+        ENFILE = libc::ENFILE,
+        ENOTTY = libc::ENOTTY,
+        ETXTBSY = libc::ETXTBSY,
+        EFBIG = libc::EFBIG,
+        ENOSPC = libc::ENOSPC,
+        ESPIPE = libc::ESPIPE,
+        EROFS = libc::EROFS,
+        EMLINK = libc::EMLINK,
+        EPIPE = libc::EPIPE,
+        EDOM = libc::EDOM,
+        ERANGE = libc::ERANGE,
+        EAGAIN = libc::EAGAIN,
+        EINPROGRESS = libc::EINPROGRESS,
+        EALREADY = libc::EALREADY,
+        ENOTSOCK = libc::ENOTSOCK,
+        EMSGSIZE = libc::EMSGSIZE,
+        EPROTOTYPE = libc::EPROTOTYPE,
+        ENOPROTOOPT = libc::ENOPROTOOPT,
+        EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
+        ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
+        EOPNOTSUPP = libc::EOPNOTSUPP,
+        EPFNOSUPPORT = libc::EPFNOSUPPORT,
+        EAFNOSUPPORT = libc::EAFNOSUPPORT,
+        EADDRINUSE = libc::EADDRINUSE,
+        EADDRNOTAVAIL = libc::EADDRNOTAVAIL,
+        ENETDOWN = libc::ENETDOWN,
+        ENETUNREACH = libc::ENETUNREACH,
+        ENETRESET = libc::ENETRESET,
+        ECONNABORTED = libc::ECONNABORTED,
+        ECONNRESET = libc::ECONNRESET,
+        ENOBUFS = libc::ENOBUFS,
+        EISCONN = libc::EISCONN,
+        ENOTCONN = libc::ENOTCONN,
+        EDESTADDRREQ = libc::EDESTADDRREQ,
+        ESHUTDOWN = libc::ESHUTDOWN,
+        ETOOMANYREFS = libc::ETOOMANYREFS,
+        ETIMEDOUT = libc::ETIMEDOUT,
+        ECONNREFUSED = libc::ECONNREFUSED,
+        ELOOP = libc::ELOOP,
+        ENAMETOOLONG = libc::ENAMETOOLONG,
+        EHOSTDOWN = libc::EHOSTDOWN,
+        EHOSTUNREACH = libc::EHOSTUNREACH,
+        ENOTEMPTY = libc::ENOTEMPTY,
+        EPROCLIM = libc::EPROCLIM,
+        EUSERS = libc::EUSERS,
+        EDQUOT = libc::EDQUOT,
+        ESTALE = libc::ESTALE,
+        EREMOTE = libc::EREMOTE,
+        EBADRPC = libc::EBADRPC,
+        ERPCMISMATCH = libc::ERPCMISMATCH,
+        EPROGUNAVAIL = libc::EPROGUNAVAIL,
+        EPROGMISMATCH = libc::EPROGMISMATCH,
+        EPROCUNAVAIL = libc::EPROCUNAVAIL,
+        ENOLCK = libc::ENOLCK,
+        EFTYPE = libc::EFTYPE,
+        EAUTH = libc::EAUTH,
+        ENEEDAUTH = libc::ENEEDAUTH,
+        ENOSYS = libc::ENOSYS,
+        ELIBEXEC = libc::ELIBEXEC,
+        ENOTSUP = libc::ENOTSUP,
+        EILSEQ = libc::EILSEQ,
+        EBACKGROUND = libc::EBACKGROUND,
+        EDIED = libc::EDIED,
+        EGREGIOUS = libc::EGREGIOUS,
+        EIEIO = libc::EIEIO,
+        EGRATUITOUS = libc::EGRATUITOUS,
+        EBADMSG = libc::EBADMSG,
+        EIDRM = libc::EIDRM,
+        EMULTIHOP = libc::EMULTIHOP,
+        ENODATA = libc::ENODATA,
+        ENOLINK = libc::ENOLINK,
+        ENOMSG = libc::ENOMSG,
+        ENOSR = libc::ENOSR,
+        ENOSTR = libc::ENOSTR,
+        EOVERFLOW = libc::EOVERFLOW,
+        EPROTO = libc::EPROTO,
+        ETIME = libc::ETIME,
+        ECANCELED = libc::ECANCELED,
+        EOWNERDEAD = libc::EOWNERDEAD,
+        ENOTRECOVERABLE = libc::ENOTRECOVERABLE,
+    }
+
+    impl Errno {
+        pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
+    }
+
+    #[deprecated(
+        since = "0.28.0",
+        note = "please use `Errno::from_raw()` instead"
+    )]
+    pub const fn from_i32(e: i32) -> Errno {
+        use self::Errno::*;
+
+        match e {
+            libc::EPERM => EPERM,
+            libc::ENOENT => ENOENT,
+            libc::ESRCH => ESRCH,
+            libc::EINTR => EINTR,
+            libc::EIO => EIO,
+            libc::ENXIO => ENXIO,
+            libc::E2BIG => E2BIG,
+            libc::ENOEXEC => ENOEXEC,
+            libc::EBADF => EBADF,
+            libc::ECHILD => ECHILD,
+            libc::EDEADLK => EDEADLK,
+            libc::ENOMEM => ENOMEM,
+            libc::EACCES => EACCES,
+            libc::EFAULT => EFAULT,
+            libc::ENOTBLK => ENOTBLK,
+            libc::EBUSY => EBUSY,
+            libc::EEXIST => EEXIST,
+            libc::EXDEV => EXDEV,
+            libc::ENODEV => ENODEV,
+            libc::ENOTDIR => ENOTDIR,
+            libc::EISDIR => EISDIR,
+            libc::EINVAL => EINVAL,
+            libc::EMFILE => EMFILE,
+            libc::ENFILE => ENFILE,
+            libc::ENOTTY => ENOTTY,
+            libc::ETXTBSY => ETXTBSY,
+            libc::EFBIG => EFBIG,
+            libc::ENOSPC => ENOSPC,
+            libc::ESPIPE => ESPIPE,
+            libc::EROFS => EROFS,
+            libc::EMLINK => EMLINK,
+            libc::EPIPE => EPIPE,
+            libc::EDOM => EDOM,
+            libc::ERANGE => ERANGE,
+            libc::EAGAIN => EAGAIN,
+            libc::EINPROGRESS => EINPROGRESS,
+            libc::EALREADY => EALREADY,
+            libc::ENOTSOCK => ENOTSOCK,
+            libc::EMSGSIZE => EMSGSIZE,
+            libc::EPROTOTYPE => EPROTOTYPE,
+            libc::ENOPROTOOPT => ENOPROTOOPT,
+            libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
+            libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
+            libc::EOPNOTSUPP => EOPNOTSUPP,
+            libc::EPFNOSUPPORT => EPFNOSUPPORT,
+            libc::EAFNOSUPPORT => EAFNOSUPPORT,
+            libc::EADDRINUSE => EADDRINUSE,
+            libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
+            libc::ENETDOWN => ENETDOWN,
+            libc::ENETUNREACH => ENETUNREACH,
+            libc::ENETRESET => ENETRESET,
+            libc::ECONNABORTED => ECONNABORTED,
+            libc::ECONNRESET => ECONNRESET,
+            libc::ENOBUFS => ENOBUFS,
+            libc::EISCONN => EISCONN,
+            libc::ENOTCONN => ENOTCONN,
+            libc::EDESTADDRREQ => EDESTADDRREQ,
+            libc::ESHUTDOWN => ESHUTDOWN,
+            libc::ETOOMANYREFS => ETOOMANYREFS,
+            libc::ETIMEDOUT => ETIMEDOUT,
+            libc::ECONNREFUSED => ECONNREFUSED,
+            libc::ELOOP => ELOOP,
+            libc::ENAMETOOLONG => ENAMETOOLONG,
+            libc::EHOSTDOWN => EHOSTDOWN,
+            libc::EHOSTUNREACH => EHOSTUNREACH,
+            libc::ENOTEMPTY => ENOTEMPTY,
+            libc::EPROCLIM => EPROCLIM,
+            libc::EUSERS => EUSERS,
+            libc::EDQUOT => EDQUOT,
+            libc::ESTALE => ESTALE,
+            libc::EREMOTE => EREMOTE,
+            libc::EBADRPC => EBADRPC,
+            libc::ERPCMISMATCH => ERPCMISMATCH,
+            libc::EPROGUNAVAIL => EPROGUNAVAIL,
+            libc::EPROGMISMATCH => EPROGMISMATCH,
+            libc::EPROCUNAVAIL => EPROCUNAVAIL,
+            libc::ENOLCK => ENOLCK,
+            libc::EFTYPE => EFTYPE,
+            libc::EAUTH => EAUTH,
+            libc::ENEEDAUTH => ENEEDAUTH,
+            libc::ENOSYS => ENOSYS,
+            libc::ELIBEXEC => ELIBEXEC,
+            libc::ENOTSUP => ENOTSUP,
+            libc::EILSEQ => EILSEQ,
+            libc::EBACKGROUND => EBACKGROUND,
+            libc::EDIED => EDIED,
+            libc::EGREGIOUS => EGREGIOUS,
+            libc::EIEIO => EIEIO,
+            libc::EGRATUITOUS => EGRATUITOUS,
+            libc::EBADMSG => EBADMSG,
+            libc::EIDRM => EIDRM,
+            libc::EMULTIHOP => EMULTIHOP,
+            libc::ENODATA => ENODATA,
+            libc::ENOLINK => ENOLINK,
+            libc::ENOMSG => ENOMSG,
+            libc::ENOSR => ENOSR,
+            libc::ENOSTR => ENOSTR,
+            libc::EOVERFLOW => EOVERFLOW,
+            libc::EPROTO => EPROTO,
+            libc::ETIME => ETIME,
+            libc::ECANCELED => ECANCELED,
+            libc::EOWNERDEAD => EOWNERDEAD,
+            libc::ENOTRECOVERABLE => ENOTRECOVERABLE,
+            _ => UnknownErrno,
+        }
+    }
+}
diff --git a/src/fcntl.rs b/src/fcntl.rs
index 9bfecda..ccefe95 100644
--- a/src/fcntl.rs
+++ b/src/fcntl.rs
@@ -1,27 +1,39 @@
+//! file control options
 use crate::errno::Errno;
-use libc::{self, c_char, c_int, c_uint, size_t, ssize_t};
+#[cfg(all(target_os = "freebsd", target_arch = "x86_64"))]
+use core::slice;
+use libc::{c_int, c_uint, size_t, ssize_t};
+#[cfg(any(
+    target_os = "netbsd",
+    apple_targets,
+    target_os = "dragonfly",
+    all(target_os = "freebsd", target_arch = "x86_64"),
+))]
+use std::ffi::CStr;
 use std::ffi::OsString;
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
+use std::ops::{Deref, DerefMut};
 #[cfg(not(target_os = "redox"))]
 use std::os::raw;
 use std::os::unix::ffi::OsStringExt;
 use std::os::unix::io::RawFd;
-// For splice and copy_file_range
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
+use std::os::unix::io::{AsRawFd, OwnedFd};
 #[cfg(any(
-    target_os = "android",
-    target_os = "freebsd",
-    target_os = "linux"
+    target_os = "netbsd",
+    apple_targets,
+    target_os = "dragonfly",
+    all(target_os = "freebsd", target_arch = "x86_64"),
 ))]
-use std::{
-    os::unix::io::{AsFd, AsRawFd},
-    ptr,
-};
+use std::path::PathBuf;
+#[cfg(any(linux_android, target_os = "freebsd"))]
+use std::{os::unix::io::AsFd, ptr};
 
 #[cfg(feature = "fs")]
 use crate::{sys::stat::Mode, NixPath, Result};
 
 #[cfg(any(
-    target_os = "linux",
-    target_os = "android",
+    linux_android,
     target_os = "emscripten",
     target_os = "fuchsia",
     target_os = "wasi",
@@ -32,41 +44,58 @@
 pub use self::posix_fadvise::{posix_fadvise, PosixFadviseAdvice};
 
 #[cfg(not(target_os = "redox"))]
-#[cfg(any(feature = "fs", feature = "process"))]
+#[cfg(any(feature = "fs", feature = "process", feature = "user"))]
 libc_bitflags! {
+    /// Flags that control how the various *at syscalls behave.
     #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "process"))))]
     pub struct AtFlags: c_int {
+        #[allow(missing_docs)]
+        #[doc(hidden)]
+        // Should not be used by the public API, but only internally.
         AT_REMOVEDIR;
+        /// Used with [`linkat`](crate::unistd::linkat`) to create a link to a symbolic link's
+        /// target, instead of to the symbolic link itself.
         AT_SYMLINK_FOLLOW;
+        /// Used with functions like [`fstatat`](crate::sys::stat::fstatat`) to operate on a link
+        /// itself, instead of the symbolic link's target.
         AT_SYMLINK_NOFOLLOW;
-        #[cfg(any(target_os = "android", target_os = "linux"))]
+        /// Don't automount the terminal ("basename") component of pathname if it is a directory
+        /// that is an automount point.
+        #[cfg(linux_android)]
         AT_NO_AUTOMOUNT;
-        #[cfg(any(target_os = "android", target_os = "linux"))]
+        /// If the provided path is an empty string, operate on the provided directory file
+        /// descriptor instead.
+        #[cfg(any(linux_android, target_os = "freebsd", target_os = "hurd"))]
         AT_EMPTY_PATH;
+        /// Used with [`faccessat`](crate::unistd::faccessat), the checks for accessibility are
+        /// performed using the effective user and group IDs instead of the real user and group ID
         #[cfg(not(target_os = "android"))]
         AT_EACCESS;
     }
 }
 
-#[cfg(any(feature = "fs", feature = "term"))]
+#[cfg(any(
+    feature = "fs",
+    feature = "term",
+    all(feature = "fanotify", target_os = "linux")
+))]
 libc_bitflags!(
     /// Configuration options for opened files.
-    #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "term"))))]
+    #[cfg_attr(docsrs, doc(cfg(any(feature = "fs", feature = "term", all(feature = "fanotify", target_os = "linux")))))]
     pub struct OFlag: c_int {
         /// Mask for the access mode of the file.
         O_ACCMODE;
         /// Use alternate I/O semantics.
         #[cfg(target_os = "netbsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         O_ALT_IO;
         /// Open the file in append-only mode.
         O_APPEND;
         /// Generate a signal when input or output becomes possible.
-        #[cfg(not(any(target_os = "aix",
-                      target_os = "illumos",
-                      target_os = "solaris",
-                      target_os = "haiku")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(not(any(
+            solarish,
+            target_os = "aix",
+            target_os = "haiku"
+        )))]
         O_ASYNC;
         /// Closes the file descriptor once an `execve` call is made.
         ///
@@ -75,68 +104,42 @@
         /// Create the file if it does not exist.
         O_CREAT;
         /// Try to minimize cache effects of the I/O for this file.
-        #[cfg(any(target_os = "android",
-                  target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "linux",
-                  target_os = "netbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(
+            freebsdlike,
+            linux_android,
+            solarish,
+            target_os = "netbsd"
+        ))]
         O_DIRECT;
         /// If the specified path isn't a directory, fail.
-        #[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         O_DIRECTORY;
         /// Implicitly follow each `write()` with an `fdatasync()`.
-        #[cfg(any(target_os = "android",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, apple_targets, netbsdlike))]
         O_DSYNC;
         /// Error out if a file was not created.
         O_EXCL;
         /// Open for execute only.
         #[cfg(target_os = "freebsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         O_EXEC;
         /// Open with an exclusive file lock.
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "ios",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd",
-                  target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(bsd, target_os = "redox"))]
         O_EXLOCK;
         /// Same as `O_SYNC`.
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "ios",
-                  all(target_os = "linux", not(target_env = "musl")),
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd",
+        #[cfg(any(bsd,
+                  all(target_os = "linux", not(target_env = "musl"), not(target_env = "ohos")),
                   target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         O_FSYNC;
         /// Allow files whose sizes can't be represented in an `off_t` to be opened.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         O_LARGEFILE;
         /// Do not update the file last access time during `read(2)`s.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         O_NOATIME;
         /// Don't attach the device as the process' controlling terminal.
         #[cfg(not(target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         O_NOCTTY;
         /// Same as `O_NONBLOCK`.
         #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         O_NDELAY;
         /// `open()` will fail if the given path is a symbolic link.
         O_NOFOLLOW;
@@ -144,13 +147,11 @@
         O_NONBLOCK;
         /// Don't deliver `SIGPIPE`.
         #[cfg(target_os = "netbsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         O_NOSIGPIPE;
         /// Obtain a file descriptor for low-level access.
         ///
         /// The file itself is not opened and other file operations will fail.
-        #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, target_os = "redox"))]
         O_PATH;
         /// Only allow reading.
         ///
@@ -161,36 +162,24 @@
         /// This should not be combined with `O_WRONLY` or `O_RDONLY`.
         O_RDWR;
         /// Similar to `O_DSYNC` but applies to `read`s instead.
-        #[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(target_os = "linux", netbsdlike))]
         O_RSYNC;
         /// Skip search permission checks.
         #[cfg(target_os = "netbsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         O_SEARCH;
         /// Open with a shared file lock.
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "ios",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd",
-                  target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(bsd, target_os = "redox"))]
         O_SHLOCK;
         /// Implicitly follow each `write()` with an `fsync()`.
         #[cfg(not(target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         O_SYNC;
         /// Create an unnamed temporary file.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         O_TMPFILE;
         /// Truncate an existing regular file to 0 length if it allows writing.
         O_TRUNC;
         /// Restore default TTY attributes.
         #[cfg(target_os = "freebsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         O_TTY_INIT;
         /// Only allow writing.
         ///
@@ -199,9 +188,23 @@
     }
 );
 
+/// Computes the raw fd consumed by a function of the form `*at`.
+#[cfg(any(
+    all(feature = "fs", not(target_os = "redox")),
+    all(feature = "process", linux_android),
+    all(feature = "fanotify", target_os = "linux")
+))]
+pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int {
+    fd.unwrap_or(libc::AT_FDCWD)
+}
+
 feature! {
 #![feature = "fs"]
 
+/// open or create a file for reading, writing or executing
+///
+/// # See Also
+/// [`open`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html)
 // The conversion is not identical on all operating systems.
 #[allow(clippy::useless_conversion)]
 pub fn open<P: ?Sized + NixPath>(
@@ -216,21 +219,37 @@
     Errno::result(fd)
 }
 
+/// open or create a file for reading, writing or executing
+///
+/// The `openat` function is equivalent to the [`open`] function except in the case where the path
+/// specifies a relative path.  In that case, the file to be opened is determined relative to the
+/// directory associated with the file descriptor `fd`.
+///
+/// # See Also
+/// [`openat`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/openat.html)
 // The conversion is not identical on all operating systems.
 #[allow(clippy::useless_conversion)]
 #[cfg(not(target_os = "redox"))]
 pub fn openat<P: ?Sized + NixPath>(
-    dirfd: RawFd,
+    dirfd: Option<RawFd>,
     path: &P,
     oflag: OFlag,
     mode: Mode,
 ) -> Result<RawFd> {
     let fd = path.with_nix_path(|cstr| unsafe {
-        libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint)
+        libc::openat(at_rawfd(dirfd), cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint)
     })?;
     Errno::result(fd)
 }
 
+/// Change the name of a file.
+///
+/// The `renameat` function is equivalent to `rename` except in the case where either `old_path`
+/// or `new_path` specifies a relative path.  In such cases, the file to be renamed (or the its new
+/// name, respectively) is located relative to `old_dirfd` or `new_dirfd`, respectively
+///
+/// # See Also
+/// [`renameat`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html)
 #[cfg(not(target_os = "redox"))]
 pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
     old_dirfd: Option<RawFd>,
@@ -255,16 +274,30 @@
 #[cfg(all(target_os = "linux", target_env = "gnu"))]
 #[cfg(feature = "fs")]
 libc_bitflags! {
+    /// Flags for use with [`renameat2`].
     #[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
     pub struct RenameFlags: u32 {
+        /// Atomically exchange `old_path` and `new_path`.
         RENAME_EXCHANGE;
+        /// Don't overwrite `new_path` of the rename.  Return an error if `new_path` already
+        /// exists.
         RENAME_NOREPLACE;
+        /// creates a "whiteout" object at the source of the rename at the same time as performing
+        /// the rename.
+        ///
+        /// This operation makes sense only for overlay/union filesystem implementations.
         RENAME_WHITEOUT;
     }
 }
 
 feature! {
 #![feature = "fs"]
+/// Like [`renameat`], but with an additional `flags` argument.
+///
+/// A `renameat2` call with an empty flags argument is equivalent to `renameat`.
+///
+/// # See Also
+/// * [`rename`](https://man7.org/linux/man-pages/man2/rename.2.html)
 #[cfg(all(target_os = "linux", target_env = "gnu"))]
 pub fn renameat2<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
     old_dirfd: Option<RawFd>,
@@ -306,12 +339,12 @@
             Some(dirfd) => libc::readlinkat(
                 dirfd,
                 cstr.as_ptr(),
-                v.as_mut_ptr() as *mut c_char,
+                v.as_mut_ptr().cast(),
                 v.capacity() as size_t,
             ),
             None => libc::readlink(
                 cstr.as_ptr(),
-                v.as_mut_ptr() as *mut c_char,
+                v.as_mut_ptr().cast(),
                 v.capacity() as size_t,
             ),
         }
@@ -322,7 +355,11 @@
     dirfd: Option<RawFd>,
     path: &P,
 ) -> Result<OsString> {
-    let mut v = Vec::with_capacity(libc::PATH_MAX as usize);
+    #[cfg(not(target_os = "hurd"))]
+    const PATH_MAX: usize = libc::PATH_MAX as usize;
+    #[cfg(target_os = "hurd")]
+    const PATH_MAX: usize = 1024; // Hurd does not define a hard limit, so try a guess first
+    let mut v = Vec::with_capacity(PATH_MAX);
 
     {
         // simple case: result is strictly less than `PATH_MAX`
@@ -340,7 +377,7 @@
         let reported_size = match dirfd {
             #[cfg(target_os = "redox")]
             Some(_) => unreachable!(),
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(any(linux_android, target_os = "freebsd", target_os = "hurd"))]
             Some(dirfd) => {
                 let flags = if path.is_empty() {
                     AtFlags::AT_EMPTY_PATH
@@ -348,18 +385,19 @@
                     AtFlags::empty()
                 };
                 super::sys::stat::fstatat(
-                    dirfd,
+                    Some(dirfd),
                     path,
                     flags | AtFlags::AT_SYMLINK_NOFOLLOW,
                 )
             }
             #[cfg(not(any(
-                target_os = "android",
-                target_os = "linux",
-                target_os = "redox"
+                linux_android,
+                target_os = "redox",
+                target_os = "freebsd",
+                target_os = "hurd"
             )))]
             Some(dirfd) => super::sys::stat::fstatat(
-                dirfd,
+                Some(dirfd),
                 path,
                 AtFlags::AT_SYMLINK_NOFOLLOW,
             ),
@@ -375,7 +413,7 @@
         } else {
             // If lstat doesn't cooperate, or reports an error, be a little less
             // precise.
-            (libc::PATH_MAX as usize).max(128) << 1
+            PATH_MAX.max(128) << 1
         }
     };
 
@@ -400,29 +438,32 @@
     }
 }
 
+/// Read value of a symbolic link
+///
+/// # See Also
+/// * [`readlink`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html)
 pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> {
     inner_readlink(None, path)
 }
 
+/// Read value of a symbolic link.
+///
+/// Equivalent to [`readlink` ] except where `path` specifies a relative path.  In that case,
+/// interpret `path` relative to open file specified by `dirfd`.
+///
+/// # See Also
+/// * [`readlink`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html)
 #[cfg(not(target_os = "redox"))]
 pub fn readlinkat<P: ?Sized + NixPath>(
-    dirfd: RawFd,
+    dirfd: Option<RawFd>,
     path: &P,
 ) -> Result<OsString> {
+    let dirfd = at_rawfd(dirfd);
     inner_readlink(Some(dirfd), path)
 }
-
-/// Computes the raw fd consumed by a function of the form `*at`.
-#[cfg(not(target_os = "redox"))]
-pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int {
-    match fd {
-        None => libc::AT_FDCWD,
-        Some(fd) => fd,
-    }
-}
 }
 
-#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
 #[cfg(feature = "fs")]
 libc_bitflags!(
     /// Additional flags for file sealing, which allows for limiting operations on a file.
@@ -436,6 +477,10 @@
         F_SEAL_GROW;
         /// The file contents cannot be modified.
         F_SEAL_WRITE;
+        /// The file contents cannot be modified, except via shared writable mappings that were
+        /// created prior to the seal being set. Since Linux 5.1.
+        #[cfg(linux_android)]
+        F_SEAL_FUTURE_WRITE;
     }
 );
 
@@ -452,59 +497,105 @@
 feature! {
 #![feature = "fs"]
 
+/// Commands for use with [`fcntl`].
 #[cfg(not(target_os = "redox"))]
 #[derive(Debug, Eq, Hash, PartialEq)]
 #[non_exhaustive]
 pub enum FcntlArg<'a> {
+    /// Duplicate the provided file descriptor
     F_DUPFD(RawFd),
+    /// Duplicate the provided file descriptor and set the `FD_CLOEXEC` flag on it.
     F_DUPFD_CLOEXEC(RawFd),
+    /// Get the close-on-exec flag associated with the file descriptor
     F_GETFD,
+    /// Set the close-on-exec flag associated with the file descriptor
     F_SETFD(FdFlag), // FD_FLAGS
+    /// Get descriptor status flags
     F_GETFL,
+    /// Set descriptor status flags
     F_SETFL(OFlag), // O_NONBLOCK
+    /// Set or clear a file segment lock
     F_SETLK(&'a libc::flock),
+    /// Like [`F_SETLK`](FcntlArg::F_SETLK) except that if a shared or exclusive lock is blocked by
+    /// other locks, the process waits until the request can be satisfied.
     F_SETLKW(&'a libc::flock),
+    /// Get the first lock that blocks the lock description
     F_GETLK(&'a mut libc::flock),
-    #[cfg(any(target_os = "linux", target_os = "android"))]
+    /// Acquire or release an open file description lock
+    #[cfg(linux_android)]
     F_OFD_SETLK(&'a libc::flock),
-    #[cfg(any(target_os = "linux", target_os = "android"))]
+    /// Like [`F_OFD_SETLK`](FcntlArg::F_OFD_SETLK) except that if a conflicting lock is held on
+    /// the file, then wait for that lock to be released.
+    #[cfg(linux_android)]
     F_OFD_SETLKW(&'a libc::flock),
-    #[cfg(any(target_os = "linux", target_os = "android"))]
+    /// Determine whether it would be possible to create the given lock.  If not, return details
+    /// about one existing lock that would prevent it.
+    #[cfg(linux_android)]
     F_OFD_GETLK(&'a mut libc::flock),
+    /// Add seals to the file
     #[cfg(any(
-        target_os = "android",
-        target_os = "linux",
+        linux_android,
         target_os = "freebsd"
     ))]
     F_ADD_SEALS(SealFlag),
+    /// Get seals associated with the file
     #[cfg(any(
-        target_os = "android",
-        target_os = "linux",
+        linux_android,
         target_os = "freebsd"
     ))]
     F_GET_SEALS,
-    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    /// Asks the drive to flush all buffered data to permanent storage.
+    #[cfg(apple_targets)]
     F_FULLFSYNC,
-    #[cfg(any(target_os = "linux", target_os = "android"))]
+    /// fsync + issue barrier to drive
+    #[cfg(apple_targets)]
+    F_BARRIERFSYNC,
+    /// Return the capacity of a pipe
+    #[cfg(linux_android)]
     F_GETPIPE_SZ,
-    #[cfg(any(target_os = "linux", target_os = "android"))]
+    /// Change the capacity of a pipe
+    #[cfg(linux_android)]
     F_SETPIPE_SZ(c_int),
+    /// Look up the path of an open file descriptor, if possible.
+    #[cfg(any(
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        apple_targets,
+    ))]
+    F_GETPATH(&'a mut PathBuf),
+    /// Look up the path of an open file descriptor, if possible.
+    #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))]
+    F_KINFO(&'a mut PathBuf),
+    /// Return the full path without firmlinks of the fd.
+    #[cfg(apple_targets)]
+    F_GETPATH_NOFIRMLINK(&'a mut PathBuf),
     // TODO: Rest of flags
 }
 
+/// Commands for use with [`fcntl`].
 #[cfg(target_os = "redox")]
 #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
 #[non_exhaustive]
 pub enum FcntlArg {
+    /// Duplicate the provided file descriptor
     F_DUPFD(RawFd),
+    /// Duplicate the provided file descriptor and set the `FD_CLOEXEC` flag on it.
     F_DUPFD_CLOEXEC(RawFd),
+    /// Get the close-on-exec flag associated with the file descriptor
     F_GETFD,
+    /// Set the close-on-exec flag associated with the file descriptor
     F_SETFD(FdFlag), // FD_FLAGS
+    /// Get descriptor status flags
     F_GETFL,
+    /// Set descriptor status flags
     F_SETFL(OFlag), // O_NONBLOCK
 }
 pub use self::FcntlArg::*;
 
+/// Perform various operations on open file descriptors.
+///
+/// # See Also
+/// * [`fcntl`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html)
 // TODO: Figure out how to handle value fcntl returns
 pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
     let res = unsafe {
@@ -523,51 +614,95 @@
             F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock),
             #[cfg(not(target_os = "redox"))]
             F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock),
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             F_OFD_SETLK(flock) => libc::fcntl(fd, libc::F_OFD_SETLK, flock),
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock),
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock),
             #[cfg(any(
-                target_os = "android",
-                target_os = "linux",
+                linux_android,
                 target_os = "freebsd"
             ))]
             F_ADD_SEALS(flag) => {
                 libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits())
             }
             #[cfg(any(
-                target_os = "android",
-                target_os = "linux",
+                linux_android,
                 target_os = "freebsd"
             ))]
             F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS),
-            #[cfg(any(target_os = "macos", target_os = "ios"))]
+            #[cfg(apple_targets)]
             F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC),
-            #[cfg(any(target_os = "linux", target_os = "android"))]
+            #[cfg(apple_targets)]
+            F_BARRIERFSYNC => libc::fcntl(fd, libc::F_BARRIERFSYNC),
+            #[cfg(linux_android)]
             F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ),
-            #[cfg(any(target_os = "linux", target_os = "android"))]
+            #[cfg(linux_android)]
             F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size),
+            #[cfg(any(
+                target_os = "dragonfly",
+                target_os = "netbsd",
+                apple_targets,
+            ))]
+            F_GETPATH(path) => {
+                let mut buffer = vec![0; libc::PATH_MAX as usize];
+                let res = libc::fcntl(fd, libc::F_GETPATH, buffer.as_mut_ptr());
+                let ok_res = Errno::result(res)?;
+                let optr = CStr::from_bytes_until_nul(&buffer).unwrap();
+                *path = PathBuf::from(OsString::from(optr.to_str().unwrap()));
+                return Ok(ok_res)
+            },
+            #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))]
+            F_KINFO(path) => {
+                let mut info: libc::kinfo_file = std::mem::zeroed();
+                info.kf_structsize = std::mem::size_of::<libc::kinfo_file>() as i32;
+                let res = libc::fcntl(fd, libc::F_KINFO, &mut info);
+                let ok_res = Errno::result(res)?;
+                let p = info.kf_path;
+                let u8_slice = slice::from_raw_parts(p.as_ptr().cast(), p.len());
+                let optr = CStr::from_bytes_until_nul(u8_slice).unwrap();
+                *path = PathBuf::from(OsString::from(optr.to_str().unwrap()));
+                return Ok(ok_res)
+            },
+            #[cfg(apple_targets)]
+            F_GETPATH_NOFIRMLINK(path) => {
+                let mut buffer = vec![0; libc::PATH_MAX as usize];
+                let res = libc::fcntl(fd, libc::F_GETPATH_NOFIRMLINK, buffer.as_mut_ptr());
+                let ok_res = Errno::result(res)?;
+                let optr = CStr::from_bytes_until_nul(&buffer).unwrap();
+                *path = PathBuf::from(OsString::from(optr.to_str().unwrap()));
+                return Ok(ok_res)
+            },
         }
     };
 
     Errno::result(res)
 }
 
-// TODO: convert to libc_enum
+/// Operations for use with [`Flock::lock`].
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
 #[non_exhaustive]
 pub enum FlockArg {
+    /// shared file lock
     LockShared,
+    /// exclusive file lock
     LockExclusive,
+    /// Unlock file
     Unlock,
+    /// Shared lock.  Do not block when locking.
     LockSharedNonblock,
+    /// Exclusive lock.  Do not block when locking.
     LockExclusiveNonblock,
+    #[allow(missing_docs)]
+    #[deprecated(since = "0.28.0", note = "Use FlockArg::Unlock instead")]
     UnlockNonblock,
 }
 
+#[allow(missing_docs)]
 #[cfg(not(any(target_os = "redox", target_os = "solaris")))]
+#[deprecated(since = "0.28.0", note = "`fcntl::Flock` should be used instead.")]
 pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> {
     use self::FlockArg::*;
 
@@ -582,15 +717,133 @@
             LockExclusiveNonblock => {
                 libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB)
             }
+            #[allow(deprecated)]
             UnlockNonblock => libc::flock(fd, libc::LOCK_UN | libc::LOCK_NB),
         }
     };
 
     Errno::result(res).map(drop)
 }
+
+/// Represents valid types for flock.
+///
+/// # Safety
+/// Types implementing this must not be `Clone`.
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
+pub unsafe trait Flockable: AsRawFd {}
+
+/// Represents an owned flock, which unlocks on drop.
+///
+/// See [flock(2)](https://linux.die.net/man/2/flock) for details on locking semantics.
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
+#[derive(Debug)]
+pub struct Flock<T: Flockable>(T);
+
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
+impl<T: Flockable> Drop for Flock<T> {
+    fn drop(&mut self) {
+        let res = Errno::result(unsafe { libc::flock(self.0.as_raw_fd(), libc::LOCK_UN) });
+        if res.is_err() && !std::thread::panicking() {
+            panic!("Failed to remove flock: {}", res.unwrap_err());
+        }
+    }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
+impl<T: Flockable> Deref for Flock<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
+impl<T: Flockable> DerefMut for Flock<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
+impl<T: Flockable> Flock<T> {
+    /// Obtain a/an flock.
+    ///
+    /// # Example
+    /// ```
+    /// # use std::io::Write;
+    /// # use std::fs::File;
+    /// # use nix::fcntl::{Flock, FlockArg};
+    /// # fn do_stuff(file: File) {
+    ///   let mut file = match Flock::lock(file, FlockArg::LockExclusive) {
+    ///       Ok(l) => l,
+    ///       Err(_) => return,
+    ///   };
+    ///
+    ///   // Do stuff
+    ///   let data = "Foo bar";
+    ///   _ = file.write(data.as_bytes());
+    ///   _ = file.sync_data();
+    /// # }
+    pub fn lock(t: T, args: FlockArg) -> std::result::Result<Self, (T, Errno)> {
+        let flags = match args {
+            FlockArg::LockShared => libc::LOCK_SH,
+            FlockArg::LockExclusive => libc::LOCK_EX,
+            FlockArg::LockSharedNonblock => libc::LOCK_SH | libc::LOCK_NB,
+            FlockArg::LockExclusiveNonblock => libc::LOCK_EX | libc::LOCK_NB,
+            #[allow(deprecated)]
+            FlockArg::Unlock | FlockArg::UnlockNonblock => return Err((t, Errno::EINVAL)),
+        };
+        match Errno::result(unsafe { libc::flock(t.as_raw_fd(), flags) }) {
+            Ok(_) => Ok(Self(t)),
+            Err(errno) => Err((t, errno)),
+        }
+    }
+
+    /// Remove the lock and return the object wrapped within.
+    ///
+    /// # Example
+    /// ```
+    /// # use std::fs::File;
+    /// # use nix::fcntl::{Flock, FlockArg};
+    /// fn do_stuff(file: File) -> nix::Result<()> {
+    ///     let mut lock = match Flock::lock(file, FlockArg::LockExclusive) {
+    ///         Ok(l) => l,
+    ///         Err((_,e)) => return Err(e),
+    ///     };
+    ///
+    ///     // Do critical section
+    ///
+    ///     // Unlock
+    ///     let file = match lock.unlock() {
+    ///         Ok(f) => f,
+    ///         Err((_, e)) => return Err(e),
+    ///     };
+    ///
+    ///     // Do anything else
+    ///
+    ///     Ok(())
+    /// }
+    pub fn unlock(self) -> std::result::Result<T, (Self, Errno)> {
+        let inner = unsafe { match Errno::result(libc::flock(self.0.as_raw_fd(), libc::LOCK_UN)) {
+            Ok(_) => std::ptr::read(&self.0),
+            Err(errno) => return Err((self, errno)),
+        }};
+
+        std::mem::forget(self);
+        Ok(inner)
+    }
+}
+
+// Safety: `File` is not [std::clone::Clone].
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
+unsafe impl Flockable for std::fs::File {}
+
+// Safety: `OwnedFd` is not [std::clone::Clone].
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
+unsafe impl Flockable for OwnedFd {}
+}
+
+#[cfg(linux_android)]
 #[cfg(feature = "zerocopy")]
 libc_bitflags! {
     /// Additional flags to `splice` and friends.
@@ -636,7 +889,7 @@
 // Note: FreeBSD defines the offset argument as "off_t".  Linux and Android
 // define it as "loff_t".  But on both OSes, on all supported platforms, those
 // are 64 bits.  So Nix uses i64 to make the docs simple and consistent.
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
 pub fn copy_file_range<Fd1: AsFd, Fd2: AsFd>(
     fd_in: Fd1,
     off_in: Option<&mut i64>,
@@ -669,7 +922,7 @@
             let ret = unsafe {
                 libc::syscall(
                     libc::SYS_copy_file_range,
-                    fd_in,
+                    fd_in.as_fd().as_raw_fd(),
                     off_in,
                     fd_out.as_fd().as_raw_fd(),
                     off_out,
@@ -682,7 +935,11 @@
     Errno::result(ret).map(|r| r as usize)
 }
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
+/// Splice data to/from a pipe
+///
+/// # See Also
+/// *[`splice`](https://man7.org/linux/man-pages/man2/splice.2.html)
+#[cfg(linux_android)]
 pub fn splice(
     fd_in: RawFd,
     off_in: Option<&mut libc::loff_t>,
@@ -704,7 +961,11 @@
     Errno::result(ret).map(|r| r as usize)
 }
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
+/// Duplicate pipe content
+///
+/// # See Also
+/// *[`tee`](https://man7.org/linux/man-pages/man2/tee.2.html)
+#[cfg(linux_android)]
 pub fn tee(
     fd_in: RawFd,
     fd_out: RawFd,
@@ -715,7 +976,11 @@
     Errno::result(ret).map(|r| r as usize)
 }
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
+/// Splice user pages to/from a pipe
+///
+/// # See Also
+/// *[`vmsplice`](https://man7.org/linux/man-pages/man2/vmsplice.2.html)
+#[cfg(linux_android)]
 pub fn vmsplice(
     fd: RawFd,
     iov: &[std::io::IoSlice<'_>],
@@ -724,7 +989,7 @@
     let ret = unsafe {
         libc::vmsplice(
             fd,
-            iov.as_ptr() as *const libc::iovec,
+            iov.as_ptr().cast(),
             iov.len(),
             flags.bits(),
         )
@@ -793,16 +1058,22 @@
 
 #[cfg(any(target_os = "freebsd"))]
 impl SpacectlRange {
+    /// Is the range empty?
+    ///
+    /// After a successful call to [`fspacectl`], A value of `true` for `SpacectlRange::is_empty`
+    /// indicates that the operation is complete.
     #[inline]
     pub fn is_empty(&self) -> bool {
         self.1 == 0
     }
 
+    /// Remaining length of the range
     #[inline]
     pub fn len(&self) -> libc::off_t {
         self.1
     }
 
+    /// Next file offset to operate on
     #[inline]
     pub fn offset(&self) -> libc::off_t {
         self.0
@@ -849,6 +1120,7 @@
 /// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef");
 /// ```
 #[cfg(target_os = "freebsd")]
+#[inline] // Delays codegen, preventing linker errors with dylibs and --no-allow-shlib-undefined
 pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result<SpacectlRange> {
     let mut rqsr = libc::spacectl_range {
         r_offset: range.0,
@@ -897,6 +1169,7 @@
 /// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef");
 /// ```
 #[cfg(target_os = "freebsd")]
+#[inline] // Delays codegen, preventing linker errors with dylibs and --no-allow-shlib-undefined
 pub fn fspacectl_all(
     fd: RawFd,
     offset: libc::off_t,
@@ -922,8 +1195,7 @@
 }
 
 #[cfg(any(
-    target_os = "linux",
-    target_os = "android",
+    linux_android,
     target_os = "emscripten",
     target_os = "fuchsia",
     target_os = "wasi",
@@ -937,21 +1209,34 @@
 
     #[cfg(feature = "fs")]
     libc_enum! {
+        /// The specific advice provided to [`posix_fadvise`].
         #[repr(i32)]
         #[non_exhaustive]
         #[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
         pub enum PosixFadviseAdvice {
+            /// Revert to the default data access behavior.
             POSIX_FADV_NORMAL,
+            /// The file data will be accessed sequentially.
             POSIX_FADV_SEQUENTIAL,
+            /// A hint that file data will be accessed randomly, and prefetching is likely not
+            /// advantageous.
             POSIX_FADV_RANDOM,
+            /// The specified data will only be accessed once and then not reused.
             POSIX_FADV_NOREUSE,
+            /// The specified data will be accessed in the near future.
             POSIX_FADV_WILLNEED,
+            /// The specified data will not be accessed in the near future.
             POSIX_FADV_DONTNEED,
         }
     }
 
     feature! {
     #![feature = "fs"]
+    /// Allows a process to describe to the system its data access behavior for an open file
+    /// descriptor.
+    ///
+    /// # See Also
+    /// * [`posix_fadvise`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fadvise.html)
     pub fn posix_fadvise(
         fd: RawFd,
         offset: libc::off_t,
@@ -963,20 +1248,22 @@
         if res == 0 {
             Ok(())
         } else {
-            Err(Errno::from_i32(res))
+            Err(Errno::from_raw(res))
         }
     }
     }
 }
 
+/// Pre-allocate storage for a range in a file
+///
+/// # See Also
+/// * [`posix_fallocate`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fallocate.html)
 #[cfg(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "dragonfly",
+    linux_android,
+    freebsdlike,
     target_os = "emscripten",
     target_os = "fuchsia",
     target_os = "wasi",
-    target_os = "freebsd"
 ))]
 pub fn posix_fallocate(
     fd: RawFd,
@@ -987,7 +1274,7 @@
     match Errno::result(res) {
         Err(err) => Err(err),
         Ok(0) => Ok(()),
-        Ok(errno) => Err(Errno::from_i32(errno)),
+        Ok(errno) => Err(Errno::from_raw(errno)),
     }
 }
 }
diff --git a/src/features.rs b/src/features.rs
index 9e292cb..0a0c618 100644
--- a/src/features.rs
+++ b/src/features.rs
@@ -1,7 +1,7 @@
 //! Feature tests for OS functionality
 pub use self::os::*;
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 mod os {
     use crate::sys::utsname::uname;
     use crate::Result;
@@ -98,11 +98,10 @@
 }
 
 #[cfg(any(
-        target_os = "dragonfly",    // Since ???
-        target_os = "freebsd",      // Since 10.0
+        freebsdlike,                // FreeBSD since 10.0 DragonFlyBSD since ???
+        netbsdlike,                 // NetBSD since 6.0 OpenBSD since 5.7
+        target_os = "hurd",         // Since glibc 2.28
         target_os = "illumos",      // Since ???
-        target_os = "netbsd",       // Since 6.0
-        target_os = "openbsd",      // Since 5.7
         target_os = "redox",        // Since 1-july-2020
 ))]
 mod os {
@@ -114,8 +113,7 @@
 
 #[cfg(any(
     target_os = "aix",
-    target_os = "macos",
-    target_os = "ios",
+    apple_targets,
     target_os = "fuchsia",
     target_os = "haiku",
     target_os = "solaris"
diff --git a/src/ifaddrs.rs b/src/ifaddrs.rs
index 70b50b0..b3de64b 100644
--- a/src/ifaddrs.rs
+++ b/src/ifaddrs.rs
@@ -4,7 +4,7 @@
 //! of interfaces and their associated addresses.
 
 use cfg_if::cfg_if;
-#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[cfg(apple_targets)]
 use std::convert::TryFrom;
 use std::ffi;
 use std::iter::Iterator;
@@ -33,7 +33,7 @@
 }
 
 cfg_if! {
-    if #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] {
+    if #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))] {
         fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr {
             info.ifa_ifu
         }
@@ -53,7 +53,7 @@
 /// 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"))]
+#[cfg(apple_targets)]
 unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option<SockaddrStorage> {
     let src_sock = info.ifa_netmask;
     if src_sock.is_null() {
@@ -62,22 +62,24 @@
 
     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(),
-    );
+    let dst_sock = unsafe {
+        // memcpy only sa_len bytes, assume the rest is zero
+        std::ptr::copy_nonoverlapping(
+            src_sock as *const u8,
+            dst_sock.as_mut_ptr().cast(),
+            (*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();
+        // 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();
+        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)
+    unsafe { SockaddrStorage::from_raw(dst_sock_ptr, None) }
 }
 
 impl InterfaceAddress {
@@ -85,14 +87,16 @@
     fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress {
         let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) };
         let address = unsafe { SockaddrStorage::from_raw(info.ifa_addr, None) };
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
+        #[cfg(apple_targets)]
         let netmask = unsafe { workaround_xnu_bug(info) };
-        #[cfg(not(any(target_os = "ios", target_os = "macos")))]
+        #[cfg(not(apple_targets))]
         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),
+            flags: InterfaceFlags::from_bits_truncate(
+                info.ifa_flags as IflagsType,
+            ),
             address,
             netmask,
             broadcast: None,
diff --git a/src/kmod.rs b/src/kmod.rs
index d3725c3..5cf2ed2 100644
--- a/src/kmod.rs
+++ b/src/kmod.rs
@@ -102,7 +102,11 @@
     /// See [`man delete_module(2)`](https://man7.org/linux/man-pages/man2/delete_module.2.html)
     /// for a detailed description how these flags work.
     pub struct DeleteModuleFlags: libc::c_int {
+        /// `delete_module` will return immediately, with an error, if the module has a nonzero
+        /// reference count.
         O_NONBLOCK;
+        /// `delete_module` will unload the module immediately, regardless of whether it has a
+        /// nonzero reference count.
         O_TRUNC;
     }
 );
diff --git a/src/lib.rs b/src/lib.rs
index af0c67b..dffac29 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,6 +12,7 @@
 //! * `dir` - Stuff relating to directory iteration
 //! * `env` - Manipulate environment variables
 //! * `event` - Event-driven APIs, like `kqueue` and `epoll`
+//! * `fanotify` - Linux's `fanotify` filesystem events monitoring API
 //! * `feature` - Query characteristics of the OS at runtime
 //! * `fs` - File system functionality
 //! * `hostname` - Get and set the system's hostname
@@ -41,7 +42,6 @@
 //! * `zerocopy` - APIs like `sendfile` and `copy_file_range`
 #![crate_name = "nix"]
 #![cfg(unix)]
-#![cfg_attr(docsrs, doc(cfg(all())))]
 #![allow(non_camel_case_types)]
 #![cfg_attr(test, deny(warnings))]
 #![recursion_limit = "500"]
@@ -54,6 +54,7 @@
         feature = "dir",
         feature = "env",
         feature = "event",
+        feature = "fanotify",
         feature = "feature",
         feature = "fs",
         feature = "hostname",
@@ -90,6 +91,7 @@
 #![warn(missing_docs)]
 #![cfg_attr(docsrs, feature(doc_cfg))]
 #![deny(clippy::cast_ptr_alignment)]
+#![deny(unsafe_op_in_unsafe_fn)]
 
 // Re-exported external crates
 pub use libc;
@@ -116,42 +118,29 @@
     #[deny(missing_docs)]
     pub mod features;
 }
-#[allow(missing_docs)]
 pub mod fcntl;
 feature! {
     #![feature = "net"]
 
-    #[cfg(any(target_os = "android",
-              target_os = "dragonfly",
-              target_os = "freebsd",
-              target_os = "ios",
-              target_os = "linux",
-              target_os = "macos",
-              target_os = "netbsd",
-              target_os = "illumos",
-              target_os = "openbsd"))]
+    #[cfg(any(linux_android,
+              bsd,
+              solarish))]
     #[deny(missing_docs)]
     pub mod ifaddrs;
     #[cfg(not(target_os = "redox"))]
     #[deny(missing_docs)]
     pub mod net;
 }
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 feature! {
     #![feature = "kmod"]
-    #[allow(missing_docs)]
     pub mod kmod;
 }
 feature! {
     #![feature = "mount"]
     pub mod mount;
 }
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "netbsd"
-))]
+#[cfg(any(freebsdlike, target_os = "linux", target_os = "netbsd"))]
 feature! {
     #![feature = "mqueue"]
     pub mod mqueue;
@@ -173,7 +162,6 @@
 pub mod sys;
 feature! {
     #![feature = "time"]
-    #[allow(missing_docs)]
     pub mod time;
 }
 // This can be implemented for other platforms as soon as libc
@@ -192,9 +180,11 @@
     #[allow(missing_docs)]
     pub mod ucontext;
 }
-#[allow(missing_docs)]
 pub mod unistd;
 
+#[cfg(any(feature = "poll", feature = "event"))]
+mod poll_timeout;
+
 use std::ffi::{CStr, CString, OsStr};
 use std::mem::MaybeUninit;
 use std::os::unix::ffi::OsStrExt;
@@ -311,7 +301,7 @@
         }
 
         let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit();
-        let buf_ptr = buf.as_mut_ptr() as *mut u8;
+        let buf_ptr = buf.as_mut_ptr().cast();
 
         unsafe {
             ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len());
diff --git a/src/macros.rs b/src/macros.rs
index adff2bc..3010a1a 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -27,9 +27,9 @@
 ///         /// PROT_WRITE enables write protect
 ///         PROT_WRITE;
 ///         PROT_EXEC;
-///         #[cfg(any(target_os = "linux", target_os = "android"))]
+///         #[cfg(linux_android)]
 ///         PROT_GROWSDOWN;
-///         #[cfg(any(target_os = "linux", target_os = "android"))]
+///         #[cfg(linux_android)]
 ///         PROT_GROWSUP;
 ///     }
 /// }
@@ -89,9 +89,9 @@
 ///         PROT_READ,
 ///         PROT_WRITE,
 ///         PROT_EXEC,
-///         #[cfg(any(target_os = "linux", target_os = "android"))]
+///         #[cfg(linux_android)]
 ///         PROT_GROWSDOWN,
-///         #[cfg(any(target_os = "linux", target_os = "android"))]
+///         #[cfg(linux_android)]
 ///         PROT_GROWSUP,
 ///     }
 /// }
diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs
index 6ed2dc7..248e0ab 100644
--- a/src/mount/bsd.rs
+++ b/src/mount/bsd.rs
@@ -17,36 +17,29 @@
     pub struct MntFlags: c_int {
         /// ACL support enabled.
         #[cfg(any(target_os = "netbsd", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MNT_ACLS;
         /// All I/O to the file system should be done asynchronously.
         MNT_ASYNC;
         /// dir should instead be a file system ID encoded as “FSID:val0:val1”.
         #[cfg(target_os = "freebsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MNT_BYFSID;
         /// Force a read-write mount even if the file system appears to be
         /// unclean.
         MNT_FORCE;
         /// GEOM journal support enabled.
         #[cfg(target_os = "freebsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MNT_GJOURNAL;
         /// MAC support for objects.
-        #[cfg(any(target_os = "macos", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(apple_targets, target_os = "freebsd"))]
         MNT_MULTILABEL;
         /// Disable read clustering.
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         MNT_NOCLUSTERR;
         /// Disable write clustering.
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         MNT_NOCLUSTERW;
         /// Enable NFS version 4 ACLs.
         #[cfg(target_os = "freebsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MNT_NFS4ACLS;
         /// Do not update access times.
         MNT_NOATIME;
@@ -55,8 +48,7 @@
         /// Do not honor setuid or setgid bits on files when executing them.
         MNT_NOSUID;
         /// Do not follow symlinks.
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         MNT_NOSYMFOLLOW;
         /// Mount read-only.
         MNT_RDONLY;
@@ -66,39 +58,29 @@
         /// Create a snapshot of the file system.
         ///
         /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs)
-        #[cfg(any(target_os = "macos", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(apple_targets, target_os = "freebsd"))]
         MNT_SNAPSHOT;
         /// Using soft updates.
-        #[cfg(any(
-                target_os = "dragonfly",
-                target_os = "freebsd",
-                target_os = "netbsd",
-                target_os = "openbsd"
-        ))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(freebsdlike, netbsdlike))]
         MNT_SOFTDEP;
         /// Directories with the SUID bit set chown new files to their own
         /// owner.
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         MNT_SUIDDIR;
         /// All I/O to the file system should be done synchronously.
         MNT_SYNCHRONOUS;
         /// Union with underlying fs.
         #[cfg(any(
-                target_os = "macos",
+                apple_targets,
                 target_os = "freebsd",
                 target_os = "netbsd"
         ))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MNT_UNION;
         /// Indicates that the mount command is being applied to an already
         /// mounted file system.
         MNT_UPDATE;
         /// Check vnode use counts.
         #[cfg(target_os = "freebsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MNT_NONBUSY;
     }
 );
@@ -198,7 +180,6 @@
 /// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount)
 /// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs)
 #[cfg(target_os = "freebsd")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 #[derive(Debug, Default)]
 pub struct Nmount<'a> {
     // n.b. notgull: In reality, this is a list that contains
@@ -210,12 +191,11 @@
 }
 
 #[cfg(target_os = "freebsd")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 impl<'a> Nmount<'a> {
     /// Helper function to push a slice onto the `iov` array.
     fn push_slice(&mut self, val: &'a [u8], is_owned: bool) {
         self.iov.push(libc::iovec {
-            iov_base: val.as_ptr() as *mut _,
+            iov_base: val.as_ptr().cast_mut().cast(),
             iov_len: val.len(),
         });
         self.is_owned.push(is_owned);
@@ -386,7 +366,7 @@
         // SAFETY: we are pushing a mutable iovec here, so we can't use
         //         the above method
         self.iov.push(libc::iovec {
-            iov_base: errmsg.as_mut_ptr() as *mut c_void,
+            iov_base: errmsg.as_mut_ptr().cast(),
             iov_len: errmsg.len(),
         });
 
@@ -396,13 +376,10 @@
         match Errno::result(res) {
             Ok(_) => Ok(()),
             Err(error) => {
-                let errmsg = match errmsg.iter().position(|&x| x == 0) {
-                    None => None,
-                    Some(0) => None,
-                    Some(n) => {
-                        let sl = &errmsg[0..n + 1];
-                        Some(CStr::from_bytes_with_nul(sl).unwrap())
-                    }
+                let errmsg = if errmsg[0] == 0 {
+                    None
+                } else {
+                    CStr::from_bytes_until_nul(&errmsg[..]).ok()
                 };
                 Err(NmountError::new(error, errmsg))
             }
diff --git a/src/mount/linux.rs b/src/mount/linux.rs
index e987603..aa166bc 100644
--- a/src/mount/linux.rs
+++ b/src/mount/linux.rs
@@ -85,7 +85,7 @@
         MNT_DETACH;
         /// Mark the mount point as expired.
         MNT_EXPIRE;
-        /// Don't dereference `target` if it is a symlink.  
+        /// Don't dereference `target` if it is a symlink.
         UMOUNT_NOFOLLOW;
     }
 );
diff --git a/src/mount/mod.rs b/src/mount/mod.rs
index e98b49c..8caf27f 100644
--- a/src/mount/mod.rs
+++ b/src/mount/mod.rs
@@ -1,26 +1,12 @@
 //! Mount file systems
-#[cfg(any(target_os = "android", target_os = "linux"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+#[cfg(linux_android)]
 mod linux;
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 pub use self::linux::*;
 
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd"
-))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+#[cfg(bsd)]
 mod bsd;
 
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd"
-))]
+#[cfg(bsd)]
 pub use self::bsd::*;
diff --git a/src/mqueue.rs b/src/mqueue.rs
index fb07d2a..7f9d687 100644
--- a/src/mqueue.rs
+++ b/src/mqueue.rs
@@ -35,7 +35,7 @@
 use crate::Result;
 
 use crate::sys::stat::Mode;
-use libc::{self, c_char, mqd_t, size_t};
+use libc::{self, mqd_t, size_t};
 use std::mem;
 #[cfg(any(
     target_os = "linux",
@@ -88,11 +88,9 @@
 // See https://sourceware.org/bugzilla/show_bug.cgi?id=21279
 /// Size of a message queue attribute member
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub type mq_attr_member_t = i64;
 /// Size of a message queue attribute member
 #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub type mq_attr_member_t = libc::c_long;
 
 impl MqAttr {
@@ -205,7 +203,7 @@
     let res = unsafe {
         libc::mq_receive(
             mqdes.0,
-            message.as_mut_ptr() as *mut c_char,
+            message.as_mut_ptr().cast(),
             len,
             msg_prio as *mut u32,
         )
@@ -229,7 +227,7 @@
         let res = unsafe {
             libc::mq_timedreceive(
                 mqdes.0,
-                message.as_mut_ptr() as *mut c_char,
+                message.as_mut_ptr().cast(),
                 len,
                 msg_prio as *mut u32,
                 abstime.as_ref(),
@@ -244,12 +242,7 @@
 /// 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().cast(), message.len(), msq_prio)
     };
     Errno::result(res).map(drop)
 }
diff --git a/src/net/if_.rs b/src/net/if_.rs
index ec46260..c66b5dc 100644
--- a/src/net/if_.rs
+++ b/src/net/if_.rs
@@ -3,9 +3,17 @@
 //! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
 //! or "socan1" into device numbers.
 
+use std::fmt;
 use crate::{Error, NixPath, Result};
 use libc::c_uint;
 
+#[cfg(not(solarish))]
+/// type alias for InterfaceFlags
+pub type IflagsType = libc::c_int;
+#[cfg(solarish)]
+/// type alias for InterfaceFlags
+pub type IflagsType = libc::c_longlong;
+
 /// Resolve an interface into a interface number.
 pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> {
     let if_index = name
@@ -20,323 +28,236 @@
 
 libc_bitflags!(
     /// Standard interface flags, used by `getifaddrs`
-    pub struct InterfaceFlags: libc::c_int {
+    pub struct InterfaceFlags: IflagsType {
+    
         /// Interface is running. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        IFF_UP;
+        IFF_UP as IflagsType;
         /// Valid broadcast address set. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        IFF_BROADCAST;
+        IFF_BROADCAST as IflagsType;
         /// Internal debugging flag. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
         #[cfg(not(target_os = "haiku"))]
-        IFF_DEBUG;
+        IFF_DEBUG as IflagsType;
         /// Interface is a loopback interface. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        IFF_LOOPBACK;
+        IFF_LOOPBACK as IflagsType;
         /// Interface is a point-to-point link. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        IFF_POINTOPOINT;
+        IFF_POINTOPOINT as IflagsType;
         /// Avoid use of trailers. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        #[cfg(any(target_os = "android",
+        #[cfg(any(
+                  linux_android,
+                  solarish,
+                  apple_targets,
                   target_os = "fuchsia",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "illumos",
-                  target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_NOTRAILERS;
+                  target_os = "netbsd"))]
+        IFF_NOTRAILERS as IflagsType;
         /// Interface manages own routes.
         #[cfg(any(target_os = "dragonfly"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_SMART;
+        IFF_SMART as IflagsType;
         /// Resources allocated. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        #[cfg(any(target_os = "android",
-                  target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "fuchsia",
-                  target_os = "illumos",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd",
-                  target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_RUNNING;
+        #[cfg(any(
+                  linux_android,
+                  bsd,
+                  solarish,
+                  target_os = "fuchsia"))]
+        IFF_RUNNING as IflagsType;
         /// No arp protocol, L2 destination address not set. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        IFF_NOARP;
+        IFF_NOARP as IflagsType;
         /// Interface is in promiscuous mode. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        IFF_PROMISC;
+        IFF_PROMISC as IflagsType;
         /// Receive all multicast packets. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        IFF_ALLMULTI;
+        IFF_ALLMULTI as IflagsType;
         /// Master of a load balancing bundle. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         IFF_MASTER;
         /// transmission in progress, tx hardware queue is full
-        #[cfg(any(target_os = "freebsd",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd",
-                  target_os = "ios"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(target_os = "freebsd", apple_targets, netbsdlike))]
         IFF_OACTIVE;
         /// Protocol code on board.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_INTELLIGENT;
+        #[cfg(solarish)]
+        IFF_INTELLIGENT as IflagsType;
         /// Slave of a load balancing bundle. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         IFF_SLAVE;
         /// Can't hear own transmissions.
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         IFF_SIMPLEX;
         /// Supports multicast. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        IFF_MULTICAST;
+        IFF_MULTICAST as IflagsType;
         /// Per link layer defined bit.
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd",
-                  target_os = "ios"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         IFF_LINK0;
         /// Multicast using broadcast.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_MULTI_BCAST;
+        #[cfg(solarish)]
+        IFF_MULTI_BCAST as IflagsType;
         /// Is able to select media type via ifmap. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         IFF_PORTSEL;
         /// Per link layer defined bit.
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd",
-                  target_os = "ios"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         IFF_LINK1;
         /// Non-unique address.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_UNNUMBERED;
+        #[cfg(solarish)]
+        IFF_UNNUMBERED as IflagsType;
         /// Auto media selection active. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         IFF_AUTOMEDIA;
         /// Per link layer defined bit.
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd",
-                  target_os = "ios"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         IFF_LINK2;
         /// Use alternate physical connection.
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "macos",
-                  target_os = "ios"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(freebsdlike, apple_targets))]
         IFF_ALTPHYS;
         /// DHCP controls interface.
-        #[cfg(any(target_os = "solaris", target_os = "illumos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_DHCPRUNNING;
+        #[cfg(solarish)]
+        IFF_DHCPRUNNING as IflagsType;
         /// The addresses are lost when the interface goes down. (see
         /// [`netdevice(7)`](https://man7.org/linux/man-pages/man7/netdevice.7.html))
-        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
         IFF_DYNAMIC;
         /// Do not advertise.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_PRIVATE;
+        #[cfg(solarish)]
+        IFF_PRIVATE as IflagsType;
         /// Driver signals L1 up. Volatile.
         #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         IFF_LOWER_UP;
         /// Interface is in polling mode.
         #[cfg(any(target_os = "dragonfly"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         IFF_POLLING_COMPAT;
         /// Unconfigurable using ioctl(2).
         #[cfg(any(target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         IFF_CANTCONFIG;
         /// Do not transmit packets.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_NOXMIT;
+        #[cfg(solarish)]
+        IFF_NOXMIT as IflagsType;
         /// Driver signals dormant. Volatile.
         #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         IFF_DORMANT;
         /// User-requested promisc mode.
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         IFF_PPROMISC;
         /// Just on-link subnet.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_NOLOCAL;
+        #[cfg(solarish)]
+        IFF_NOLOCAL as IflagsType;
         /// Echo sent packets. Volatile.
         #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         IFF_ECHO;
         /// User-requested monitor mode.
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         IFF_MONITOR;
         /// Address is deprecated.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_DEPRECATED;
+        #[cfg(solarish)]
+        IFF_DEPRECATED as IflagsType;
         /// Static ARP.
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         IFF_STATICARP;
         /// Address from stateless addrconf.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_ADDRCONF;
+        #[cfg(solarish)]
+        IFF_ADDRCONF as IflagsType;
         /// Interface is in polling mode.
         #[cfg(any(target_os = "dragonfly"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         IFF_NPOLLING;
         /// Router on interface.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_ROUTER;
+        #[cfg(solarish)]
+        IFF_ROUTER as IflagsType;
         /// Interface is in polling mode.
         #[cfg(any(target_os = "dragonfly"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         IFF_IDIRECT;
         /// Interface is winding down
         #[cfg(any(target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         IFF_DYING;
         /// No NUD on interface.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_NONUD;
+        #[cfg(solarish)]
+        IFF_NONUD as IflagsType;
         /// Interface is being renamed
         #[cfg(any(target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         IFF_RENAMING;
         /// Anycast address.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_ANYCAST;
+        #[cfg(solarish)]
+        IFF_ANYCAST as IflagsType;
         /// Don't exchange routing info.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_NORTEXCH;
+        #[cfg(solarish)]
+        IFF_NORTEXCH as IflagsType;
         /// Do not provide packet information
-        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_NO_PI as libc::c_int;
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
+        IFF_NO_PI as IflagsType;
         /// TUN device (no Ethernet headers)
-        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_TUN as libc::c_int;
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
+        IFF_TUN as IflagsType;
         /// TAP device
-        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_TAP as libc::c_int;
+        #[cfg(any(linux_android, target_os = "fuchsia"))]
+        IFF_TAP as IflagsType;
         /// IPv4 interface.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_IPV4;
+        #[cfg(solarish)]
+        IFF_IPV4 as IflagsType;
         /// IPv6 interface.
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_IPV6;
+        #[cfg(solarish)]
+        IFF_IPV6 as IflagsType;
         /// in.mpathd test address
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_NOFAILOVER;
+        #[cfg(solarish)]
+        IFF_NOFAILOVER as IflagsType;
         /// Interface has failed
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_FAILED;
+        #[cfg(solarish)]
+        IFF_FAILED as IflagsType;
         /// Interface is a hot-spare
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_STANDBY;
+        #[cfg(solarish)]
+        IFF_STANDBY as IflagsType;
         /// Functioning but not used
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_INACTIVE;
+        #[cfg(solarish)]
+        IFF_INACTIVE as IflagsType;
         /// Interface is offline
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_OFFLINE;
-        #[cfg(target_os = "solaris")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_COS_ENABLED;
-        /// Prefer as source addr.
-        #[cfg(target_os = "solaris")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_PREFERRED;
+        #[cfg(solarish)]
+        IFF_OFFLINE as IflagsType;
+        /// Has CoS marking supported
+        #[cfg(solarish)]
+        IFF_COS_ENABLED as IflagsType;
+        /// Prefer as source addr
+        #[cfg(solarish)]
+        IFF_PREFERRED as IflagsType;
         /// RFC3041
-        #[cfg(target_os = "solaris")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_TEMPORARY;
-        /// MTU set with SIOCSLIFMTU
-        #[cfg(target_os = "solaris")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_FIXEDMTU;
-        /// Cannot send / receive packets
-        #[cfg(target_os = "solaris")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_VIRTUAL;
+        #[cfg(solarish)]
+        IFF_TEMPORARY as IflagsType;
+        /// MTU set
+        #[cfg(solarish)]
+        IFF_FIXEDMTU as IflagsType;
+        /// Cannot send/receive packets
+        #[cfg(solarish)]
+        IFF_VIRTUAL as IflagsType;
         /// Local address in use
-        #[cfg(target_os = "solaris")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_DUPLICATE;
+        #[cfg(solarish)]
+        IFF_DUPLICATE as IflagsType;
         /// IPMP IP interface
-        #[cfg(target_os = "solaris")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        IFF_IPMP;
+        #[cfg(solarish)]
+        IFF_IPMP as IflagsType;
     }
 );
 
+impl fmt::Display for InterfaceFlags {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        bitflags::parser::to_writer(self, f)
+    }
+}
+
+
 #[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
+    bsd,
     target_os = "fuchsia",
-    target_os = "ios",
     target_os = "linux",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd",
-    target_os = "illumos",
+    solarish,
 ))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 mod if_nameindex {
     use super::*;
 
@@ -373,6 +294,7 @@
     }
 
     /// A list of the network interfaces available on this system. Obtained from [`if_nameindex()`].
+    #[repr(transparent)]
     pub struct Interfaces {
         ptr: NonNull<libc::if_nameindex>,
     }
@@ -388,7 +310,7 @@
         /// null-terminated, so calling this calculates the length. If random access isn't needed,
         /// [`Interfaces::iter()`] should be used instead.
         pub fn to_slice(&self) -> &[Interface] {
-            let ifs = self.ptr.as_ptr() as *const Interface;
+            let ifs = self.ptr.as_ptr().cast();
             let len = self.iter().count();
             unsafe { std::slice::from_raw_parts(ifs, len) }
         }
@@ -458,14 +380,9 @@
     }
 }
 #[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
+    bsd,
     target_os = "fuchsia",
-    target_os = "ios",
     target_os = "linux",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd",
-    target_os = "illumos",
+    solarish,
 ))]
 pub use if_nameindex::*;
diff --git a/src/poll.rs b/src/poll.rs
index 9181bf7..0ad9f40 100644
--- a/src/poll.rs
+++ b/src/poll.rs
@@ -2,6 +2,7 @@
 use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd};
 
 use crate::errno::Errno;
+pub use crate::poll_timeout::PollTimeout;
 use crate::Result;
 
 /// This is a wrapper around `libc::pollfd`.
@@ -22,24 +23,35 @@
 impl<'fd> PollFd<'fd> {
     /// Creates a new `PollFd` specifying the events of interest
     /// for a given file descriptor.
-    //
-    // Different from other I/O-safe interfaces, here, we have to take `AsFd`
-    // by reference to prevent the case where the `fd` is closed but it is
-    // still in use. For example:
+    ///
+    /// # Examples
+    /// ```no_run
+    /// # use std::os::unix::io::{AsFd, AsRawFd, FromRawFd};
+    /// # use nix::{
+    /// #     poll::{PollTimeout, PollFd, PollFlags, poll},
+    /// #     unistd::{pipe, read}
+    /// # };
+    /// let (r, w) = pipe().unwrap();
+    /// let pfd = PollFd::new(r.as_fd(), PollFlags::POLLIN);
+    /// let mut fds = [pfd];
+    /// poll(&mut fds, PollTimeout::NONE).unwrap();
+    /// let mut buf = [0u8; 80];
+    /// read(r.as_raw_fd(), &mut buf[..]);
+    /// ```
+    // Unlike I/O functions, constructors like this must take `BorrowedFd`
+    // instead of AsFd or &AsFd.  Otherwise, an `OwnedFd` argument would be
+    // dropped at the end of the method, leaving the structure referencing a
+    // closed file descriptor.  For example:
     //
     // ```rust
-    // let (reader, _) = pipe().unwrap();
-    //
-    // // If `PollFd::new()` takes `AsFd` by value, then `reader` will be consumed,
-    // // but the file descriptor of `reader` will still be in use.
-    // let pollfd = PollFd::new(reader, flag);
-    //
+    // let (r, _) = pipe().unwrap();
+    // let pollfd = PollFd::new(r, flag);  // Drops the OwnedFd
     // // Do something with `pollfd`, which uses the CLOSED fd.
     // ```
-    pub fn new<Fd: AsFd>(fd: &'fd Fd, events: PollFlags) -> PollFd<'fd> {
+    pub fn new(fd: BorrowedFd<'fd>, events: PollFlags) -> PollFd<'fd> {
         PollFd {
             pollfd: libc::pollfd {
-                fd: fd.as_fd().as_raw_fd(),
+                fd: fd.as_raw_fd(),
                 events: events.bits(),
                 revents: PollFlags::empty().bits(),
             },
@@ -133,19 +145,15 @@
         POLLOUT;
         /// Equivalent to [`POLLIN`](constant.POLLIN.html)
         #[cfg(not(target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         POLLRDNORM;
         #[cfg(not(target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         /// Equivalent to [`POLLOUT`](constant.POLLOUT.html)
         POLLWRNORM;
         /// Priority band data can be read (generally unused on Linux).
         #[cfg(not(target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         POLLRDBAND;
         /// Priority data may be written.
         #[cfg(not(target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         POLLWRBAND;
         /// Error condition (only returned in
         /// [`PollFd::revents`](struct.PollFd.html#method.revents);
@@ -184,16 +192,19 @@
 ///
 /// Note that the timeout interval will be rounded up to the system clock
 /// granularity, and kernel scheduling delays mean that the blocking
-/// interval may overrun by a small amount.  Specifying a negative value
-/// in timeout means an infinite timeout.  Specifying a timeout of zero
-/// causes `poll()` to return immediately, even if no file descriptors are
-/// ready.
-pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> {
+/// interval may overrun by a small amount.  Specifying a [`PollTimeout::NONE`]
+/// in timeout means an infinite timeout.  Specifying a timeout of
+/// [`PollTimeout::ZERO`] causes `poll()` to return immediately, even if no file
+/// descriptors are ready.
+pub fn poll<T: Into<PollTimeout>>(
+    fds: &mut [PollFd],
+    timeout: T,
+) -> Result<libc::c_int> {
     let res = unsafe {
         libc::poll(
-            fds.as_mut_ptr() as *mut libc::pollfd,
+            fds.as_mut_ptr().cast(),
             fds.len() as libc::nfds_t,
-            timeout,
+            i32::from(timeout.into()),
         )
     };
 
@@ -213,7 +224,7 @@
 /// so in that case `ppoll` differs from `poll` only in the precision of the
 /// timeout argument.
 ///
-#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, freebsdlike))]
 pub fn ppoll(
     fds: &mut [PollFd],
     timeout: Option<crate::sys::time::TimeSpec>,
@@ -223,7 +234,7 @@
     let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
     let sigmask = sigmask.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
     let res = unsafe {
-        libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd,
+        libc::ppoll(fds.as_mut_ptr().cast(),
                     fds.len() as libc::nfds_t,
                     timeout,
                     sigmask)
diff --git a/src/poll_timeout.rs b/src/poll_timeout.rs
new file mode 100644
index 0000000..f7d9015
--- /dev/null
+++ b/src/poll_timeout.rs
@@ -0,0 +1,224 @@
+use std::time::Duration;
+
+/// PollTimeout argument for polling.
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
+pub struct PollTimeout(i32);
+
+impl PollTimeout {
+    /// Blocks indefinitely.
+    ///
+    /// > Specifying a negative value in timeout means an infinite timeout.
+    pub const NONE: Self = Self(-1);
+    /// Returns immediately.
+    ///
+    /// > Specifying a timeout of zero causes poll() to return immediately, even if no file
+    /// > descriptors are ready.
+    pub const ZERO: Self = Self(0);
+    /// Blocks for at most [`i32::MAX`] milliseconds.
+    pub const MAX: Self = Self(i32::MAX);
+    /// Returns if `self` equals [`PollTimeout::NONE`].
+    pub fn is_none(&self) -> bool {
+        // > Specifying a negative value in timeout means an infinite timeout.
+        *self <= Self::NONE
+    }
+    /// Returns if `self` does not equal [`PollTimeout::NONE`].
+    pub fn is_some(&self) -> bool {
+        !self.is_none()
+    }
+    /// Returns the timeout in milliseconds if there is some, otherwise returns `None`.
+    pub fn as_millis(&self) -> Option<u32> {
+        self.is_some().then_some(u32::try_from(self.0).unwrap())
+    }
+    /// Returns the timeout as a `Duration` if there is some, otherwise returns `None`.
+    pub fn duration(&self) -> Option<Duration> {
+        self.as_millis()
+            .map(|x| Duration::from_millis(u64::from(x)))
+    }
+}
+
+/// Error type for integer conversions into `PollTimeout`.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum PollTimeoutTryFromError {
+    /// Passing a value less than -1 is invalid on some systems, see
+    /// <https://man.freebsd.org/cgi/man.cgi?poll#end>.
+    TooNegative,
+    /// Passing a value greater than `i32::MAX` is invalid.
+    TooPositive,
+}
+
+impl std::fmt::Display for PollTimeoutTryFromError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::TooNegative => write!(f, "Passed a negative timeout less than -1."),
+            Self::TooPositive => write!(f, "Passed a positive timeout greater than `i32::MAX` milliseconds.")
+        }
+    }
+}
+
+impl std::error::Error for PollTimeoutTryFromError {}
+
+impl<T: Into<PollTimeout>> From<Option<T>> for PollTimeout {
+    fn from(x: Option<T>) -> Self {
+        x.map_or(Self::NONE, |x| x.into())
+    }
+}
+impl TryFrom<Duration> for PollTimeout {
+    type Error = PollTimeoutTryFromError;
+    fn try_from(x: Duration) -> std::result::Result<Self, Self::Error> {
+        Ok(Self(
+            i32::try_from(x.as_millis())
+                .map_err(|_| PollTimeoutTryFromError::TooPositive)?,
+        ))
+    }
+}
+impl TryFrom<u128> for PollTimeout {
+    type Error = PollTimeoutTryFromError;
+    fn try_from(x: u128) -> std::result::Result<Self, Self::Error> {
+        Ok(Self(
+            i32::try_from(x)
+                .map_err(|_| PollTimeoutTryFromError::TooPositive)?,
+        ))
+    }
+}
+impl TryFrom<u64> for PollTimeout {
+    type Error = PollTimeoutTryFromError;
+    fn try_from(x: u64) -> std::result::Result<Self, Self::Error> {
+        Ok(Self(
+            i32::try_from(x)
+                .map_err(|_| PollTimeoutTryFromError::TooPositive)?,
+        ))
+    }
+}
+impl TryFrom<u32> for PollTimeout {
+    type Error = PollTimeoutTryFromError;
+    fn try_from(x: u32) -> std::result::Result<Self, Self::Error> {
+        Ok(Self(
+            i32::try_from(x)
+                .map_err(|_| PollTimeoutTryFromError::TooPositive)?,
+        ))
+    }
+}
+impl From<u16> for PollTimeout {
+    fn from(x: u16) -> Self {
+        Self(i32::from(x))
+    }
+}
+impl From<u8> for PollTimeout {
+    fn from(x: u8) -> Self {
+        Self(i32::from(x))
+    }
+}
+impl TryFrom<i128> for PollTimeout {
+    type Error = PollTimeoutTryFromError;
+    fn try_from(x: i128) -> std::result::Result<Self, Self::Error> {
+        match x {
+            ..=-2 => Err(PollTimeoutTryFromError::TooNegative),
+            -1.. => Ok(Self(
+                i32::try_from(x)
+                    .map_err(|_| PollTimeoutTryFromError::TooPositive)?,
+            )),
+        }
+    }
+}
+impl TryFrom<i64> for PollTimeout {
+    type Error = PollTimeoutTryFromError;
+    fn try_from(x: i64) -> std::result::Result<Self, Self::Error> {
+        match x {
+            ..=-2 => Err(PollTimeoutTryFromError::TooNegative),
+            -1.. => Ok(Self(
+                i32::try_from(x)
+                    .map_err(|_| PollTimeoutTryFromError::TooPositive)?,
+            )),
+        }
+    }
+}
+impl TryFrom<i32> for PollTimeout {
+    type Error = PollTimeoutTryFromError;
+    fn try_from(x: i32) -> std::result::Result<Self, Self::Error> {
+        match x {
+            ..=-2 => Err(PollTimeoutTryFromError::TooNegative),
+            -1.. => Ok(Self(x)),
+        }
+    }
+}
+impl TryFrom<i16> for PollTimeout {
+    type Error = PollTimeoutTryFromError;
+    fn try_from(x: i16) -> std::result::Result<Self, Self::Error> {
+        match x {
+            ..=-2 => Err(PollTimeoutTryFromError::TooNegative),
+            -1.. => Ok(Self(i32::from(x))),
+        }
+    }
+}
+impl TryFrom<i8> for PollTimeout {
+    type Error = PollTimeoutTryFromError;
+    fn try_from(x: i8) -> std::result::Result<Self, Self::Error> {
+        match x {
+            ..=-2 => Err(PollTimeoutTryFromError::TooNegative),
+            -1.. => Ok(Self(i32::from(x))),
+        }
+    }
+}
+impl TryFrom<PollTimeout> for Duration {
+    type Error = ();
+    fn try_from(x: PollTimeout) -> std::result::Result<Self, ()> {
+        x.duration().ok_or(())
+    }
+}
+impl TryFrom<PollTimeout> for u128 {
+    type Error = <Self as TryFrom<i32>>::Error;
+    fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
+        Self::try_from(x.0)
+    }
+}
+impl TryFrom<PollTimeout> for u64 {
+    type Error = <Self as TryFrom<i32>>::Error;
+    fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
+        Self::try_from(x.0)
+    }
+}
+impl TryFrom<PollTimeout> for u32 {
+    type Error = <Self as TryFrom<i32>>::Error;
+    fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
+        Self::try_from(x.0)
+    }
+}
+impl TryFrom<PollTimeout> for u16 {
+    type Error = <Self as TryFrom<i32>>::Error;
+    fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
+        Self::try_from(x.0)
+    }
+}
+impl TryFrom<PollTimeout> for u8 {
+    type Error = <Self as TryFrom<i32>>::Error;
+    fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
+        Self::try_from(x.0)
+    }
+}
+impl From<PollTimeout> for i128 {
+    fn from(x: PollTimeout) -> Self {
+        Self::from(x.0)
+    }
+}
+impl From<PollTimeout> for i64 {
+    fn from(x: PollTimeout) -> Self {
+        Self::from(x.0)
+    }
+}
+impl From<PollTimeout> for i32 {
+    fn from(x: PollTimeout) -> Self {
+        x.0
+    }
+}
+impl TryFrom<PollTimeout> for i16 {
+    type Error = <Self as TryFrom<i32>>::Error;
+    fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
+        Self::try_from(x.0)
+    }
+}
+impl TryFrom<PollTimeout> for i8 {
+    type Error = <Self as TryFrom<i32>>::Error;
+    fn try_from(x: PollTimeout) -> std::result::Result<Self, Self::Error> {
+        Self::try_from(x.0)
+    }
+}
diff --git a/src/pty.rs b/src/pty.rs
index 455828b..74f8ecf 100644
--- a/src/pty.rs
+++ b/src/pty.rs
@@ -71,7 +71,7 @@
 
 impl io::Write for PtyMaster {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from)
+        unistd::write(&self.0, buf).map_err(io::Error::from)
     }
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
@@ -86,7 +86,7 @@
 
 impl io::Write for &PtyMaster {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from)
+        unistd::write(&self.0, buf).map_err(io::Error::from)
     }
     fn flush(&mut self) -> io::Result<()> {
         Ok(())
@@ -169,12 +169,12 @@
 /// For a threadsafe and non-`unsafe` alternative on Linux, see `ptsname_r()`.
 #[inline]
 pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> {
-    let name_ptr = libc::ptsname(fd.as_raw_fd());
+    let name_ptr = unsafe { libc::ptsname(fd.as_raw_fd()) };
     if name_ptr.is_null() {
         return Err(Errno::last());
     }
 
-    let name = CStr::from_ptr(name_ptr);
+    let name = unsafe { CStr::from_ptr(name_ptr) };
     Ok(name.to_string_lossy().into_owned())
 }
 
@@ -187,8 +187,7 @@
 ///
 /// This value is useful for opening the slave ptty once the master has already been opened with
 /// `posix_openpt()`.
-#[cfg(any(target_os = "android", target_os = "linux"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+#[cfg(linux_android)]
 #[inline]
 pub fn ptsname_r(fd: &PtyMaster) -> Result<String> {
     let mut name_buf = Vec::<libc::c_char>::with_capacity(64);
@@ -342,7 +341,7 @@
         .map(|ws| ws as *const Winsize as *mut _)
         .unwrap_or(ptr::null_mut());
 
-    let res = libc::forkpty(master.as_mut_ptr(), ptr::null_mut(), term, win);
+    let res = unsafe { libc::forkpty(master.as_mut_ptr(), ptr::null_mut(), term, win) };
 
     let fork_result = Errno::result(res).map(|res| match res {
         0 => ForkResult::Child,
@@ -350,7 +349,7 @@
     })?;
 
     Ok(ForkptyResult {
-        master: OwnedFd::from_raw_fd(master.assume_init()),
+        master: unsafe { OwnedFd::from_raw_fd( master.assume_init() ) },
         fork_result,
     })
 }
diff --git a/src/sched.rs b/src/sched.rs
index c9d5d6d..d76d558 100644
--- a/src/sched.rs
+++ b/src/sched.rs
@@ -4,11 +4,10 @@
 //! [sched.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sched.h.html)
 use crate::{Errno, Result};
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 pub use self::sched_linux_like::*;
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+#[cfg(linux_android)]
 mod sched_linux_like {
     use crate::errno::Errno;
     use crate::unistd::Pid;
@@ -117,17 +116,19 @@
         }
 
         let combined = flags.bits() | signal.unwrap_or(0);
-        let ptr = stack.as_mut_ptr().add(stack.len());
-        let ptr_aligned = ptr.sub(ptr as usize % 16);
-        let res = libc::clone(
-            mem::transmute(
-                callback
-                    as extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32,
-            ),
-            ptr_aligned as *mut c_void,
-            combined,
-            &mut cb as *mut _ as *mut c_void,
-        );
+        let res = unsafe {
+            let ptr = stack.as_mut_ptr().add(stack.len());
+            let ptr_aligned = ptr.sub(ptr as usize % 16);
+            libc::clone(
+                mem::transmute(
+                    callback
+                        as extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32,
+                ),
+                ptr_aligned as *mut c_void,
+                combined,
+                &mut cb as *mut _ as *mut c_void,
+            )
+        };
 
         Errno::result(res).map(Pid::from_raw)
     }
@@ -151,20 +152,10 @@
     }
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux"
-))]
+#[cfg(any(linux_android, freebsdlike))]
 pub use self::sched_affinity::*;
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux"
-))]
+#[cfg(any(linux_android, freebsdlike))]
 mod sched_affinity {
     use crate::errno::Errno;
     use crate::unistd::Pid;
diff --git a/src/sys/aio.rs b/src/sys/aio.rs
index 5471177..e9213c6 100644
--- a/src/sys/aio.rs
+++ b/src/sys/aio.rs
@@ -35,7 +35,7 @@
     ptr, thread,
 };
 
-use libc::{c_void, off_t};
+use libc::off_t;
 use pin_utils::unsafe_pinned;
 
 use crate::{
@@ -53,12 +53,9 @@
         /// do it like `fsync`
         O_SYNC,
         /// on supported operating systems only, do it like `fdatasync`
-        #[cfg(any(target_os = "ios",
+        #[cfg(any(apple_targets,
                   target_os = "linux",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  netbsdlike))]
         O_DSYNC
     }
     impl TryFrom<i32>
@@ -161,7 +158,7 @@
         let r = unsafe { libc::aio_error(&self.aiocb().0) };
         match r {
             0 => Ok(()),
-            num if num > 0 => Err(Errno::from_i32(num)),
+            num if num > 0 => Err(Errno::from_raw(num)),
             -1 => Err(Errno::last()),
             num => panic!("unknown aio_error return value {num:?}"),
         }
@@ -581,7 +578,7 @@
     ) -> Self {
         let mut aiocb = AioCb::common_init(fd, prio, sigev_notify);
         aiocb.aiocb.0.aio_nbytes = buf.len();
-        aiocb.aiocb.0.aio_buf = buf.as_mut_ptr() as *mut c_void;
+        aiocb.aiocb.0.aio_buf = buf.as_mut_ptr().cast();
         aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READ;
         aiocb.aiocb.0.aio_offset = offs;
         AioRead {
@@ -702,7 +699,7 @@
         // In vectored mode, aio_nbytes stores the length of the iovec array,
         // not the byte count.
         aiocb.aiocb.0.aio_nbytes = bufs.len();
-        aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr() as *mut c_void;
+        aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr().cast();
         aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READV;
         aiocb.aiocb.0.aio_offset = offs;
         AioReadv {
@@ -817,7 +814,7 @@
         // but technically its only unsafe to dereference it, not to create
         // it.  Type Safety guarantees that we'll never pass aiocb to
         // aio_read or aio_readv.
-        aiocb.aiocb.0.aio_buf = buf.as_ptr() as *mut c_void;
+        aiocb.aiocb.0.aio_buf = buf.as_ptr().cast_mut().cast();
         aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITE;
         aiocb.aiocb.0.aio_offset = offs;
         AioWrite {
@@ -935,7 +932,7 @@
         // but technically its only unsafe to dereference it, not to create
         // it.  Type Safety guarantees that we'll never pass aiocb to
         // aio_read or aio_readv.
-        aiocb.aiocb.0.aio_buf = bufs.as_ptr() as *mut c_void;
+        aiocb.aiocb.0.aio_buf = bufs.as_ptr().cast_mut().cast();
         aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITEV;
         aiocb.aiocb.0.aio_offset = offs;
         AioWritev {
@@ -1055,7 +1052,8 @@
     // generic, and accepting arguments like &[AioWrite].  But that would
     // prevent using aio_suspend to wait on a heterogeneous list of mixed
     // operations.
-    let v = list.iter()
+    let v = list
+        .iter()
         .map(|x| x.as_ref() as *const libc::aiocb)
         .collect::<Vec<*const libc::aiocb>>();
     let p = v.as_ptr();
@@ -1175,7 +1173,10 @@
 /// // notification, we know that all operations are complete.
 /// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len());
 /// ```
-#[deprecated(since = "0.27.0", note = "https://github.com/nix-rust/nix/issues/2017")]
+#[deprecated(
+    since = "0.27.0",
+    note = "https://github.com/nix-rust/nix/issues/2017"
+)]
 pub fn lio_listio(
     mode: LioMode,
     list: &mut [Pin<&mut dyn AsMut<libc::aiocb>>],
@@ -1190,56 +1191,3 @@
     })
     .map(drop)
 }
-
-#[cfg(test)]
-mod t {
-    use super::*;
-
-    /// aio_suspend relies on casting Rust Aio* struct pointers to libc::aiocb
-    /// pointers.  This test ensures that such casts are valid.
-    #[test]
-    fn casting() {
-        let sev = SigevNotify::SigevNone;
-        let aiof = AioFsync::new(666, AioFsyncMode::O_SYNC, 0, sev);
-        assert_eq!(
-            aiof.as_ref() as *const libc::aiocb,
-            &aiof as *const AioFsync as *const libc::aiocb
-        );
-
-        let mut rbuf = [];
-        let aior = AioRead::new(666, 0, &mut rbuf, 0, sev);
-        assert_eq!(
-            aior.as_ref() as *const libc::aiocb,
-            &aior as *const AioRead as *const libc::aiocb
-        );
-
-        let wbuf = [];
-        let aiow = AioWrite::new(666, 0, &wbuf, 0, sev);
-        assert_eq!(
-            aiow.as_ref() as *const libc::aiocb,
-            &aiow as *const AioWrite as *const libc::aiocb
-        );
-    }
-
-    #[cfg(target_os = "freebsd")]
-    #[test]
-    fn casting_vectored() {
-        let sev = SigevNotify::SigevNone;
-
-        let mut rbuf = [];
-        let mut rbufs = [IoSliceMut::new(&mut rbuf)];
-        let aiorv = AioReadv::new(666, 0, &mut rbufs[..], 0, sev);
-        assert_eq!(
-            aiorv.as_ref() as *const libc::aiocb,
-            &aiorv as *const AioReadv as *const libc::aiocb
-        );
-
-        let wbuf = [];
-        let wbufs = [IoSlice::new(&wbuf)];
-        let aiowv = AioWritev::new(666, 0, &wbufs, 0, sev);
-        assert_eq!(
-            aiowv.as_ref() as *const libc::aiocb,
-            &aiowv as *const AioWritev as *const libc::aiocb
-        );
-    }
-}
diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs
index 36f9c17..ec146a8 100644
--- a/src/sys/epoll.rs
+++ b/src/sys/epoll.rs
@@ -1,4 +1,5 @@
 use crate::errno::Errno;
+pub use crate::poll_timeout::PollTimeout as EpollTimeout;
 use crate::Result;
 use libc::{self, c_int};
 use std::mem;
@@ -71,32 +72,32 @@
 
 /// A safe wrapper around [`epoll`](https://man7.org/linux/man-pages/man7/epoll.7.html).
 /// ```
-/// # use nix::sys::{epoll::{Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{eventfd, EfdFlags}};
+/// # use nix::sys::{epoll::{EpollTimeout, Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{EventFd, EfdFlags}};
 /// # use nix::unistd::write;
-/// # use std::os::unix::io::{OwnedFd, FromRawFd, AsRawFd, AsFd};
+/// # use std::os::unix::io::{OwnedFd, FromRawFd, AsFd};
 /// # use std::time::{Instant, Duration};
 /// # fn main() -> nix::Result<()> {
 /// const DATA: u64 = 17;
-/// const MILLIS: u64 = 100;
+/// const MILLIS: u8 = 100;
 ///
 /// // Create epoll
 /// let epoll = Epoll::new(EpollCreateFlags::empty())?;
 ///
 /// // Create eventfd & Add event
-/// let eventfd = eventfd(0, EfdFlags::empty())?;
+/// let eventfd = EventFd::new()?;
 /// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?;
 ///
 /// // Arm eventfd & Time wait
-/// write(eventfd.as_raw_fd(), &1u64.to_ne_bytes())?;
+/// eventfd.arm()?;
 /// let now = Instant::now();
 ///
 /// // Wait on event
 /// let mut events = [EpollEvent::empty()];
-/// epoll.wait(&mut events, MILLIS as isize)?;
+/// epoll.wait(&mut events, MILLIS)?;
 ///
 /// // Assert data correct & timeout didn't occur
 /// assert_eq!(events[0].data(), DATA);
-/// assert!(now.elapsed() < Duration::from_millis(MILLIS));
+/// assert!(now.elapsed().as_millis() < MILLIS.into());
 /// # Ok(())
 /// # }
 /// ```
@@ -140,17 +141,17 @@
     /// (This can be thought of as fetching items from the ready list of the epoll instance.)
     ///
     /// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html)
-    pub fn wait(
+    pub fn wait<T: Into<EpollTimeout>>(
         &self,
         events: &mut [EpollEvent],
-        timeout: isize,
+        timeout: T,
     ) -> Result<usize> {
         let res = unsafe {
             libc::epoll_wait(
                 self.0.as_raw_fd(),
-                events.as_mut_ptr() as *mut libc::epoll_event,
+                events.as_mut_ptr().cast(),
                 events.len() as c_int,
-                timeout as c_int,
+                timeout.into().into(),
             )
         };
 
@@ -240,7 +241,7 @@
     let res = unsafe {
         libc::epoll_wait(
             epfd,
-            events.as_mut_ptr() as *mut libc::epoll_event,
+            events.as_mut_ptr().cast(),
             events.len() as c_int,
             timeout_ms as c_int,
         )
diff --git a/src/sys/event.rs b/src/sys/event.rs
index ec7f7e2..b294d27 100644
--- a/src/sys/event.rs
+++ b/src/sys/event.rs
@@ -10,6 +10,7 @@
 use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t};
 use std::convert::TryInto;
 use std::mem;
+use std::os::fd::{AsFd, BorrowedFd};
 use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd};
 use std::ptr;
 
@@ -29,6 +30,18 @@
 #[derive(Debug)]
 pub struct Kqueue(OwnedFd);
 
+impl AsFd for Kqueue {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl From<Kqueue> for OwnedFd {
+    fn from(value: Kqueue) -> Self {
+        value.0
+    }
+}
+
 impl Kqueue {
     /// Create a new kernel event queue.
     pub fn new() -> Result<Self> {
@@ -63,9 +76,9 @@
         let res = unsafe {
             libc::kevent(
                 self.0.as_raw_fd(),
-                changelist.as_ptr() as *const libc::kevent,
+                changelist.as_ptr().cast(),
                 changelist.len() as type_of_nchanges,
-                eventlist.as_mut_ptr() as *mut libc::kevent,
+                eventlist.as_mut_ptr().cast(),
                 eventlist.len() as type_of_nchanges,
                 if let Some(ref timeout) = timeout_opt {
                     timeout as *const timespec
@@ -78,13 +91,7 @@
     }
 }
 
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "openbsd"
-))]
+#[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))]
 type type_of_udata = *mut libc::c_void;
 #[cfg(target_os = "netbsd")]
 type type_of_udata = intptr_t;
@@ -109,10 +116,7 @@
         /// Takes a descriptor as the identifier, and returns whenever one of
         /// the specified exceptional conditions has occurred on the descriptor.
         EVFILT_EXCEPT,
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "ios",
-                  target_os = "macos"))]
+        #[cfg(any(freebsdlike, apple_targets))]
         /// Establishes a file system monitor.
         EVFILT_FS,
         #[cfg(target_os = "freebsd")]
@@ -120,7 +124,7 @@
         /// # See Also
         /// [lio_listio(2)](https://www.freebsd.org/cgi/man.cgi?query=lio_listio)
         EVFILT_LIO,
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
+        #[cfg(apple_targets)]
         /// Mach portsets
         EVFILT_MACHPORT,
         /// Notifies when a process performs one or more of the requested
@@ -144,13 +148,10 @@
         EVFILT_SIGNAL,
         /// Establishes a timer and notifies when the timer expires.
         EVFILT_TIMER,
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "ios",
-                  target_os = "macos"))]
+        #[cfg(any(freebsdlike, apple_targets))]
         /// Notifies only when explicitly requested by the user.
         EVFILT_USER,
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
+        #[cfg(apple_targets)]
         /// Virtual memory events
         EVFILT_VM,
         /// Notifies when a requested event happens on a specified file.
@@ -162,13 +163,7 @@
     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(freebsdlike, apple_targets, target_os = "openbsd"))]
 #[doc(hidden)]
 pub type type_of_event_flag = u16;
 #[cfg(target_os = "netbsd")]
@@ -187,9 +182,7 @@
         EV_DELETE;
         #[allow(missing_docs)]
         EV_DISABLE;
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
-                  target_os = "ios", target_os = "macos",
-                  target_os = "netbsd", target_os = "openbsd"))]
+        #[cfg(bsd)]
         #[allow(missing_docs)]
         EV_DISPATCH;
         #[cfg(target_os = "freebsd")]
@@ -201,7 +194,7 @@
         EV_EOF;
         #[allow(missing_docs)]
         EV_ERROR;
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         #[allow(missing_docs)]
         EV_FLAG0;
         #[allow(missing_docs)]
@@ -211,15 +204,13 @@
         EV_NODATA;
         #[allow(missing_docs)]
         EV_ONESHOT;
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         #[allow(missing_docs)]
         EV_OOBAND;
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         #[allow(missing_docs)]
         EV_POLL;
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
-                  target_os = "ios", target_os = "macos",
-                  target_os = "netbsd", target_os = "openbsd"))]
+        #[cfg(bsd)]
         #[allow(missing_docs)]
         EV_RECEIPT;
     }
@@ -231,7 +222,7 @@
     // that wouldn't simply be repeating the man page.
     #[allow(missing_docs)]
     pub struct FilterFlag: u32 {
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         #[allow(missing_docs)]
         NOTE_ABSOLUTE;
         #[allow(missing_docs)]
@@ -247,45 +238,27 @@
         NOTE_EXEC;
         #[allow(missing_docs)]
         NOTE_EXIT;
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         #[allow(missing_docs)]
         NOTE_EXITSTATUS;
         #[allow(missing_docs)]
         NOTE_EXTEND;
-        #[cfg(any(target_os = "macos",
-                  target_os = "ios",
-                  target_os = "freebsd",
-                  target_os = "dragonfly"))]
+        #[cfg(any(apple_targets, freebsdlike))]
         #[allow(missing_docs)]
         NOTE_FFAND;
-        #[cfg(any(target_os = "macos",
-                  target_os = "ios",
-                  target_os = "freebsd",
-                  target_os = "dragonfly"))]
+        #[cfg(any(apple_targets, freebsdlike))]
         #[allow(missing_docs)]
         NOTE_FFCOPY;
-        #[cfg(any(target_os = "macos",
-                  target_os = "ios",
-                  target_os = "freebsd",
-                  target_os = "dragonfly"))]
+        #[cfg(any(apple_targets, freebsdlike))]
         #[allow(missing_docs)]
         NOTE_FFCTRLMASK;
-        #[cfg(any(target_os = "macos",
-                  target_os = "ios",
-                  target_os = "freebsd",
-                  target_os = "dragonfly"))]
+        #[cfg(any(apple_targets, freebsdlike))]
         #[allow(missing_docs)]
         NOTE_FFLAGSMASK;
-        #[cfg(any(target_os = "macos",
-                  target_os = "ios",
-                  target_os = "freebsd",
-                  target_os = "dragonfly"))]
+        #[cfg(any(apple_targets, freebsdlike))]
         #[allow(missing_docs)]
         NOTE_FFNOP;
-        #[cfg(any(target_os = "macos",
-                  target_os = "ios",
-                  target_os = "freebsd",
-                  target_os = "dragonfly"))]
+        #[cfg(any(apple_targets, freebsdlike))]
         #[allow(missing_docs)]
         NOTE_FFOR;
         #[allow(missing_docs)]
@@ -297,10 +270,12 @@
         #[cfg(target_os = "freebsd")]
         #[allow(missing_docs)]
         NOTE_MSECONDS;
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         #[allow(missing_docs)]
         NOTE_NONE;
-        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
+        #[cfg(any(
+            apple_targets,
+            target_os = "freebsd"))]
         #[allow(missing_docs)]
         NOTE_NSECONDS;
         #[cfg(target_os = "dragonfly")]
@@ -314,38 +289,39 @@
         NOTE_RENAME;
         #[allow(missing_docs)]
         NOTE_REVOKE;
-        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
+        #[cfg(any(
+            apple_targets,
+            target_os = "freebsd"))]
         #[allow(missing_docs)]
         NOTE_SECONDS;
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         #[allow(missing_docs)]
         NOTE_SIGNAL;
         #[allow(missing_docs)]
         NOTE_TRACK;
         #[allow(missing_docs)]
         NOTE_TRACKERR;
-        #[cfg(any(target_os = "macos",
-                  target_os = "ios",
-                  target_os = "freebsd",
-                  target_os = "dragonfly"))]
+        #[cfg(any(apple_targets, freebsdlike))]
         #[allow(missing_docs)]
         NOTE_TRIGGER;
         #[cfg(target_os = "openbsd")]
         #[allow(missing_docs)]
         NOTE_TRUNCATE;
-        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
+        #[cfg(any(
+            apple_targets,
+            target_os = "freebsd"))]
         #[allow(missing_docs)]
         NOTE_USECONDS;
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         #[allow(missing_docs)]
         NOTE_VM_ERROR;
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         #[allow(missing_docs)]
         NOTE_VM_PRESSURE;
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         #[allow(missing_docs)]
         NOTE_VM_PRESSURE_SUDDEN_TERMINATE;
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         #[allow(missing_docs)]
         NOTE_VM_PRESSURE_TERMINATE;
         #[allow(missing_docs)]
@@ -443,13 +419,7 @@
     kq.kevent(changelist, eventlist, Some(timeout))
 }
 
-#[cfg(any(
-    target_os = "macos",
-    target_os = "ios",
-    target_os = "freebsd",
-    target_os = "dragonfly",
-    target_os = "openbsd"
-))]
+#[cfg(any(apple_targets, freebsdlike, target_os = "openbsd"))]
 type type_of_nchanges = c_int;
 #[cfg(target_os = "netbsd")]
 type type_of_nchanges = size_t;
@@ -484,42 +454,3 @@
     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 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);
-    assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits());
-    assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits());
-    assert_eq!(0x1337, actual.data());
-    assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata);
-    assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>());
-}
-
-#[test]
-fn test_kevent_filter() {
-    let udata: intptr_t = 12345;
-
-    let actual = KEvent::new(
-        0xdead_beef,
-        EventFilter::EVFILT_READ,
-        EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
-        FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
-        0x1337,
-        udata,
-    );
-    assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap());
-}
diff --git a/src/sys/eventfd.rs b/src/sys/eventfd.rs
index f172351..50a4f09 100644
--- a/src/sys/eventfd.rs
+++ b/src/sys/eventfd.rs
@@ -1,17 +1,84 @@
 use crate::errno::Errno;
-use crate::Result;
-use std::os::unix::io::{FromRawFd, OwnedFd};
+use crate::{Result,unistd};
+use std::os::unix::io::{FromRawFd, OwnedFd, AsRawFd, AsFd, RawFd, BorrowedFd};
 
 libc_bitflags! {
     pub struct EfdFlags: libc::c_int {
-        EFD_CLOEXEC; // Since Linux 2.6.27
-        EFD_NONBLOCK; // Since Linux 2.6.27
-        EFD_SEMAPHORE; // Since Linux 2.6.30
+        EFD_CLOEXEC; // Since Linux 2.6.27/FreeBSD 13.0
+        EFD_NONBLOCK; // Since Linux 2.6.27/FreeBSD 13.0
+        EFD_SEMAPHORE; // Since Linux 2.6.30/FreeBSD 13.0
     }
 }
 
+#[deprecated(since = "0.28.0", note = "Use EventFd::from_value_and_flags() instead")]
 pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<OwnedFd> {
     let res = unsafe { libc::eventfd(initval, flags.bits()) };
 
     Errno::result(res).map(|r| unsafe { OwnedFd::from_raw_fd(r) })
 }
+
+#[derive(Debug)]
+#[repr(transparent)]
+pub struct EventFd(OwnedFd);
+impl EventFd {
+    /// [`EventFd::from_value_and_flags`] with `init_val = 0` and `flags = EfdFlags::empty()`.
+    pub fn new() -> Result<Self> {
+        Self::from_value_and_flags(0, EfdFlags::empty())
+    }
+    /// Constructs [`EventFd`] with the given `init_val` and `flags`.
+    /// 
+    /// Wrapper around [`libc::eventfd`].
+    pub fn from_value_and_flags(init_val: u32, flags: EfdFlags) -> Result<Self> {
+        let res = unsafe { libc::eventfd(init_val, flags.bits()) };
+        Errno::result(res).map(|r| Self(unsafe { OwnedFd::from_raw_fd(r) }))
+    }
+    /// [`EventFd::from_value_and_flags`] with `init_val = 0` and given `flags`.
+    pub fn from_flags(flags: EfdFlags) -> Result<Self> {
+        Self::from_value_and_flags(0, flags)
+    }
+    /// [`EventFd::from_value_and_flags`] with given `init_val` and `flags = EfdFlags::empty()`.
+    pub fn from_value(init_val: u32) -> Result<Self> {
+        Self::from_value_and_flags(init_val, EfdFlags::empty())
+    }
+    /// Arms `self`, a following call to `poll`, `select` or `epoll` will return immediately.
+    /// 
+    /// [`EventFd::write`] with `1`.
+    pub fn arm(&self) -> Result<usize> {
+        self.write(1)
+    }
+    /// Defuses `self`, a following call to `poll`, `select` or `epoll` will block.
+    /// 
+    /// [`EventFd::write`] with `0`.
+    pub fn defuse(&self) -> Result<usize> {
+        self.write(0)
+    }
+    /// Enqueues `value` triggers.
+    /// 
+    /// The next `value` calls to `poll`, `select` or `epoll` will return immediately.
+    /// 
+    /// [`EventFd::write`] with `value`.
+    pub fn write(&self, value: u64) -> Result<usize> { 
+        unistd::write(&self.0,&value.to_ne_bytes())
+    }
+    // Reads the value from the file descriptor.
+    pub fn read(&self) -> Result<u64> {
+        let mut arr = [0; std::mem::size_of::<u64>()];
+        unistd::read(self.0.as_raw_fd(),&mut arr)?;
+        Ok(u64::from_ne_bytes(arr))
+    }
+}
+impl AsFd for EventFd {
+    fn as_fd(&self) -> BorrowedFd {
+        self.0.as_fd()
+    }
+}
+impl AsRawFd for EventFd {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+impl From<EventFd> for OwnedFd {
+    fn from(x: EventFd) -> OwnedFd {
+        x.0
+    }
+}
diff --git a/src/sys/fanotify.rs b/src/sys/fanotify.rs
new file mode 100644
index 0000000..e217406
--- /dev/null
+++ b/src/sys/fanotify.rs
@@ -0,0 +1,416 @@
+//! Monitoring API for filesystem events.
+//!
+//! Fanotify is a Linux-only API to monitor filesystems events.
+//!
+//! Additional capabilities compared to the `inotify` API include the ability to
+//! monitor all of the objects in a mounted filesystem, the ability to make
+//! access permission decisions, and the possibility to read or modify files
+//! before access by other applications.
+//!
+//! For more documentation, please read
+//! [fanotify(7)](https://man7.org/linux/man-pages/man7/fanotify.7.html).
+
+use crate::errno::Errno;
+use crate::fcntl::{at_rawfd, OFlag};
+use crate::unistd::{close, read, write};
+use crate::{NixPath, Result};
+use std::marker::PhantomData;
+use std::mem::{size_of, MaybeUninit};
+use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
+use std::ptr;
+
+libc_bitflags! {
+    /// Mask for defining which events shall be listened with
+    /// [`fanotify_mark`](fn.fanotify_mark.html) and for querying notifications.
+    pub struct MaskFlags: u64 {
+        /// File was accessed.
+        FAN_ACCESS;
+        /// File was modified.
+        FAN_MODIFY;
+        /// Metadata has changed. Since Linux 5.1.
+        FAN_ATTRIB;
+        /// Writtable file was closed.
+        FAN_CLOSE_WRITE;
+        /// Unwrittable file was closed.
+        FAN_CLOSE_NOWRITE;
+        /// File was opened.
+        FAN_OPEN;
+        /// File was moved from X. Since Linux 5.1.
+        FAN_MOVED_FROM;
+        /// File was moved to Y. Since Linux 5.1.
+        FAN_MOVED_TO;
+        /// Subfile was created. Since Linux 5.1.
+        FAN_CREATE;
+        /// Subfile was deleted. Since Linux 5.1.
+        FAN_DELETE;
+        /// Self was deleted. Since Linux 5.1.
+        FAN_DELETE_SELF;
+        /// Self was moved. Since Linux 5.1.
+        FAN_MOVE_SELF;
+        /// File was opened for execution. Since Linux 5.0.
+        FAN_OPEN_EXEC;
+
+        /// Event queue overflowed.
+        FAN_Q_OVERFLOW;
+        /// Filesystem error. Since Linux 5.16.
+        FAN_FS_ERROR;
+
+        /// Permission to open file was requested.
+        FAN_OPEN_PERM;
+        /// Permission to access file was requested.
+        FAN_ACCESS_PERM;
+        /// Permission to open file for execution was requested. Since Linux
+        /// 5.0.
+        FAN_OPEN_EXEC_PERM;
+
+        /// Interested in child events.
+        FAN_EVENT_ON_CHILD;
+
+        /// File was renamed. Since Linux 5.17.
+        FAN_RENAME;
+
+        /// Event occurred against dir.
+        FAN_ONDIR;
+
+        /// Combination of `FAN_CLOSE_WRITE` and `FAN_CLOSE_NOWRITE`.
+        FAN_CLOSE;
+        /// Combination of `FAN_MOVED_FROM` and `FAN_MOVED_TO`.
+        FAN_MOVE;
+    }
+}
+
+libc_bitflags! {
+    /// Configuration options for [`fanotify_init`](fn.fanotify_init.html).
+    pub struct InitFlags: libc::c_uint {
+        /// Close-on-exec flag set on the file descriptor.
+        FAN_CLOEXEC;
+        /// Nonblocking flag set on the file descriptor.
+        FAN_NONBLOCK;
+
+        /// Receipt of events notifications.
+        FAN_CLASS_NOTIF;
+        /// Receipt of events for permission decisions, after they contain final
+        /// data.
+        FAN_CLASS_CONTENT;
+        /// Receipt of events for permission decisions, before they contain
+        /// final data.
+        FAN_CLASS_PRE_CONTENT;
+
+        /// Remove the limit of 16384 events for the event queue.
+        FAN_UNLIMITED_QUEUE;
+        /// Remove the limit of 8192 marks.
+        FAN_UNLIMITED_MARKS;
+
+        /// Make `FanotifyEvent::pid` return pidfd. Since Linux 5.15.
+        FAN_REPORT_PIDFD;
+        /// Make `FanotifyEvent::pid` return thread id. Since Linux 4.20.
+        FAN_REPORT_TID;
+    }
+}
+
+libc_bitflags! {
+    /// File status flags for fanotify events file descriptors.
+    pub struct EventFFlags: libc::c_uint {
+        /// Read only access.
+        O_RDONLY as libc::c_uint;
+        /// Write only access.
+        O_WRONLY as libc::c_uint;
+        /// Read and write access.
+        O_RDWR as libc::c_uint;
+        /// Support for files exceeded 2 GB.
+        O_LARGEFILE as libc::c_uint;
+        /// Close-on-exec flag for the file descriptor. Since Linux 3.18.
+        O_CLOEXEC as libc::c_uint;
+        /// Append mode for the file descriptor.
+        O_APPEND as libc::c_uint;
+        /// Synchronized I/O data integrity completion.
+        O_DSYNC as libc::c_uint;
+        /// No file last access time update.
+        O_NOATIME as libc::c_uint;
+        /// Nonblocking mode for the file descriptor.
+        O_NONBLOCK as libc::c_uint;
+        /// Synchronized I/O file integrity completion.
+        O_SYNC as libc::c_uint;
+    }
+}
+
+impl TryFrom<OFlag> for EventFFlags {
+    type Error = Errno;
+
+    fn try_from(o_flag: OFlag) -> Result<Self> {
+        EventFFlags::from_bits(o_flag.bits() as u32).ok_or(Errno::EINVAL)
+    }
+}
+
+impl From<EventFFlags> for OFlag {
+    fn from(event_f_flags: EventFFlags) -> Self {
+        OFlag::from_bits_retain(event_f_flags.bits() as i32)
+    }
+}
+
+libc_bitflags! {
+    /// Configuration options for [`fanotify_mark`](fn.fanotify_mark.html).
+    pub struct MarkFlags: libc::c_uint {
+        /// Add the events to the marks.
+        FAN_MARK_ADD;
+        /// Remove the events to the marks.
+        FAN_MARK_REMOVE;
+        /// Don't follow symlinks, mark them.
+        FAN_MARK_DONT_FOLLOW;
+        /// Raise an error if filesystem to be marked is not a directory.
+        FAN_MARK_ONLYDIR;
+        /// Events added to or removed from the marks.
+        FAN_MARK_IGNORED_MASK;
+        /// Ignore mask shall survive modify events.
+        FAN_MARK_IGNORED_SURV_MODIFY;
+        /// Remove all marks.
+        FAN_MARK_FLUSH;
+        /// Do not pin inode object in the inode cache. Since Linux 5.19.
+        FAN_MARK_EVICTABLE;
+        /// Events added to or removed from the marks. Since Linux 6.0.
+        FAN_MARK_IGNORE;
+
+        /// Default flag.
+        FAN_MARK_INODE;
+        /// Mark the mount specified by pathname.
+        FAN_MARK_MOUNT;
+        /// Mark the filesystem specified by pathname. Since Linux 4.20.
+        FAN_MARK_FILESYSTEM;
+
+        /// Combination of `FAN_MARK_IGNORE` and `FAN_MARK_IGNORED_SURV_MODIFY`.
+        FAN_MARK_IGNORE_SURV;
+    }
+}
+
+/// Compile version number of fanotify API.
+pub const FANOTIFY_METADATA_VERSION: u8 = libc::FANOTIFY_METADATA_VERSION;
+
+/// Abstract over `libc::fanotify_event_metadata`, which represents an event
+/// received via `Fanotify::read_events`.
+// Is not Clone due to fd field, to avoid use-after-close scenarios.
+#[derive(Debug, Eq, Hash, PartialEq)]
+#[repr(transparent)]
+#[allow(missing_copy_implementations)]
+pub struct FanotifyEvent(libc::fanotify_event_metadata);
+
+impl FanotifyEvent {
+    /// Version number for the structure. It must be compared to
+    /// `FANOTIFY_METADATA_VERSION` to verify compile version and runtime
+    /// version does match. It can be done with the
+    /// `FanotifyEvent::check_version` method.
+    pub fn version(&self) -> u8 {
+        self.0.vers
+    }
+
+    /// Checks that compile fanotify API version is equal to the version of the
+    /// event.
+    pub fn check_version(&self) -> bool {
+        self.version() == FANOTIFY_METADATA_VERSION
+    }
+
+    /// Mask flags of the events.
+    pub fn mask(&self) -> MaskFlags {
+        MaskFlags::from_bits_truncate(self.0.mask)
+    }
+
+    /// The file descriptor of the event. If the value is `None` when reading
+    /// from the fanotify group, this event is to notify that a group queue
+    /// overflow occured.
+    pub fn fd(&self) -> Option<BorrowedFd> {
+        if self.0.fd == libc::FAN_NOFD {
+            None
+        } else {
+            // SAFETY: self.0.fd will be opened for the lifetime of `Self`,
+            // which is longer than the lifetime of the returned BorrowedFd, so
+            // it is safe.
+            Some(unsafe { BorrowedFd::borrow_raw(self.0.fd) })
+        }
+    }
+
+    /// PID of the process that caused the event. TID in case flag
+    /// `FAN_REPORT_TID` was set at group initialization.
+    pub fn pid(&self) -> i32 {
+        self.0.pid
+    }
+}
+
+impl Drop for FanotifyEvent {
+    fn drop(&mut self) {
+        let e = close(self.0.fd);
+        if !std::thread::panicking() && e == Err(Errno::EBADF) {
+            panic!("Closing an invalid file descriptor!");
+        };
+    }
+}
+
+/// Abstraction over the structure to be sent to allow or deny a given event.
+#[derive(Debug)]
+#[repr(transparent)]
+pub struct FanotifyResponse<'a> {
+    inner: libc::fanotify_response,
+    _borrowed_fd: PhantomData<BorrowedFd<'a>>,
+}
+
+impl<'a> FanotifyResponse<'a> {
+    /// Create a new response.
+    pub fn new(fd: BorrowedFd<'a>, response: Response) -> Self {
+        Self {
+            inner: libc::fanotify_response {
+                fd: fd.as_raw_fd(),
+                response: response.bits(),
+            },
+            _borrowed_fd: PhantomData,
+        }
+    }
+}
+
+libc_bitflags! {
+    /// Response to be wrapped in `FanotifyResponse` and sent to the `Fanotify`
+    /// group to allow or deny an event.
+    pub struct Response: u32 {
+        /// Allow the event.
+        FAN_ALLOW;
+        /// Deny the event.
+        FAN_DENY;
+    }
+}
+
+/// A fanotify group. This is also a file descriptor that can feed to other
+/// interfaces consuming file descriptors.
+#[derive(Debug)]
+pub struct Fanotify {
+    fd: OwnedFd,
+}
+
+impl Fanotify {
+    /// Initialize a new fanotify group.
+    ///
+    /// Returns a Result containing a Fanotify instance.
+    ///
+    /// For more information, see [fanotify_init(2)](https://man7.org/linux/man-pages/man7/fanotify_init.2.html).
+    pub fn init(
+        flags: InitFlags,
+        event_f_flags: EventFFlags,
+    ) -> Result<Fanotify> {
+        let res = Errno::result(unsafe {
+            libc::fanotify_init(flags.bits(), event_f_flags.bits())
+        });
+        res.map(|fd| Fanotify {
+            fd: unsafe { OwnedFd::from_raw_fd(fd) },
+        })
+    }
+
+    /// Add, remove, or modify an fanotify mark on a filesystem object.
+    /// If `dirfd` is `None`, `AT_FDCWD` is used.
+    ///
+    /// Returns a Result containing either `()` on success or errno otherwise.
+    ///
+    /// For more information, see [fanotify_mark(2)](https://man7.org/linux/man-pages/man7/fanotify_mark.2.html).
+    pub fn mark<P: ?Sized + NixPath>(
+        &self,
+        flags: MarkFlags,
+        mask: MaskFlags,
+        dirfd: Option<RawFd>,
+        path: Option<&P>,
+    ) -> 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,
+        {
+            match p {
+                Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())),
+                None => Ok(f(std::ptr::null())),
+            }
+        }
+
+        let res = with_opt_nix_path(path, |p| unsafe {
+            libc::fanotify_mark(
+                self.fd.as_raw_fd(),
+                flags.bits(),
+                mask.bits(),
+                at_rawfd(dirfd),
+                p,
+            )
+        })?;
+
+        Errno::result(res).map(|_| ())
+    }
+
+    /// Read incoming events from the fanotify group.
+    ///
+    /// Returns a Result containing either a `Vec` of events on success or errno
+    /// otherwise.
+    ///
+    /// # Errors
+    ///
+    /// Possible errors can be those that are explicitly listed in
+    /// [fanotify(2)](https://man7.org/linux/man-pages/man7/fanotify.2.html) in
+    /// addition to the possible errors caused by `read` call.
+    /// In particular, `EAGAIN` is returned when no event is available on a
+    /// group that has been initialized with the flag `InitFlags::FAN_NONBLOCK`,
+    /// thus making this method nonblocking.
+    pub fn read_events(&self) -> Result<Vec<FanotifyEvent>> {
+        let metadata_size = size_of::<libc::fanotify_event_metadata>();
+        const BUFSIZ: usize = 4096;
+        let mut buffer = [0u8; BUFSIZ];
+        let mut events = Vec::new();
+        let mut offset = 0;
+
+        let nread = read(self.fd.as_raw_fd(), &mut buffer)?;
+
+        while (nread - offset) >= metadata_size {
+            let metadata = unsafe {
+                let mut metadata =
+                    MaybeUninit::<libc::fanotify_event_metadata>::uninit();
+                ptr::copy_nonoverlapping(
+                    buffer.as_ptr().add(offset),
+                    metadata.as_mut_ptr().cast(),
+                    (BUFSIZ - offset).min(metadata_size),
+                );
+                metadata.assume_init()
+            };
+
+            events.push(FanotifyEvent(metadata));
+            offset += metadata.event_len as usize;
+        }
+
+        Ok(events)
+    }
+
+    /// Write an event response on the fanotify group.
+    ///
+    /// Returns a Result containing either `()` on success or errno otherwise.
+    ///
+    /// # Errors
+    ///
+    /// Possible errors can be those that are explicitly listed in
+    /// [fanotify(2)](https://man7.org/linux/man-pages/man7/fanotify.2.html) in
+    /// addition to the possible errors caused by `write` call.
+    /// In particular, `EAGAIN` or `EWOULDBLOCK` is returned when no event is
+    /// available on a group that has been initialized with the flag
+    /// `InitFlags::FAN_NONBLOCK`, thus making this method nonblocking.
+    pub fn write_response(&self, response: FanotifyResponse) -> Result<()> {
+        write(self.fd.as_fd(), unsafe {
+            std::slice::from_raw_parts(
+                (&response.inner as *const libc::fanotify_response).cast(),
+                size_of::<libc::fanotify_response>(),
+            )
+        })?;
+        Ok(())
+    }
+}
+
+impl FromRawFd for Fanotify {
+    unsafe fn from_raw_fd(fd: RawFd) -> Self {
+        Fanotify {
+            fd: unsafe { OwnedFd::from_raw_fd(fd) },
+        }
+    }
+}
+
+impl AsFd for Fanotify {
+    fn as_fd(&'_ self) -> BorrowedFd<'_> {
+        self.fd.as_fd()
+    }
+}
diff --git a/src/sys/inotify.rs b/src/sys/inotify.rs
index e5fe930..9cbeb53 100644
--- a/src/sys/inotify.rs
+++ b/src/sys/inotify.rs
@@ -143,7 +143,9 @@
     pub fn init(flags: InitFlags) -> Result<Inotify> {
         let res = Errno::result(unsafe { libc::inotify_init1(flags.bits()) });
 
-        res.map(|fd| Inotify { fd: unsafe { OwnedFd::from_raw_fd(fd) } })
+        res.map(|fd| Inotify {
+            fd: unsafe { OwnedFd::from_raw_fd(fd) },
+        })
     }
 
     /// Adds a new watch on the target file or directory.
@@ -157,7 +159,11 @@
         mask: AddWatchFlags,
     ) -> Result<WatchDescriptor> {
         let res = path.with_nix_path(|cstr| unsafe {
-            libc::inotify_add_watch(self.fd.as_raw_fd(), cstr.as_ptr(), mask.bits())
+            libc::inotify_add_watch(
+                self.fd.as_raw_fd(),
+                cstr.as_ptr(),
+                mask.bits(),
+            )
         })?;
 
         Errno::result(res).map(|wd| WatchDescriptor { wd })
@@ -202,7 +208,7 @@
                 let mut event = MaybeUninit::<libc::inotify_event>::uninit();
                 ptr::copy_nonoverlapping(
                     buffer.as_ptr().add(offset),
-                    event.as_mut_ptr() as *mut u8,
+                    event.as_mut_ptr().cast(),
                     (BUFSIZ - offset).min(header_size),
                 );
                 event.assume_init()
@@ -237,7 +243,9 @@
 
 impl FromRawFd for Inotify {
     unsafe fn from_raw_fd(fd: RawFd) -> Self {
-        Inotify { fd: OwnedFd::from_raw_fd(fd) }
+        Inotify {
+            fd: unsafe { OwnedFd::from_raw_fd(fd) },
+        }
     }
 }
 
diff --git a/src/sys/ioctl/bsd.rs b/src/sys/ioctl/bsd.rs
index 307994c..cedc8e6 100644
--- a/src/sys/ioctl/bsd.rs
+++ b/src/sys/ioctl/bsd.rs
@@ -1,10 +1,10 @@
 /// The datatype used for the ioctl number
 #[doc(hidden)]
-#[cfg(not(target_os = "illumos"))]
+#[cfg(not(solarish))]
 pub type ioctl_num_type = ::libc::c_ulong;
 
 #[doc(hidden)]
-#[cfg(target_os = "illumos")]
+#[cfg(solarish)]
 pub type ioctl_num_type = ::libc::c_int;
 
 /// The datatype used for the 3rd argument
diff --git a/src/sys/ioctl/linux.rs b/src/sys/ioctl/linux.rs
index 610b8dd..52312f4 100644
--- a/src/sys/ioctl/linux.rs
+++ b/src/sys/ioctl/linux.rs
@@ -19,7 +19,9 @@
 cfg_if! {
     if #[cfg(any(
         target_arch = "mips",
+        target_arch = "mips32r6",
         target_arch = "mips64",
+        target_arch = "mips64r6",
         target_arch = "powerpc",
         target_arch = "powerpc64",
         target_arch = "sparc64"
diff --git a/src/sys/ioctl/mod.rs b/src/sys/ioctl/mod.rs
index 0b3fe3e..e1e808f 100644
--- a/src/sys/ioctl/mod.rs
+++ b/src/sys/ioctl/mod.rs
@@ -72,7 +72,7 @@
 //! # const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
 //! # const SPI_IOC_TYPE_MODE: u8 = 1;
 //! pub unsafe fn spi_read_mode(fd: c_int, data: *mut u8) -> Result<c_int> {
-//!     let res = libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data);
+//!     let res = unsafe { libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data) };
 //!     Errno::result(res)
 //! }
 //! # fn main() {}
@@ -121,11 +121,11 @@
 //!
 //! ```
 //! # #[macro_use] extern crate nix;
-//! # #[cfg(any(target_os = "android", target_os = "linux"))]
+//! # #[cfg(linux_android)]
 //! # use nix::libc::TCGETS as TCGETS;
-//! # #[cfg(any(target_os = "android", target_os = "linux"))]
+//! # #[cfg(linux_android)]
 //! # use nix::libc::termios as termios;
-//! # #[cfg(any(target_os = "android", target_os = "linux"))]
+//! # #[cfg(linux_android)]
 //! ioctl_read_bad!(tcgets, TCGETS, termios);
 //! # fn main() {}
 //! ```
@@ -179,9 +179,13 @@
 //! # const SPI_IOC_TYPE_MESSAGE: u8 = 0;
 //! # pub struct spi_ioc_transfer(u64);
 //! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result<c_int> {
-//!     let res = libc::ioctl(fd,
-//!                           request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()),
-//!                           data);
+//!     let res = unsafe {
+//!         libc::ioctl(
+//!             fd,
+//!             request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()),
+//!             data
+//!         )
+//!     };
 //!     Errno::result(res)
 //! }
 //! # fn main() {}
@@ -223,40 +227,18 @@
 //! ```
 use cfg_if::cfg_if;
 
-#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+#[cfg(any(linux_android, target_os = "redox"))]
 #[macro_use]
 mod linux;
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "linux",
-    target_os = "redox"
-))]
+#[cfg(any(linux_android, target_os = "redox"))]
 pub use self::linux::*;
 
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "illumos",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "haiku",
-    target_os = "openbsd"
-))]
+#[cfg(any(bsd, solarish, target_os = "haiku",))]
 #[macro_use]
 mod bsd;
 
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "illumos",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "haiku",
-    target_os = "openbsd"
-))]
+#[cfg(any(bsd, solarish, target_os = "haiku",))]
 pub use self::bsd::*;
 
 /// Convert raw ioctl return value to a Nix result
@@ -305,7 +287,9 @@
         $(#[$attr])*
         pub unsafe fn $name(fd: $crate::libc::c_int)
                             -> $crate::Result<$crate::libc::c_int> {
-            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type))
+            unsafe {
+                convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type))
+            }
         }
     )
 }
@@ -345,7 +329,9 @@
         $(#[$attr])*
         pub unsafe fn $name(fd: $crate::libc::c_int)
                             -> $crate::Result<$crate::libc::c_int> {
-            convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type))
+            unsafe {
+                convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type))
+            }
         }
     )
 }
@@ -383,7 +369,9 @@
         pub unsafe fn $name(fd: $crate::libc::c_int,
                             data: *mut $ty)
                             -> $crate::Result<$crate::libc::c_int> {
-            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+            unsafe {
+                convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+            }
         }
     )
 }
@@ -408,7 +396,7 @@
 ///
 /// ```
 /// # #[macro_use] extern crate nix;
-/// # #[cfg(any(target_os = "android", target_os = "linux"))]
+/// # #[cfg(linux_android)]
 /// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
 /// # fn main() {}
 /// ```
@@ -419,7 +407,9 @@
         pub unsafe fn $name(fd: $crate::libc::c_int,
                             data: *mut $ty)
                             -> $crate::Result<$crate::libc::c_int> {
-            convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+            unsafe {
+                convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+            }
         }
     )
 }
@@ -456,7 +446,9 @@
         pub unsafe fn $name(fd: $crate::libc::c_int,
                             data: *const $ty)
                             -> $crate::Result<$crate::libc::c_int> {
-            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+            unsafe {
+                convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+            }
         }
     )
 }
@@ -481,7 +473,7 @@
 ///
 /// ```
 /// # #[macro_use] extern crate nix;
-/// # #[cfg(any(target_os = "android", target_os = "linux"))]
+/// # #[cfg(linux_android)]
 /// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios);
 /// # fn main() {}
 /// ```
@@ -492,13 +484,15 @@
         pub unsafe fn $name(fd: $crate::libc::c_int,
                             data: *const $ty)
                             -> $crate::Result<$crate::libc::c_int> {
-            convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+            unsafe {
+                convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+            }
         }
     )
 }
 
 cfg_if! {
-    if #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] {
+    if #[cfg(freebsdlike)] {
         /// Generates a wrapper function for a ioctl that writes an integer to the kernel.
         ///
         /// The arguments to this macro are:
@@ -533,7 +527,9 @@
                 pub unsafe fn $name(fd: $crate::libc::c_int,
                                     data: $crate::sys::ioctl::ioctl_param_type)
                                     -> $crate::Result<$crate::libc::c_int> {
-                    convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data))
+                    unsafe {
+                        convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data))
+                    }
                 }
             )
         }
@@ -574,7 +570,9 @@
                 pub unsafe fn $name(fd: $crate::libc::c_int,
                                     data: $crate::sys::ioctl::ioctl_param_type)
                                     -> $crate::Result<$crate::libc::c_int> {
-                    convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data))
+                    unsafe {
+                        convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data))
+                    }
                 }
             )
         }
@@ -600,7 +598,7 @@
 ///
 /// ```
 /// # #[macro_use] extern crate nix;
-/// # #[cfg(any(target_os = "android", target_os = "linux"))]
+/// # #[cfg(linux_android)]
 /// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK);
 /// # fn main() {}
 /// ```
@@ -618,7 +616,9 @@
         pub unsafe fn $name(fd: $crate::libc::c_int,
                             data: $crate::libc::c_int)
                             -> $crate::Result<$crate::libc::c_int> {
-            convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+            unsafe {
+                convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+            }
         }
     )
 }
@@ -655,7 +655,9 @@
         pub unsafe fn $name(fd: $crate::libc::c_int,
                             data: *mut $ty)
                             -> $crate::Result<$crate::libc::c_int> {
-            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+            unsafe {
+                convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+            }
         }
     )
 }
@@ -683,7 +685,9 @@
         pub unsafe fn $name(fd: $crate::libc::c_int,
                             data: *mut $ty)
                             -> $crate::Result<$crate::libc::c_int> {
-            convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+            unsafe {
+                convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+            }
         }
     )
 }
@@ -712,7 +716,9 @@
         pub unsafe fn $name(fd: $crate::libc::c_int,
                             data: &mut [$ty])
                             -> $crate::Result<$crate::libc::c_int> {
-            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data))
+            unsafe {
+                convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data.as_mut_ptr()))
+            }
         }
     )
 }
@@ -751,7 +757,9 @@
         pub unsafe fn $name(fd: $crate::libc::c_int,
                             data: &[$ty])
                             -> $crate::Result<$crate::libc::c_int> {
-            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data))
+            unsafe {
+                convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data.as_ptr()))
+            }
         }
     )
 }
@@ -780,7 +788,9 @@
         pub unsafe fn $name(fd: $crate::libc::c_int,
                             data: &mut [$ty])
                             -> $crate::Result<$crate::libc::c_int> {
-            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data))
+            unsafe {
+                convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data.as_mut_ptr()))
+            }
         }
     )
 }
diff --git a/src/sys/memfd.rs b/src/sys/memfd.rs
index d147ccf..918bf0b 100644
--- a/src/sys/memfd.rs
+++ b/src/sys/memfd.rs
@@ -29,6 +29,49 @@
         ///
         /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html
         MFD_ALLOW_SEALING;
+        /// Anonymous file will be created using huge pages. It should be safe now to
+        /// combine with [`MFD_ALLOW_SEALING`] too.
+        /// However, despite its presence, on FreeBSD it is unimplemented for now (ENOSYS).
+        ///
+        /// See also the hugetlb filesystem in [`memfd_create(2)`].
+        ///
+        /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html
+        #[cfg(linux_android)]
+        MFD_HUGETLB;
+        /// Following are to be used with [`MFD_HUGETLB`], indicating the desired hugetlb size.
+        ///
+        /// See also the hugetlb filesystem in [`memfd_create(2)`].
+        ///
+        /// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html
+        #[cfg(linux_android)]
+        MFD_HUGE_1MB;
+        /// hugetlb size of 2MB.
+        #[cfg(linux_android)]
+        MFD_HUGE_2MB;
+        /// hugetlb size of 8MB.
+        #[cfg(linux_android)]
+        MFD_HUGE_8MB;
+        /// hugetlb size of 16MB.
+        #[cfg(linux_android)]
+        MFD_HUGE_16MB;
+        /// hugetlb size of 32MB.
+        #[cfg(linux_android)]
+        MFD_HUGE_32MB;
+        /// hugetlb size of 256MB.
+        #[cfg(linux_android)]
+        MFD_HUGE_256MB;
+        /// hugetlb size of 512MB.
+        #[cfg(linux_android)]
+        MFD_HUGE_512MB;
+        /// hugetlb size of 1GB.
+        #[cfg(linux_android)]
+        MFD_HUGE_1GB;
+        /// hugetlb size of 2GB.
+        #[cfg(linux_android)]
+        MFD_HUGE_2GB;
+        /// hugetlb size of 16GB.
+        #[cfg(linux_android)]
+        MFD_HUGE_16GB;
     }
 );
 
diff --git a/src/sys/mman.rs b/src/sys/mman.rs
index 8cfd6d6..a64f14f 100644
--- a/src/sys/mman.rs
+++ b/src/sys/mman.rs
@@ -8,7 +8,11 @@
 #[cfg(feature = "fs")]
 use crate::{fcntl::OFlag, sys::stat::Mode};
 use libc::{self, c_int, c_void, off_t, size_t};
-use std::{num::NonZeroUsize, os::unix::io::{AsRawFd, AsFd}};
+use std::ptr::NonNull;
+use std::{
+    num::NonZeroUsize,
+    os::unix::io::{AsFd, AsRawFd},
+};
 
 libc_bitflags! {
     /// Desired memory protection of a memory mapping.
@@ -22,12 +26,10 @@
         /// Pages can be executed
         PROT_EXEC;
         /// Apply protection up to the end of a mapping that grows upwards.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         PROT_GROWSDOWN;
         /// Apply protection down to the beginning of a mapping that grows downwards.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         PROT_GROWSUP;
     }
 }
@@ -45,145 +47,143 @@
         MAP_FIXED;
         /// Place the mapping at exactly the address specified in `addr`, but never clobber an existing range.
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_FIXED_NOREPLACE;
         /// To be used with `MAP_FIXED`, to forbid the system
         /// to select a different address than the one specified.
         #[cfg(target_os = "freebsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_EXCL;
         /// Synonym for `MAP_ANONYMOUS`.
         MAP_ANON;
         /// The mapping is not backed by any file.
         MAP_ANONYMOUS;
         /// Put the mapping into the first 2GB of the process address space.
-        #[cfg(any(all(any(target_os = "android", target_os = "linux"),
+        #[cfg(any(all(linux_android,
                       any(target_arch = "x86", target_arch = "x86_64")),
                   all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")),
                   all(target_os = "freebsd", target_pointer_width = "64")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_32BIT;
         /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MAP_GROWSDOWN;
         /// Compatibility flag. Ignored.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MAP_DENYWRITE;
         /// Compatibility flag. Ignored.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MAP_EXECUTABLE;
         /// Mark the mmaped region to be locked in the same way as `mlock(2)`.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MAP_LOCKED;
         /// Do not reserve swap space for this mapping.
         ///
         /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD.
-        #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", target_os = "aix")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(not(any(freebsdlike, target_os = "aix", target_os = "hurd")))]
         MAP_NORESERVE;
         /// Populate page tables for a mapping.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MAP_POPULATE;
         /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MAP_NONBLOCK;
         /// Allocate the mapping using "huge pages."
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MAP_HUGETLB;
         /// Make use of 64KB huge page (must be supported by the system)
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_HUGE_64KB;
         /// Make use of 512KB huge page (must be supported by the system)
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_HUGE_512KB;
         /// Make use of 1MB huge page (must be supported by the system)
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_HUGE_1MB;
         /// Make use of 2MB huge page (must be supported by the system)
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_HUGE_2MB;
         /// Make use of 8MB huge page (must be supported by the system)
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_HUGE_8MB;
         /// Make use of 16MB huge page (must be supported by the system)
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_HUGE_16MB;
         /// Make use of 32MB huge page (must be supported by the system)
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_HUGE_32MB;
         /// Make use of 256MB huge page (must be supported by the system)
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_HUGE_256MB;
         /// Make use of 512MB huge page (must be supported by the system)
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_HUGE_512MB;
         /// Make use of 1GB huge page (must be supported by the system)
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_HUGE_1GB;
         /// Make use of 2GB huge page (must be supported by the system)
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_HUGE_2GB;
         /// Make use of 16GB huge page (must be supported by the system)
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_HUGE_16GB;
 
         /// Lock the mapped region into memory as with `mlock(2)`.
         #[cfg(target_os = "netbsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_WIRED;
         /// Causes dirtied data in the specified range to be flushed to disk only when necessary.
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         MAP_NOSYNC;
         /// Rename private pages to a file.
         ///
         /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD.
-        #[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(netbsdlike)]
         MAP_RENAME;
         /// Region may contain semaphores.
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(freebsdlike, netbsdlike))]
         MAP_HASSEMAPHORE;
         /// Region grows down, like a stack.
-        #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))]
         MAP_STACK;
         /// Pages in this mapping are not retained in the kernel's memory cache.
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         MAP_NOCACHE;
         /// Allows the W/X bit on the page, it's necessary on aarch64 architecture.
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         MAP_JIT;
         /// Allows to use large pages, underlying alignment based on size.
         #[cfg(target_os = "freebsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_ALIGNED_SUPER;
         /// Pages will be discarded in the core dumps.
         #[cfg(target_os = "openbsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_CONCEAL;
+        /// Attempt to place the mapping at exactly the address specified in `addr`.
+        /// it's a default behavior on OpenBSD.
+        #[cfg(netbsdlike)]
+        MAP_TRYFIXED;
+    }
+}
+
+impl MapFlags {
+    /// Create `MAP_HUGETLB` with provided size of huge page.
+    ///
+    /// Under the hood it computes `MAP_HUGETLB | (huge_page_size_log2 << libc::MAP_HUGE_SHIFT`).
+    /// `huge_page_size_log2` denotes logarithm of huge page size to use and should be
+    /// between 16 and 63 (inclusively).
+    ///
+    /// ```
+    /// # use nix::sys::mman::MapFlags;
+    /// let f = MapFlags::map_hugetlb_with_size_log2(30).unwrap();
+    /// assert_eq!(f, MapFlags::MAP_HUGETLB | MapFlags::MAP_HUGE_1GB);
+    /// ```
+    #[cfg(any(linux_android, target_os = "fuchsia"))]
+    pub fn map_hugetlb_with_size_log2(
+        huge_page_size_log2: u32,
+    ) -> Option<Self> {
+        if (16..=63).contains(&huge_page_size_log2) {
+            let flag = libc::MAP_HUGETLB
+                | (huge_page_size_log2 << libc::MAP_HUGE_SHIFT) as i32;
+            Some(Self(flag.into()))
+        } else {
+            None
+        }
     }
 }
 
@@ -193,19 +193,15 @@
     pub struct MRemapFlags: c_int {
         /// Permit the kernel to relocate the mapping to a new virtual address, if necessary.
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MREMAP_MAYMOVE;
         /// Place the mapping at exactly the address specified in `new_address`.
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MREMAP_FIXED;
         /// Place the mapping at exactly the address specified in `new_address`.
         #[cfg(target_os = "netbsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_FIXED;
         /// Allows to duplicate the mapping to be able to apply different flags on the copy.
         #[cfg(target_os = "netbsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MAP_REMAPDUP;
     }
 }
@@ -228,30 +224,24 @@
         /// Do not expect access in the near future.
         MADV_DONTNEED,
         /// Free up a given range of pages and its associated backing store.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MADV_REMOVE,
         /// Do not make pages in this range available to the child after a `fork(2)`.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MADV_DONTFORK,
         /// Undo the effect of `MADV_DONTFORK`.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MADV_DOFORK,
         /// Poison the given pages.
         ///
         /// Subsequent references to those pages are treated like hardware memory corruption.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MADV_HWPOISON,
         /// Enable Kernel Samepage Merging (KSM) for the given pages.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MADV_MERGEABLE,
         /// Undo the effect of `MADV_MERGEABLE`
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MADV_UNMERGEABLE,
         /// Preserve the memory of each page but offline the original page.
         #[cfg(any(target_os = "android",
@@ -266,68 +256,52 @@
                 target_arch = "sparc64"))))]
         MADV_SOFT_OFFLINE,
         /// Enable Transparent Huge Pages (THP) for pages in the given range.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MADV_HUGEPAGE,
         /// Undo the effect of `MADV_HUGEPAGE`.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MADV_NOHUGEPAGE,
         /// Exclude the given range from a core dump.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MADV_DONTDUMP,
         /// Undo the effect of an earlier `MADV_DONTDUMP`.
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         MADV_DODUMP,
         /// Specify that the application no longer needs the pages in the given range.
-        #[cfg(not(target_os = "aix"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(not(any(target_os = "aix", target_os = "hurd")))]
         MADV_FREE,
         /// Request that the system not flush the current range to disk unless it needs to.
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         MADV_NOSYNC,
         /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range.
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         MADV_AUTOSYNC,
         /// Region is not included in a core file.
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         MADV_NOCORE,
         /// Include region in a core file
-        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         MADV_CORE,
         /// This process should not be killed when swap space is exhausted.
         #[cfg(any(target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MADV_PROTECT,
         /// Invalidate the hardware page table for the given region.
         #[cfg(target_os = "dragonfly")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MADV_INVAL,
         /// Set the offset of the page directory page to `value` for the virtual page table.
         #[cfg(target_os = "dragonfly")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MADV_SETMAP,
         /// Indicates that the application will not need the data in the given range.
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         MADV_ZERO_WIRED_PAGES,
         /// Pages can be reused (by anyone).
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         MADV_FREE_REUSABLE,
         /// Caller wants to reuse those pages.
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         MADV_FREE_REUSE,
         // Darwin doesn't document this flag's behavior.
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         #[allow(missing_docs)]
         MADV_CAN_REUSE,
     }
@@ -341,12 +315,10 @@
         /// Invalidate all cached data.
         MS_INVALIDATE;
         /// Invalidate pages, but leave them mapped.
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         MS_KILLPAGES;
         /// Deactivate pages, but leave them mapped.
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         MS_DEACTIVATE;
         /// Perform an update and wait for it to complete.
         MS_SYNC;
@@ -374,8 +346,8 @@
 /// `addr` must meet all the requirements described in the [`mlock(2)`] man page.
 ///
 /// [`mlock(2)`]: https://man7.org/linux/man-pages/man2/mlock.2.html
-pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
-    Errno::result(libc::mlock(addr, length)).map(drop)
+pub unsafe fn mlock(addr: NonNull<c_void>, length: size_t) -> Result<()> {
+    unsafe { Errno::result(libc::mlock(addr.as_ptr(), length)).map(drop) }
 }
 
 /// Unlocks all memory pages that contain part of the address range with
@@ -387,8 +359,8 @@
 /// page.
 ///
 /// [`munlock(2)`]: https://man7.org/linux/man-pages/man2/munlock.2.html
-pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
-    Errno::result(libc::munlock(addr, length)).map(drop)
+pub unsafe fn munlock(addr: NonNull<c_void>, length: size_t) -> Result<()> {
+    unsafe { Errno::result(libc::munlock(addr.as_ptr(), length)).map(drop) }
 }
 
 /// Locks all memory pages mapped into this process' address space.
@@ -411,7 +383,9 @@
     unsafe { Errno::result(libc::munlockall()) }.map(drop)
 }
 
-/// allocate memory, or map files or devices into memory
+/// Allocate memory, or map files or devices into memory
+///
+/// For anonymous mappings (`MAP_ANON`/`MAP_ANONYMOUS`), see [mmap_anonymous].
 ///
 /// # Safety
 ///
@@ -423,20 +397,54 @@
     length: NonZeroUsize,
     prot: ProtFlags,
     flags: MapFlags,
-    f: Option<F>,
+    f: F,
     offset: off_t,
-) -> Result<*mut c_void> {
-    let ptr =
-        addr.map_or(std::ptr::null_mut(), |a| usize::from(a) as *mut c_void);
+) -> Result<NonNull<c_void>> {
+    let ptr = addr.map_or(std::ptr::null_mut(), |a| a.get() as *mut c_void);
 
-    let fd = f.map(|f| f.as_fd().as_raw_fd()).unwrap_or(-1);
-    let ret =
-        libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset);
+    let fd = f.as_fd().as_raw_fd();
+    let ret = unsafe {
+        libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset)
+    };
 
     if ret == libc::MAP_FAILED {
         Err(Errno::last())
     } else {
-        Ok(ret)
+        // SAFETY: `libc::mmap` returns a valid non-null pointer or `libc::MAP_FAILED`, thus `ret`
+        // will be non-null here.
+        Ok(unsafe { NonNull::new_unchecked(ret) })
+    }
+}
+
+/// Create an anonymous memory mapping.
+///
+/// This function is a wrapper around [`mmap`]:
+/// `mmap(ptr, len, prot, MAP_ANONYMOUS | flags, -1, 0)`.
+///
+/// # Safety
+///
+/// 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_anonymous(
+    addr: Option<NonZeroUsize>,
+    length: NonZeroUsize,
+    prot: ProtFlags,
+    flags: MapFlags,
+) -> Result<NonNull<c_void>> {
+    let ptr = addr.map_or(std::ptr::null_mut(), |a| a.get() as *mut c_void);
+
+    let flags = MapFlags::MAP_ANONYMOUS | flags;
+    let ret = unsafe {
+        libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), -1, 0)
+    };
+
+    if ret == libc::MAP_FAILED {
+        Err(Errno::last())
+    } else {
+        // SAFETY: `libc::mmap` returns a valid non-null pointer or `libc::MAP_FAILED`, thus `ret`
+        // will be non-null here.
+        Ok(unsafe { NonNull::new_unchecked(ret) })
     }
 }
 
@@ -449,33 +457,43 @@
 /// detailed requirements.
 #[cfg(any(target_os = "linux", target_os = "netbsd"))]
 pub unsafe fn mremap(
-    addr: *mut c_void,
+    addr: NonNull<c_void>,
     old_size: size_t,
     new_size: size_t,
     flags: MRemapFlags,
-    new_address: Option<*mut c_void>,
-) -> Result<*mut c_void> {
+    new_address: Option<NonNull<c_void>>,
+) -> Result<NonNull<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 = unsafe {
+        libc::mremap(
+            addr.as_ptr(),
+            old_size,
+            new_size,
+            flags.bits(),
+            new_address
+                .map(NonNull::as_ptr)
+                .unwrap_or(std::ptr::null_mut()),
+        )
+    };
     #[cfg(target_os = "netbsd")]
-    let ret = libc::mremap(
-        addr,
-        old_size,
-        new_address.unwrap_or(std::ptr::null_mut()),
-        new_size,
-        flags.bits(),
-    );
+    let ret = unsafe {
+        libc::mremap(
+            addr.as_ptr(),
+            old_size,
+            new_address
+                .map(NonNull::as_ptr)
+                .unwrap_or(std::ptr::null_mut()),
+            new_size,
+            flags.bits(),
+        )
+    };
 
     if ret == libc::MAP_FAILED {
         Err(Errno::last())
     } else {
-        Ok(ret)
+        // SAFETY: `libc::mremap` returns a valid non-null pointer or `libc::MAP_FAILED`, thus `ret`
+        // will be non-null here.
+        Ok(unsafe { NonNull::new_unchecked(ret) })
     }
 }
 
@@ -487,8 +505,8 @@
 /// page.
 ///
 /// [`munmap(2)`]: https://man7.org/linux/man-pages/man2/munmap.2.html
-pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
-    Errno::result(libc::munmap(addr, len)).map(drop)
+pub unsafe fn munmap(addr: NonNull<c_void>, len: size_t) -> Result<()> {
+    unsafe { Errno::result(libc::munmap(addr.as_ptr(), len)).map(drop) }
 }
 
 /// give advice about use of memory
@@ -499,12 +517,16 @@
 /// [`MmapAdvise::MADV_FREE`].
 ///
 /// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html
+#[allow(rustdoc::broken_intra_doc_links)] // For Hurd as `MADV_FREE` is not available on it
 pub unsafe fn madvise(
-    addr: *mut c_void,
+    addr: NonNull<c_void>,
     length: size_t,
     advise: MmapAdvise,
 ) -> Result<()> {
-    Errno::result(libc::madvise(addr, length, advise as i32)).map(drop)
+    unsafe {
+        Errno::result(libc::madvise(addr.as_ptr(), length, advise as i32))
+            .map(drop)
+    }
 }
 
 /// Set protection of memory mapping.
@@ -519,27 +541,30 @@
 ///
 /// ```
 /// # use nix::libc::size_t;
-/// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags};
+/// # use nix::sys::mman::{mmap_anonymous, mprotect, MapFlags, ProtFlags};
 /// # use std::ptr;
 /// # use std::os::unix::io::BorrowedFd;
 /// const ONE_K: size_t = 1024;
 /// let one_k_non_zero = std::num::NonZeroUsize::new(ONE_K).unwrap();
 /// let mut slice: &mut [u8] = unsafe {
-///     let mem = mmap::<BorrowedFd>(None, one_k_non_zero, ProtFlags::PROT_NONE,
-///                    MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, None, 0).unwrap();
+///     let mem = mmap_anonymous(None, one_k_non_zero, ProtFlags::PROT_NONE, MapFlags::MAP_PRIVATE)
+///         .unwrap();
 ///     mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap();
-///     std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
+///     std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
 /// };
 /// assert_eq!(slice[0], 0x00);
 /// slice[0] = 0xFF;
 /// assert_eq!(slice[0], 0xFF);
 /// ```
 pub unsafe fn mprotect(
-    addr: *mut c_void,
+    addr: NonNull<c_void>,
     length: size_t,
     prot: ProtFlags,
 ) -> Result<()> {
-    Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop)
+    unsafe {
+        Errno::result(libc::mprotect(addr.as_ptr(), length, prot.bits()))
+            .map(drop)
+    }
 }
 
 /// synchronize a mapped region
@@ -551,11 +576,14 @@
 ///
 /// [`msync(2)`]: https://man7.org/linux/man-pages/man2/msync.2.html
 pub unsafe fn msync(
-    addr: *mut c_void,
+    addr: NonNull<c_void>,
     length: size_t,
     flags: MsFlags,
 ) -> Result<()> {
-    Errno::result(libc::msync(addr, length, flags.bits())).map(drop)
+    unsafe {
+        Errno::result(libc::msync(addr.as_ptr(), length, flags.bits()))
+            .map(drop)
+    }
 }
 
 #[cfg(not(target_os = "android"))]
@@ -576,11 +604,11 @@
     use std::os::unix::io::{FromRawFd, OwnedFd};
 
     let ret = name.with_nix_path(|cstr| {
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         unsafe {
             libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint)
         }
-        #[cfg(not(any(target_os = "macos", target_os = "ios")))]
+        #[cfg(not(apple_targets))]
         unsafe {
             libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t)
         }
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index bf047b3..93339d1 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -1,10 +1,8 @@
 //! Mostly platform-specific functionality
 #[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
+    freebsdlike,
     all(target_os = "linux", not(target_env = "uclibc")),
-    target_os = "macos",
+    apple_targets,
     target_os = "netbsd"
 ))]
 feature! {
@@ -15,41 +13,31 @@
 feature! {
     #![feature = "event"]
 
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     #[allow(missing_docs)]
     pub mod epoll;
 
-    #[cfg(any(target_os = "dragonfly",
-              target_os = "freebsd",
-              target_os = "ios",
-              target_os = "macos",
-              target_os = "netbsd",
-              target_os = "openbsd"))]
+    #[cfg(bsd)]
     pub mod event;
 
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(any(linux_android, target_os = "freebsd"))]
     #[allow(missing_docs)]
     pub mod eventfd;
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "linux",
-    target_os = "redox",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "illumos",
-    target_os = "openbsd"
-))]
+#[cfg(target_os = "linux")]
+feature! {
+    #![feature = "fanotify"]
+    pub mod fanotify;
+}
+
+#[cfg(any(bsd, linux_android, target_os = "redox", solarish))]
 #[cfg(feature = "ioctl")]
 #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
 #[macro_use]
 pub mod ioctl;
 
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
 feature! {
     #![feature = "fs"]
     pub mod memfd;
@@ -78,15 +66,7 @@
     pub mod pthread;
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd"
-))]
+#[cfg(any(linux_android, bsd))]
 feature! {
     #![feature = "ptrace"]
     #[allow(missing_docs)]
@@ -99,7 +79,7 @@
     pub mod quota;
 }
 
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "linux", netbsdlike))]
 feature! {
     #![feature = "reboot"]
     pub mod reboot;
@@ -108,7 +88,7 @@
 #[cfg(not(any(
     target_os = "redox",
     target_os = "fuchsia",
-    target_os = "illumos",
+    solarish,
     target_os = "haiku"
 )))]
 feature! {
@@ -121,14 +101,7 @@
     pub mod select;
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "linux",
-    target_os = "macos"
-))]
+#[cfg(any(linux_android, freebsdlike, apple_targets, solarish))]
 feature! {
     #![feature = "zerocopy"]
     pub mod sendfile;
@@ -136,7 +109,7 @@
 
 pub mod signal;
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 feature! {
     #![feature = "signal"]
     #[allow(missing_docs)]
@@ -155,15 +128,7 @@
     pub mod stat;
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "linux",
-    target_os = "macos",
-    target_os = "openbsd"
-))]
+#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "openbsd"))]
 feature! {
     #![feature = "fs"]
     pub mod statfs;
@@ -174,8 +139,7 @@
     pub mod statvfs;
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub mod sysinfo;
 
@@ -203,13 +167,13 @@
     pub mod wait;
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 feature! {
     #![feature = "inotify"]
     pub mod inotify;
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 feature! {
     #![feature = "time"]
     pub mod timerfd;
@@ -218,7 +182,7 @@
 #[cfg(all(
     any(
         target_os = "freebsd",
-        target_os = "illumos",
+        solarish,
         target_os = "linux",
         target_os = "netbsd"
     ),
diff --git a/src/sys/personality.rs b/src/sys/personality.rs
index 30231dd..a4cfb5e 100644
--- a/src/sys/personality.rs
+++ b/src/sys/personality.rs
@@ -21,7 +21,6 @@
         ADDR_LIMIT_3GB;
         /// User-space function pointers to signal handlers point to descriptors.
         #[cfg(not(any(target_env = "musl", target_env = "uclibc")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         FDPIC_FUNCPTRS;
         /// Map page 0 as read-only.
         MMAP_PAGE_ZERO;
@@ -43,7 +42,6 @@
         ///
         /// [`uname(2)`]: https://man7.org/linux/man-pages/man2/uname.2.html
         #[cfg(not(any(target_env = "musl", target_env = "uclibc")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         UNAME26;
         /// No effects.
         WHOLE_SECONDS;
diff --git a/src/sys/prctl.rs b/src/sys/prctl.rs
index 995382c..42324be 100644
--- a/src/sys/prctl.rs
+++ b/src/sys/prctl.rs
@@ -50,7 +50,9 @@
     // prctl writes into this var
     let mut subreaper: c_int = 0;
 
-    let res = unsafe { libc::prctl(libc::PR_GET_CHILD_SUBREAPER, &mut subreaper, 0, 0, 0) };
+    let res = unsafe {
+        libc::prctl(libc::PR_GET_CHILD_SUBREAPER, &mut subreaper, 0, 0, 0)
+    };
 
     Errno::result(res).map(|_| subreaper != 0)
 }
@@ -78,7 +80,9 @@
 
 /// Clear the thread memory corruption kill policy and use the system-wide default
 pub fn clear_mce_kill() -> Result<()> {
-    let res = unsafe { libc::prctl(libc::PR_MCE_KILL, libc::PR_MCE_KILL_CLEAR, 0, 0, 0) };
+    let res = unsafe {
+        libc::prctl(libc::PR_MCE_KILL, libc::PR_MCE_KILL_CLEAR, 0, 0, 0)
+    };
 
     Errno::result(res).map(drop)
 }
@@ -151,10 +155,11 @@
 
     let res = unsafe { libc::prctl(libc::PR_GET_NAME, &buf, 0, 0, 0) };
 
-    let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
-    let name = CStr::from_bytes_with_nul(&buf[..=len]).map_err(|_| Errno::EINVAL)?;
-
-    Errno::result(res).map(|_| name.to_owned())
+    Errno::result(res).and_then(|_| {
+        CStr::from_bytes_until_nul(&buf)
+            .map(CStr::to_owned)
+            .map_err(|_| Errno::EINVAL)
+    })
 }
 
 /// Sets the timer slack value for the calling thread. Timer slack is used by the kernel to group
@@ -174,14 +179,16 @@
 
 /// Disable all performance counters attached to the calling process.
 pub fn task_perf_events_disable() -> Result<()> {
-    let res = unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_DISABLE, 0, 0, 0, 0) };
+    let res =
+        unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_DISABLE, 0, 0, 0, 0) };
 
     Errno::result(res).map(drop)
 }
 
 /// Enable all performance counters attached to the calling process.
 pub fn task_perf_events_enable() -> Result<()> {
-    let res = unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_ENABLE, 0, 0, 0, 0) };
+    let res =
+        unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_ENABLE, 0, 0, 0, 0) };
 
     Errno::result(res).map(drop)
 }
diff --git a/src/sys/ptrace/bsd.rs b/src/sys/ptrace/bsd.rs
index ba267c6..3dd4862 100644
--- a/src/sys/ptrace/bsd.rs
+++ b/src/sys/ptrace/bsd.rs
@@ -9,10 +9,7 @@
 pub type RequestType = c_int;
 
 cfg_if! {
-    if #[cfg(any(target_os = "dragonfly",
-                 target_os = "freebsd",
-                 target_os = "macos",
-                 target_os = "openbsd"))] {
+    if #[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))] {
         #[doc(hidden)]
         pub type AddressType = *mut ::libc::c_char;
     } else {
@@ -29,33 +26,26 @@
         PT_TRACE_ME,
         PT_READ_I,
         PT_READ_D,
-        #[cfg(target_os = "macos")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         PT_READ_U,
         PT_WRITE_I,
         PT_WRITE_D,
-        #[cfg(target_os = "macos")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         PT_WRITE_U,
         PT_CONTINUE,
         PT_KILL,
-        #[cfg(any(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "macos"),
+        #[cfg(any(any(freebsdlike, apple_targets),
                   all(target_os = "openbsd", target_arch = "x86_64"),
                   all(target_os = "netbsd", any(target_arch = "x86_64",
                                                 target_arch = "powerpc"))))]
         PT_STEP,
         PT_ATTACH,
         PT_DETACH,
-        #[cfg(target_os = "macos")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         PT_SIGEXC,
-        #[cfg(target_os = "macos")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         PT_THUPDATE,
-        #[cfg(target_os = "macos")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(apple_targets)]
         PT_ATTACHEXC
     }
 }
@@ -66,13 +56,15 @@
     addr: AddressType,
     data: c_int,
 ) -> Result<c_int> {
-    Errno::result(libc::ptrace(
-        request as RequestType,
-        libc::pid_t::from(pid),
-        addr,
-        data,
-    ))
-    .map(|_| 0)
+    unsafe {
+        Errno::result(libc::ptrace(
+            request as RequestType,
+            libc::pid_t::from(pid),
+            addr,
+            data,
+        ))
+        .map(|_| 0)
+    }
 }
 
 /// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)`
@@ -157,7 +149,7 @@
 /// }
 /// ```
 #[cfg(any(
-    any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"),
+    any(freebsdlike, apple_targets),
     all(target_os = "openbsd", target_arch = "x86_64"),
     all(
         target_os = "netbsd",
diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs
index 8c134cf..26544e1 100644
--- a/src/sys/ptrace/linux.rs
+++ b/src/sys/ptrace/linux.rs
@@ -53,28 +53,36 @@
         #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
                   all(target_os = "linux", any(target_env = "musl",
                                                target_arch = "mips",
+                                               target_arch = "mips32r6",
                                                target_arch = "mips64",
+                                               target_arch = "mips64r6",
                                                target_arch = "x86_64",
                                                target_pointer_width = "32"))))]
         PTRACE_GETREGS,
         #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
                   all(target_os = "linux", any(target_env = "musl",
                                                target_arch = "mips",
+                                               target_arch = "mips32r6",
                                                target_arch = "mips64",
+                                               target_arch = "mips64r6",
                                                target_arch = "x86_64",
                                                target_pointer_width = "32"))))]
         PTRACE_SETREGS,
         #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
                   all(target_os = "linux", any(target_env = "musl",
                                                target_arch = "mips",
+                                               target_arch = "mips32r6",
                                                target_arch = "mips64",
+                                               target_arch = "mips64r6",
                                                target_arch = "x86_64",
                                                target_pointer_width = "32"))))]
         PTRACE_GETFPREGS,
         #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
                   all(target_os = "linux", any(target_env = "musl",
                                                target_arch = "mips",
+                                               target_arch = "mips32r6",
                                                target_arch = "mips64",
+                                               target_arch = "mips64r6",
                                                target_arch = "x86_64",
                                                target_pointer_width = "32"))))]
         PTRACE_SETFPREGS,
@@ -82,13 +90,17 @@
         PTRACE_DETACH,
         #[cfg(all(target_os = "linux", any(target_env = "musl",
                                            target_arch = "mips",
+                                           target_arch = "mips32r6",
                                            target_arch = "mips64",
+                                           target_arch = "mips64r6",
                                            target_arch = "x86",
                                            target_arch = "x86_64")))]
         PTRACE_GETFPXREGS,
         #[cfg(all(target_os = "linux", any(target_env = "musl",
                                            target_arch = "mips",
+                                           target_arch = "mips32r6",
                                            target_arch = "mips64",
+                                           target_arch = "mips64r6",
                                            target_arch = "x86",
                                            target_arch = "x86_64")))]
         PTRACE_SETFPXREGS,
@@ -98,22 +110,28 @@
         PTRACE_GETSIGINFO,
         PTRACE_SETSIGINFO,
         #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
-                                               target_arch = "mips64"))))]
+                                               target_arch = "mips32r6",
+                                               target_arch = "mips64",
+                                               target_arch = "mips64r6"))))]
         PTRACE_GETREGSET,
         #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
-                                               target_arch = "mips64"))))]
+                                               target_arch = "mips32r6",
+                                               target_arch = "mips64",
+                                               target_arch = "mips64r6"))))]
         PTRACE_SETREGSET,
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         PTRACE_SEIZE,
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         PTRACE_INTERRUPT,
         #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
-                                               target_arch = "mips64"))))]
+                                               target_arch = "mips32r6",
+                                               target_arch = "mips64",
+                                               target_arch = "mips64r6"))))]
         PTRACE_LISTEN,
         #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
-                                               target_arch = "mips64"))))]
+                                               target_arch = "mips32r6",
+                                               target_arch = "mips64",
+                                               target_arch = "mips64r6"))))]
         PTRACE_PEEKSIGINFO,
         #[cfg(all(target_os = "linux", target_env = "gnu",
                   any(target_arch = "x86", target_arch = "x86_64")))]
@@ -241,13 +259,13 @@
 /// and therefore use the data field to return values. This function handles these
 /// requests.
 fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
-    let mut data = mem::MaybeUninit::uninit();
+    let mut data = mem::MaybeUninit::<T>::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,
+            data.as_mut_ptr(),
         )
     };
     Errno::result(res)?;
@@ -260,13 +278,15 @@
     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 {
+        Errno::result(libc::ptrace(
+            request as RequestType,
+            libc::pid_t::from(pid),
+            addr,
+            data,
+        ))
+        .map(|_| 0)
+    }
 }
 
 /// Set options, as with `ptrace(PTRACE_SETOPTIONS, ...)`.
@@ -381,7 +401,6 @@
 ///
 /// Attaches to the process specified in pid, making it a tracee of the calling process.
 #[cfg(target_os = "linux")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub fn seize(pid: Pid, options: Options) -> Result<()> {
     unsafe {
         ptrace_other(
@@ -428,7 +447,6 @@
 ///
 /// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)`
 #[cfg(target_os = "linux")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub fn interrupt(pid: Pid) -> Result<()> {
     unsafe {
         ptrace_other(
@@ -535,7 +553,7 @@
     addr: AddressType,
     data: *mut c_void,
 ) -> Result<()> {
-    ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
+    unsafe { ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop) }
 }
 
 /// Reads a word from a user area at `offset`, as with ptrace(PTRACE_PEEKUSER, ...).
@@ -556,5 +574,7 @@
     offset: AddressType,
     data: *mut c_void,
 ) -> Result<()> {
-    ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data).map(drop)
+    unsafe {
+        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 88648ac..c059797 100644
--- a/src/sys/ptrace/mod.rs
+++ b/src/sys/ptrace/mod.rs
@@ -1,25 +1,13 @@
 //! Provides helpers for making ptrace system calls
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 mod linux;
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 pub use self::linux::*;
 
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd"
-))]
+#[cfg(bsd)]
 mod bsd;
 
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd"
-))]
+#[cfg(bsd)]
 pub use self::bsd::*;
diff --git a/src/sys/quota.rs b/src/sys/quota.rs
index a32d07a..2d12b85 100644
--- a/src/sys/quota.rs
+++ b/src/sys/quota.rs
@@ -264,7 +264,7 @@
 ) -> 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;
+        let p: *mut c_char = path_copy.as_mut_ptr().cast();
         quotactl(
             QuotaCmd(QuotaSubCmd::Q_QUOTAON, which),
             Some(special),
@@ -308,12 +308,12 @@
     special: &P,
     id: c_int,
 ) -> Result<Dqblk> {
-    let mut dqblk = mem::MaybeUninit::uninit();
+    let mut dqblk = mem::MaybeUninit::<libc::dqblk>::uninit();
     quotactl(
         QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which),
         Some(special),
         id,
-        dqblk.as_mut_ptr() as *mut c_char,
+        dqblk.as_mut_ptr().cast(),
     )?;
     Ok(unsafe { Dqblk(dqblk.assume_init()) })
 }
diff --git a/src/sys/reboot.rs b/src/sys/reboot.rs
index 02d9816..2e4d888 100644
--- a/src/sys/reboot.rs
+++ b/src/sys/reboot.rs
@@ -1,48 +1,141 @@
-//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete.
+//! Reboot/shutdown
+//!
+//! On Linux, This can also be used to enable/disable Ctrl-Alt-Delete.
 
 use crate::errno::Errno;
 use crate::Result;
+use cfg_if::cfg_if;
 use std::convert::Infallible;
-use std::mem::drop;
 
-libc_enum! {
-    /// How exactly should the system be rebooted.
-    ///
-    /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for
-    /// enabling/disabling Ctrl-Alt-Delete.
-    #[repr(i32)]
-    #[non_exhaustive]
-    pub enum RebootMode {
-        /// Halt the system.
-        RB_HALT_SYSTEM,
-        /// Execute a kernel that has been loaded earlier with
-        /// [`kexec_load(2)`](https://man7.org/linux/man-pages/man2/kexec_load.2.html).
-        RB_KEXEC,
-        /// Stop the system and switch off power, if possible.
-        RB_POWER_OFF,
-        /// Restart the system.
-        RB_AUTOBOOT,
-        // we do not support Restart2.
-        /// Suspend the system using software suspend.
-        RB_SW_SUSPEND,
+cfg_if! {
+    if #[cfg(target_os = "linux")] {
+        use std::mem::drop;
+
+        libc_enum! {
+            /// How exactly should the system be rebooted.
+            ///
+            /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for
+            /// enabling/disabling Ctrl-Alt-Delete.
+            #[repr(i32)]
+            #[non_exhaustive]
+            pub enum RebootMode {
+                /// Halt the system.
+                RB_HALT_SYSTEM,
+                /// Execute a kernel that has been loaded earlier with
+                /// [`kexec_load(2)`](https://man7.org/linux/man-pages/man2/kexec_load.2.html).
+                RB_KEXEC,
+                /// Stop the system and switch off power, if possible.
+                RB_POWER_OFF,
+                /// Restart the system.
+                RB_AUTOBOOT,
+                // we do not support Restart2.
+                /// Suspend the system using software suspend.
+                RB_SW_SUSPEND,
+            }
+        }
+
+        /// Reboots or shuts down the system.
+        pub fn reboot(how: RebootMode) -> Result<Infallible> {
+            unsafe { libc::reboot(how as libc::c_int) };
+            Err(Errno::last())
+        }
+
+        /// Enable or disable the reboot keystroke (Ctrl-Alt-Delete).
+        ///
+        /// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C.
+        pub fn set_cad_enabled(enable: bool) -> Result<()> {
+            let cmd = if enable {
+                libc::RB_ENABLE_CAD
+            } else {
+                libc::RB_DISABLE_CAD
+            };
+            let res = unsafe { libc::reboot(cmd) };
+            Errno::result(res).map(drop)
+        }
+    } else if #[cfg(netbsdlike)] {
+        use libc::c_int;
+
+        libc_bitflags! {
+            /// How exactly should the system be rebooted.
+            pub struct RebootMode: c_int {
+                /// The default, causing the system to reboot in its usual fashion.
+                RB_AUTOBOOT;
+                /// Interpreted by the bootstrap program itself, causing it to
+                /// prompt on the console as to what file should be booted.
+                /// Normally, the system is booted from the file “xx(0,0)bsd”,
+                /// where xx is the default disk name, without prompting for
+                /// the file name.
+                RB_ASKNAME;
+                /// Dump kernel memory before rebooting; see `savecore(8)` for
+                /// more information.
+                RB_DUMP;
+                /// The processor is simply halted; no reboot takes place.
+                RB_HALT;
+                /// Power off the system if the system hardware supports the
+                /// function, otherwise it has no effect.
+                ///
+                /// Should be used in conjunction with `RB_HALT`.
+                RB_POWERDOWN;
+                /// By default, the system will halt if `reboot()` is called during
+                /// startup (before the system has finished autoconfiguration), even
+                /// if `RB_HALT` is not specified. This is because `panic(9)`s
+                /// during startup will probably just repeat on the next boot.
+                /// Use of this option implies that the user has requested the
+                /// action specified (for example, using the `ddb(4)` boot reboot
+                /// command), so the system will reboot if a halt is not explicitly
+                /// requested.
+                #[cfg(target_os = "openbsd")]
+                RB_USERREQ;
+                /// Load the symbol table and enable a built-in debugger in the
+                /// system. This option will have no useful function if the kernel
+                /// is not configured for debugging. Several other options have
+                /// different meaning if combined with this option, although their
+                /// use may not be possible via the `reboot()` call. See `ddb(4)` for
+                /// more information.
+                RB_KDB;
+                /// Normally, the disks are sync'd (see `sync(8)`) before the
+                /// processor is halted or rebooted. This option may be useful
+                /// if file system changes have been made manually or if the
+                /// processor is on fire.
+                RB_NOSYNC;
+                /// Normally, the reboot procedure involves an automatic disk
+                /// consistency check and then multi-user operations. `RB_SINGLE`
+                /// prevents this, booting the system with a single-user shell on
+                /// the console. `RB_SINGLE` is actually interpreted by the `init(8)`
+                /// program in the newly booted system.
+                ///
+                /// When no options are given (i.e., `RB_AUTOBOOT` is used), the
+                /// system is rebooted from file /bsd in the root file system of
+                /// unit 0 of a disk chosen in a processor specific way. An automatic
+                /// consistency check of the disks is normally performed (see `fsck(8)`).
+                RB_SINGLE;
+                /// Initially invoke the `userconf(4)` facility when the system
+                /// starts up again, if it has been compiled into the kernel
+                /// that is loaded.
+                #[cfg(target_os = "netbsd")]
+                RB_USERCONF;
+                /// Don't update the hardware clock from the system clock, presumably
+                /// because the system clock is suspect.
+                #[cfg(target_os = "openbsd")]
+                RB_TIMEBAD;
+            }
+        }
+
+        /// Reboot system or halt processor
+        ///
+        /// For more information, see the man pages:
+        ///
+        /// * [NetBSD](https://man.netbsd.org/reboot.2)
+        /// * [OpenBSD](https://man.openbsd.org/reboot.2)
+        #[cfg(netbsdlike)]
+        pub fn reboot(how: RebootMode) -> Result<Infallible> {
+            #[cfg(target_os = "openbsd")]
+            unsafe { libc::reboot(how.bits()) };
+            #[cfg(target_os = "netbsd")]
+            unsafe { libc::reboot(how.bits(), std::ptr::null_mut()) };
+
+            Err(Errno::last())
+        }
     }
 }
 
-/// Reboots or shuts down the system.
-pub fn reboot(how: RebootMode) -> Result<Infallible> {
-    unsafe { libc::reboot(how as libc::c_int) };
-    Err(Errno::last())
-}
-
-/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete).
-///
-/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C.
-pub fn set_cad_enabled(enable: bool) -> Result<()> {
-    let cmd = if enable {
-        libc::RB_ENABLE_CAD
-    } else {
-        libc::RB_DISABLE_CAD
-    };
-    let res = unsafe { libc::reboot(cmd) };
-    Errno::result(res).map(drop)
-}
diff --git a/src/sys/resource.rs b/src/sys/resource.rs
index f42d32e..7131507 100644
--- a/src/sys/resource.rs
+++ b/src/sys/resource.rs
@@ -10,16 +10,14 @@
 use std::mem;
 
 cfg_if! {
-    if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{
+    if #[cfg(any(
+        all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")),
+        target_os = "hurd"
+    ))]{
         use libc::{__rlimit_resource_t, rlimit};
     } else if #[cfg(any(
-        target_os = "freebsd",
-        target_os = "openbsd",
-        target_os = "netbsd",
-        target_os = "macos",
-        target_os = "ios",
+        bsd,
         target_os = "android",
-        target_os = "dragonfly",
         target_os = "aix",
         all(target_os = "linux", not(target_env = "gnu"))
     ))]{
@@ -43,22 +41,19 @@
     //
     // https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html
     // https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs
-    #[cfg_attr(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), repr(u32))]
     #[cfg_attr(any(
-            target_os = "freebsd",
-            target_os = "openbsd",
-            target_os = "netbsd",
-            target_os = "macos",
-            target_os = "ios",
+            all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")),
+            target_os = "hurd"
+        ), repr(u32))]
+    #[cfg_attr(any(
+            bsd,
             target_os = "android",
-            target_os = "dragonfly",
             target_os = "aix",
             all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc")))
         ), repr(i32))]
     #[non_exhaustive]
     pub enum Resource {
-        #[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(not(any(target_os = "freebsd", netbsdlike)))]
         /// The maximum amount (in bytes) of virtual memory the process is
         /// allowed to map.
         RLIMIT_AS,
@@ -77,102 +72,78 @@
         RLIMIT_STACK,
 
         #[cfg(target_os = "freebsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         /// The maximum number of kqueues this user id is allowed to create.
         RLIMIT_KQUEUES,
 
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         /// A limit on the combined number of flock locks and fcntl leases that
         /// this process may establish.
         RLIMIT_LOCKS,
 
-        #[cfg(any(
-            target_os = "android",
-            target_os = "freebsd",
-            target_os = "openbsd",
-            target_os = "linux",
-            target_os = "netbsd"
-        ))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, target_os = "freebsd", netbsdlike))]
         /// The maximum size (in bytes) which a process may lock into memory
         /// using the mlock(2) system call.
         RLIMIT_MEMLOCK,
 
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         /// A limit on the number of bytes that can be allocated for POSIX
         /// message queues  for  the  real  user  ID  of  the  calling process.
         RLIMIT_MSGQUEUE,
 
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         /// A ceiling to which the process's nice value can be raised using
         /// setpriority or nice.
         RLIMIT_NICE,
 
         #[cfg(any(
-            target_os = "android",
+            linux_android,
             target_os = "freebsd",
-            target_os = "netbsd",
-            target_os = "openbsd",
-            target_os = "linux",
+            netbsdlike,
             target_os = "aix",
         ))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         /// The maximum number of simultaneous processes for this user id.
         RLIMIT_NPROC,
 
         #[cfg(target_os = "freebsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         /// The maximum number of pseudo-terminals this user id is allowed to
         /// create.
         RLIMIT_NPTS,
 
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
             target_os = "freebsd",
-            target_os = "netbsd",
-            target_os = "openbsd",
-            target_os = "linux",
+            netbsdlike,
             target_os = "aix",
         ))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         /// When there is memory pressure and swap is available, prioritize
         /// eviction of a process' resident pages beyond this amount (in bytes).
         RLIMIT_RSS,
 
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         /// A ceiling on the real-time priority that may be set for this process
         /// using sched_setscheduler and  sched_set‐ param.
         RLIMIT_RTPRIO,
 
         #[cfg(any(target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         /// A limit (in microseconds) on the amount of CPU time that a process
         /// scheduled under a real-time scheduling policy may con‐ sume without
         /// making a blocking system call.
         RLIMIT_RTTIME,
 
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         /// A limit on the number of signals that may be queued for the real
         /// user ID of the  calling  process.
         RLIMIT_SIGPENDING,
 
-        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         /// The maximum size (in bytes) of socket buffer usage for this user.
         RLIMIT_SBSIZE,
 
         #[cfg(target_os = "freebsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         /// The maximum size (in bytes) of the swap space that may be reserved
         /// or used by all of this user id's processes.
         RLIMIT_SWAP,
 
         #[cfg(target_os = "freebsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         /// An alias for RLIMIT_AS.
         RLIMIT_VMEM,
     }
@@ -206,7 +177,10 @@
     let mut old_rlim = mem::MaybeUninit::<rlimit>::uninit();
 
     cfg_if! {
-        if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{
+        if #[cfg(any(
+            all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")),
+            target_os = "hurd"
+        ))] {
             let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) };
         } else {
             let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) };
@@ -259,7 +233,10 @@
         rlim_max: hard_limit,
     };
     cfg_if! {
-        if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{
+        if #[cfg(any(
+            all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")),
+            target_os = "hurd",
+        ))]{
             let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) };
         }else{
             let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) };
@@ -281,7 +258,6 @@
         RUSAGE_CHILDREN,
 
         #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         /// Resource usage for the calling thread.
         RUSAGE_THREAD,
     }
@@ -420,28 +396,3 @@
         Errno::result(res).map(|_| Usage(rusage.assume_init()))
     }
 }
-
-#[cfg(test)]
-mod test {
-    use super::{getrusage, UsageWho};
-
-    #[test]
-    pub fn test_self_cpu_time() {
-        // Make sure some CPU time is used.
-        let mut numbers: Vec<i32> = (1..1_000_000).collect();
-        numbers.iter_mut().for_each(|item| *item *= 2);
-
-        // FIXME: this is here to help ensure the compiler does not optimize the whole
-        // thing away. Replace the assert with test::black_box once stabilized.
-        assert_eq!(numbers[100..200].iter().sum::<i32>(), 30_100);
-
-        let usage = getrusage(UsageWho::RUSAGE_SELF)
-            .expect("Failed to call getrusage for SELF");
-        let rusage = usage.as_ref();
-
-        let user = usage.user_time();
-        assert!(user.tv_sec() > 0 || user.tv_usec() > 0);
-        assert_eq!(user.tv_sec(), rusage.ru_utime.tv_sec);
-        assert_eq!(user.tv_usec(), rusage.ru_utime.tv_usec);
-    }
-}
diff --git a/src/sys/select.rs b/src/sys/select.rs
index 0e2193b..64a8e25 100644
--- a/src/sys/select.rs
+++ b/src/sys/select.rs
@@ -7,7 +7,7 @@
 use std::iter::FusedIterator;
 use std::mem;
 use std::ops::Range;
-use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
+use std::os::unix::io::{AsRawFd, BorrowedFd, RawFd};
 use std::ptr::{null, null_mut};
 
 pub use libc::FD_SETSIZE;
@@ -41,21 +41,21 @@
     }
 
     /// Add a file descriptor to an `FdSet`
-    pub fn insert<Fd: AsFd>(&mut self, fd: &'fd Fd) {
-        assert_fd_valid(fd.as_fd().as_raw_fd());
-        unsafe { libc::FD_SET(fd.as_fd().as_raw_fd(), &mut self.set) };
+    pub fn insert(&mut self, fd: BorrowedFd<'fd>) {
+        assert_fd_valid(fd.as_raw_fd());
+        unsafe { libc::FD_SET(fd.as_raw_fd(), &mut self.set) };
     }
 
     /// Remove a file descriptor from an `FdSet`
-    pub fn remove<Fd: AsFd>(&mut self, fd: &'fd Fd) {
-        assert_fd_valid(fd.as_fd().as_raw_fd());
-        unsafe { libc::FD_CLR(fd.as_fd().as_raw_fd(), &mut self.set) };
+    pub fn remove(&mut self, fd: BorrowedFd<'fd>) {
+        assert_fd_valid(fd.as_raw_fd());
+        unsafe { libc::FD_CLR(fd.as_raw_fd(), &mut self.set) };
     }
 
     /// Test an `FdSet` for the presence of a certain file descriptor.
-    pub fn contains<Fd: AsFd>(&self, fd: &'fd Fd) -> bool {
-        assert_fd_valid(fd.as_fd().as_raw_fd());
-        unsafe { libc::FD_ISSET(fd.as_fd().as_raw_fd(), &self.set) }
+    pub fn contains(&self, fd: BorrowedFd<'fd>) -> bool {
+        assert_fd_valid(fd.as_raw_fd());
+        unsafe { libc::FD_ISSET(fd.as_raw_fd(), &self.set) }
     }
 
     /// Remove all file descriptors from this `FdSet`.
@@ -77,8 +77,8 @@
     /// let fd_four = unsafe {BorrowedFd::borrow_raw(4)};
     /// let fd_nine = unsafe {BorrowedFd::borrow_raw(9)};
     /// let mut set = FdSet::new();
-    /// set.insert(&fd_four);
-    /// set.insert(&fd_nine);
+    /// set.insert(fd_four);
+    /// set.insert(fd_nine);
     /// assert_eq!(set.highest().map(|borrowed_fd|borrowed_fd.as_raw_fd()), Some(9));
     /// ```
     ///
@@ -101,8 +101,8 @@
     /// let mut set = FdSet::new();
     /// let fd_four = unsafe {BorrowedFd::borrow_raw(4)};
     /// let fd_nine = unsafe {BorrowedFd::borrow_raw(9)};
-    /// set.insert(&fd_four);
-    /// set.insert(&fd_nine);
+    /// set.insert(fd_four);
+    /// set.insert(fd_nine);
     /// let fds: Vec<RawFd> = set.fds(None).map(|borrowed_fd|borrowed_fd.as_raw_fd()).collect();
     /// assert_eq!(fds, vec![4, 9]);
     /// ```
@@ -134,7 +134,7 @@
     fn next(&mut self) -> Option<Self::Item> {
         for i in &mut self.range {
             let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
-            if self.set.contains(&borrowed_i) {
+            if self.set.contains(borrowed_i) {
                 return Some(borrowed_i);
             }
         }
@@ -153,7 +153,7 @@
     fn next_back(&mut self) -> Option<BorrowedFd<'fd>> {
         while let Some(i) = self.range.next_back() {
             let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
-            if self.set.contains(&borrowed_i) {
+            if self.set.contains(borrowed_i) {
                 return Some(borrowed_i);
             }
         }
@@ -317,238 +317,3 @@
     Errno::result(res)
 }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::sys::time::{TimeVal, TimeValLike};
-    use crate::unistd::{close, pipe, write};
-    use std::os::unix::io::{FromRawFd, OwnedFd, RawFd};
-
-    #[test]
-    fn fdset_insert() {
-        let mut fd_set = FdSet::new();
-
-        for i in 0..FD_SETSIZE {
-            let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
-            assert!(!fd_set.contains(&borrowed_i));
-        }
-
-        let fd_seven = unsafe { BorrowedFd::borrow_raw(7) };
-        fd_set.insert(&fd_seven);
-
-        assert!(fd_set.contains(&fd_seven));
-    }
-
-    #[test]
-    fn fdset_remove() {
-        let mut fd_set = FdSet::new();
-
-        for i in 0..FD_SETSIZE {
-            let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
-            assert!(!fd_set.contains(&borrowed_i));
-        }
-
-        let fd_seven = unsafe { BorrowedFd::borrow_raw(7) };
-        fd_set.insert(&fd_seven);
-        fd_set.remove(&fd_seven);
-
-        for i in 0..FD_SETSIZE {
-            let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
-            assert!(!fd_set.contains(&borrowed_i));
-        }
-    }
-
-    #[test]
-    #[allow(non_snake_case)]
-    fn fdset_clear() {
-        let mut fd_set = FdSet::new();
-        let fd_one = unsafe { BorrowedFd::borrow_raw(1) };
-        let fd_FD_SETSIZE_devided_by_two =
-            unsafe { BorrowedFd::borrow_raw((FD_SETSIZE / 2) as RawFd) };
-        let fd_FD_SETSIZE_minus_one =
-            unsafe { BorrowedFd::borrow_raw((FD_SETSIZE - 1) as RawFd) };
-        fd_set.insert(&fd_one);
-        fd_set.insert(&fd_FD_SETSIZE_devided_by_two);
-        fd_set.insert(&fd_FD_SETSIZE_minus_one);
-
-        fd_set.clear();
-
-        for i in 0..FD_SETSIZE {
-            let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
-            assert!(!fd_set.contains(&borrowed_i));
-        }
-    }
-
-    #[test]
-    fn fdset_highest() {
-        let mut set = FdSet::new();
-        assert_eq!(
-            set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
-            None
-        );
-        let fd_zero = unsafe { BorrowedFd::borrow_raw(0) };
-        let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) };
-        set.insert(&fd_zero);
-        assert_eq!(
-            set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
-            Some(0)
-        );
-        set.insert(&fd_ninety);
-        assert_eq!(
-            set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
-            Some(90)
-        );
-        set.remove(&fd_zero);
-        assert_eq!(
-            set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
-            Some(90)
-        );
-        set.remove(&fd_ninety);
-        assert_eq!(
-            set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
-            None
-        );
-
-        let fd_four = unsafe { BorrowedFd::borrow_raw(4) };
-        let fd_five = unsafe { BorrowedFd::borrow_raw(5) };
-        let fd_seven = unsafe { BorrowedFd::borrow_raw(7) };
-        set.insert(&fd_four);
-        set.insert(&fd_five);
-        set.insert(&fd_seven);
-        assert_eq!(
-            set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
-            Some(7)
-        );
-    }
-
-    #[test]
-    fn fdset_fds() {
-        let mut set = FdSet::new();
-        let fd_zero = unsafe { BorrowedFd::borrow_raw(0) };
-        let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) };
-        assert_eq!(
-            set.fds(None)
-                .map(|borrowed_fd| borrowed_fd.as_raw_fd())
-                .collect::<Vec<_>>(),
-            vec![]
-        );
-        set.insert(&fd_zero);
-        assert_eq!(
-            set.fds(None)
-                .map(|borrowed_fd| borrowed_fd.as_raw_fd())
-                .collect::<Vec<_>>(),
-            vec![0]
-        );
-        set.insert(&fd_ninety);
-        assert_eq!(
-            set.fds(None)
-                .map(|borrowed_fd| borrowed_fd.as_raw_fd())
-                .collect::<Vec<_>>(),
-            vec![0, 90]
-        );
-
-        // highest limit
-        assert_eq!(
-            set.fds(Some(89))
-                .map(|borrowed_fd| borrowed_fd.as_raw_fd())
-                .collect::<Vec<_>>(),
-            vec![0]
-        );
-        assert_eq!(
-            set.fds(Some(90))
-                .map(|borrowed_fd| borrowed_fd.as_raw_fd())
-                .collect::<Vec<_>>(),
-            vec![0, 90]
-        );
-    }
-
-    #[test]
-    fn test_select() {
-        let (r1, w1) = pipe().unwrap();
-        let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
-        let w1 = unsafe { OwnedFd::from_raw_fd(w1) };
-        let (r2, _w2) = pipe().unwrap();
-        let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
-
-        write(w1.as_raw_fd(), b"hi!").unwrap();
-        let mut fd_set = FdSet::new();
-        fd_set.insert(&r1);
-        fd_set.insert(&r2);
-
-        let mut timeout = TimeVal::seconds(10);
-        assert_eq!(
-            1,
-            select(None, &mut fd_set, None, None, &mut timeout).unwrap()
-        );
-        assert!(fd_set.contains(&r1));
-        assert!(!fd_set.contains(&r2));
-        close(_w2).unwrap();
-    }
-
-    #[test]
-    fn test_select_nfds() {
-        let (r1, w1) = pipe().unwrap();
-        let (r2, _w2) = pipe().unwrap();
-        let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
-        let w1 = unsafe { OwnedFd::from_raw_fd(w1) };
-        let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
-
-        write(w1.as_raw_fd(), b"hi!").unwrap();
-        let mut fd_set = FdSet::new();
-        fd_set.insert(&r1);
-        fd_set.insert(&r2);
-
-        let mut timeout = TimeVal::seconds(10);
-        {
-            assert_eq!(
-                1,
-                select(
-                    Some(
-                        fd_set
-                            .highest()
-                            .map(|borrowed_fd| borrowed_fd.as_raw_fd())
-                            .unwrap()
-                            + 1
-                    ),
-                    &mut fd_set,
-                    None,
-                    None,
-                    &mut timeout
-                )
-                .unwrap()
-            );
-        }
-        assert!(fd_set.contains(&r1));
-        assert!(!fd_set.contains(&r2));
-        close(_w2).unwrap();
-    }
-
-    #[test]
-    fn test_select_nfds2() {
-        let (r1, w1) = pipe().unwrap();
-        write(w1, b"hi!").unwrap();
-        let (r2, _w2) = pipe().unwrap();
-        let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
-        let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
-        let mut fd_set = FdSet::new();
-        fd_set.insert(&r1);
-        fd_set.insert(&r2);
-
-        let mut timeout = TimeVal::seconds(10);
-        assert_eq!(
-            1,
-            select(
-                std::cmp::max(r1.as_raw_fd(), r2.as_raw_fd()) + 1,
-                &mut fd_set,
-                None,
-                None,
-                &mut timeout
-            )
-            .unwrap()
-        );
-        assert!(fd_set.contains(&r1));
-        assert!(!fd_set.contains(&r2));
-        close(_w2).unwrap();
-    }
-}
diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs
index 9f3c333..d7452ed 100644
--- a/src/sys/sendfile.rs
+++ b/src/sys/sendfile.rs
@@ -20,9 +20,9 @@
 ///
 /// `in_fd` must support `mmap`-like operations and therefore cannot be a socket.
 ///
-/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html)
-#[cfg(any(target_os = "android", target_os = "linux"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) for Linux,
+/// see [the sendfile(2) man page.](https://docs.oracle.com/cd/E88353_01/html/E37843/sendfile-3c.html) for Solaris.
+#[cfg(any(linux_android, solarish))]
 pub fn sendfile<F1: AsFd, F2: AsFd>(
     out_fd: F1,
     in_fd: F2,
@@ -56,7 +56,6 @@
 ///
 /// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html)
 #[cfg(target_os = "linux")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub fn sendfile64<F1: AsFd, F2: AsFd>(
     out_fd: F1,
     in_fd: F2,
@@ -78,46 +77,82 @@
 }
 
 cfg_if! {
-    if #[cfg(any(target_os = "dragonfly",
-                 target_os = "freebsd",
-                 target_os = "ios",
-                 target_os = "macos"))] {
+    if #[cfg(any(freebsdlike, apple_targets))] {
         use std::io::IoSlice;
 
         #[derive(Clone, Debug)]
-        struct SendfileHeaderTrailer<'a>(
-            libc::sf_hdtr,
-            Option<Vec<IoSlice<'a>>>,
-            Option<Vec<IoSlice<'a>>>,
-        );
+        struct SendfileHeaderTrailer<'a> {
+            raw: libc::sf_hdtr,
+            _headers: Option<Vec<IoSlice<'a>>>,
+            _trailers: Option<Vec<IoSlice<'a>>>,
+        }
 
         impl<'a> SendfileHeaderTrailer<'a> {
             fn new(
                 headers: Option<&'a [&'a [u8]]>,
                 trailers: Option<&'a [&'a [u8]]>
             ) -> SendfileHeaderTrailer<'a> {
-                let header_iovecs: Option<Vec<IoSlice<'_>>> =
+                let mut header_iovecs: Option<Vec<IoSlice<'_>>> =
                     headers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect());
-                let trailer_iovecs: Option<Vec<IoSlice<'_>>> =
+                let mut trailer_iovecs: Option<Vec<IoSlice<'_>>> =
                     trailers.map(|s| s.iter().map(|b| IoSlice::new(b)).collect());
-                SendfileHeaderTrailer(
-                    libc::sf_hdtr {
+
+                SendfileHeaderTrailer {
+                    raw: libc::sf_hdtr {
                         headers: {
                             header_iovecs
-                                .as_ref()
-                                .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
+                                .as_mut()
+                                .map_or(ptr::null_mut(), |v| v.as_mut_ptr())
+                                .cast()
                         },
                         hdr_cnt: header_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32,
                         trailers: {
                             trailer_iovecs
-                                .as_ref()
-                                .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
+                                .as_mut()
+                                .map_or(ptr::null_mut(), |v| v.as_mut_ptr())
+                                .cast()
                         },
                         trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32
                     },
-                    header_iovecs,
-                    trailer_iovecs,
-                )
+                    _headers: header_iovecs,
+                    _trailers: trailer_iovecs,
+                }
+            }
+        }
+    } else if #[cfg(solarish)] {
+        use std::os::unix::io::BorrowedFd;
+        use std::marker::PhantomData;
+
+        #[derive(Debug, Copy, Clone)]
+        /// Mapping of the raw C sendfilevec_t struct
+        pub struct SendfileVec<'fd> {
+            raw: libc::sendfilevec_t,
+            phantom: PhantomData<BorrowedFd<'fd>>
+        }
+
+        impl<'fd> SendfileVec<'fd> {
+            /// initialises SendfileVec to send data directly from the process's address space
+            /// same in C with sfv_fd set to SFV_FD_SELF.
+            pub fn newself(
+                off: off_t,
+                len: usize
+            ) -> Self {
+                Self{raw: libc::sendfilevec_t{sfv_fd: libc::SFV_FD_SELF, sfv_flag: 0, sfv_off: off, sfv_len: len}, phantom: PhantomData}
+            }
+
+            /// initialises SendfileVec to send data from `fd`.
+            pub fn new(
+                fd: BorrowedFd<'fd>,
+                off: off_t,
+                len: usize
+            ) -> SendfileVec<'fd> {
+                Self{raw: libc::sendfilevec_t{sfv_fd: fd.as_raw_fd(), sfv_flag: 0, sfv_off:off, sfv_len: len}, phantom: PhantomData}
+            }
+        }
+
+        impl From<SendfileVec<'_>> for libc::sendfilevec_t {
+            fn from<'fd>(vec: SendfileVec) -> libc::sendfilevec_t {
+                vec.raw
             }
         }
     }
@@ -187,7 +222,7 @@
             let flags: u32 = (ra32 << 16) | (flags.bits() as u32);
             let mut bytes_sent: off_t = 0;
             let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
-            let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
+            let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr);
             let return_code = unsafe {
                 libc::sendfile(in_fd.as_fd().as_raw_fd(),
                                out_sock.as_fd().as_raw_fd(),
@@ -230,7 +265,7 @@
         ) -> (Result<()>, off_t) {
             let mut bytes_sent: off_t = 0;
             let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
-            let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
+            let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr);
             let return_code = unsafe {
                 libc::sendfile(in_fd.as_fd().as_raw_fd(),
                                out_sock.as_fd().as_raw_fd(),
@@ -242,7 +277,7 @@
             };
             (Errno::result(return_code).and(Ok(())), bytes_sent)
         }
-    } else if #[cfg(any(target_os = "ios", target_os = "macos"))] {
+    } else if #[cfg(apple_targets)] {
         /// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to
         /// `out_sock`.
         ///
@@ -276,7 +311,7 @@
         ) -> (Result<()>, off_t) {
             let mut len = count.unwrap_or(0);
             let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
-            let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
+            let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.raw as *const libc::sf_hdtr);
             let return_code = unsafe {
                 libc::sendfile(in_fd.as_fd().as_raw_fd(),
                                out_sock.as_fd().as_raw_fd(),
@@ -287,5 +322,30 @@
             };
             (Errno::result(return_code).and(Ok(())), len)
         }
+    } else if #[cfg(solarish)] {
+        /// Write data from the vec arrays to `out_sock` and returns a `Result` and a
+        /// count of bytes written.
+        ///
+        /// Each `SendfileVec` set needs to be instantiated either with `SendfileVec::new` or
+        /// `SendfileVec::newself`.
+        ///
+        /// The former allows to send data from a file descriptor through `fd`,
+        ///  from an offset `off` and for a given amount of data `len`.
+        ///
+        /// The latter allows to send data from the process's address space, from an offset `off`
+        /// and for a given amount of data `len`.
+        ///
+        /// For more information, see
+        /// [the sendfilev(3) man page.](https://illumos.org/man/3EXT/sendfilev)
+        pub fn sendfilev<F: AsFd>(
+            out_sock: F,
+            vec: &[SendfileVec]
+        ) -> (Result<()>, usize) {
+            let mut len = 0usize;
+            let return_code = unsafe {
+                libc::sendfilev(out_sock.as_fd().as_raw_fd(), vec.as_ptr() as *const libc::sendfilevec_t, vec.len() as i32, &mut len)
+            };
+            (Errno::result(return_code).and(Ok(())), len)
+        }
     }
 }
diff --git a/src/sys/signal.rs b/src/sys/signal.rs
index c946e4a..c9b593d 100644
--- a/src/sys/signal.rs
+++ b/src/sys/signal.rs
@@ -7,14 +7,17 @@
 use crate::{Error, Result};
 use cfg_if::cfg_if;
 use std::fmt;
+use std::hash::{Hash, Hasher};
 use std::mem;
-#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+use std::ops::BitOr;
+#[cfg(freebsdlike)]
 use std::os::unix::io::RawFd;
 use std::ptr;
 use std::str::FromStr;
 
 #[cfg(not(any(
     target_os = "fuchsia",
+    target_os = "hurd",
     target_os = "openbsd",
     target_os = "redox"
 )))]
@@ -63,9 +66,12 @@
         /// Software termination signal from kill
         SIGTERM,
         /// Stack fault (obsolete)
-        #[cfg(all(any(target_os = "android", target_os = "emscripten",
-                      target_os = "fuchsia", target_os = "linux"),
-                  not(any(target_arch = "mips", target_arch = "mips64",
+        #[cfg(all(any(linux_android, target_os = "emscripten",
+                      target_os = "fuchsia"),
+                  not(any(target_arch = "mips",
+                          target_arch = "mips32r6",
+                          target_arch = "mips64",
+                          target_arch = "mips64r6",
                           target_arch = "sparc64"))))]
         SIGSTKFLT,
         /// To parent on child stop or exit
@@ -94,27 +100,21 @@
         SIGWINCH,
         /// Input/output possible signal
         #[cfg(not(target_os = "haiku"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         SIGIO,
-        #[cfg(any(target_os = "android", target_os = "emscripten",
-                  target_os = "fuchsia", target_os = "linux",
-                  target_os = "aix"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, target_os = "emscripten",
+                  target_os = "fuchsia", target_os = "aix"))]
         /// Power failure imminent.
         SIGPWR,
         /// Bad system call
         SIGSYS,
-        #[cfg(not(any(target_os = "android", target_os = "emscripten",
-                      target_os = "fuchsia", target_os = "linux",
+        #[cfg(not(any(linux_android, target_os = "emscripten",
+                      target_os = "fuchsia",
                       target_os = "redox", target_os = "haiku")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         /// Emulator trap
         SIGEMT,
-        #[cfg(not(any(target_os = "android", target_os = "emscripten",
-                      target_os = "fuchsia", target_os = "linux",
-                      target_os = "redox", target_os = "haiku",
-                      target_os = "aix")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(not(any(linux_android, target_os = "emscripten",
+                      target_os = "fuchsia", target_os = "redox",
+                      target_os = "haiku", target_os = "aix")))]
         /// Information request
         SIGINFO,
     }
@@ -143,14 +143,15 @@
             "SIGTERM" => Signal::SIGTERM,
             #[cfg(all(
                 any(
-                    target_os = "android",
+                    linux_android,
                     target_os = "emscripten",
                     target_os = "fuchsia",
-                    target_os = "linux"
                 ),
                 not(any(
                     target_arch = "mips",
+                    target_arch = "mips32r6",
                     target_arch = "mips64",
+                    target_arch = "mips64r6",
                     target_arch = "sparc64"
                 ))
             ))]
@@ -170,27 +171,24 @@
             #[cfg(not(target_os = "haiku"))]
             "SIGIO" => Signal::SIGIO,
             #[cfg(any(
-                target_os = "android",
+                linux_android,
                 target_os = "emscripten",
                 target_os = "fuchsia",
-                target_os = "linux"
             ))]
             "SIGPWR" => Signal::SIGPWR,
             "SIGSYS" => Signal::SIGSYS,
             #[cfg(not(any(
-                target_os = "android",
+                linux_android,
                 target_os = "emscripten",
                 target_os = "fuchsia",
-                target_os = "linux",
                 target_os = "redox",
                 target_os = "haiku"
             )))]
             "SIGEMT" => Signal::SIGEMT,
             #[cfg(not(any(
-                target_os = "android",
+                linux_android,
                 target_os = "emscripten",
                 target_os = "fuchsia",
-                target_os = "linux",
                 target_os = "redox",
                 target_os = "aix",
                 target_os = "haiku"
@@ -227,14 +225,15 @@
             Signal::SIGTERM => "SIGTERM",
             #[cfg(all(
                 any(
-                    target_os = "android",
+                    linux_android,
                     target_os = "emscripten",
                     target_os = "fuchsia",
-                    target_os = "linux"
                 ),
                 not(any(
                     target_arch = "mips",
+                    target_arch = "mips32r6",
                     target_arch = "mips64",
+                    target_arch = "mips64r6",
                     target_arch = "sparc64"
                 ))
             ))]
@@ -254,28 +253,25 @@
             #[cfg(not(target_os = "haiku"))]
             Signal::SIGIO => "SIGIO",
             #[cfg(any(
-                target_os = "android",
+                linux_android,
                 target_os = "emscripten",
                 target_os = "fuchsia",
                 target_os = "aix",
-                target_os = "linux"
             ))]
             Signal::SIGPWR => "SIGPWR",
             Signal::SIGSYS => "SIGSYS",
             #[cfg(not(any(
-                target_os = "android",
+                linux_android,
                 target_os = "emscripten",
                 target_os = "fuchsia",
-                target_os = "linux",
                 target_os = "redox",
                 target_os = "haiku"
             )))]
             Signal::SIGEMT => "SIGEMT",
             #[cfg(not(any(
-                target_os = "android",
+                linux_android,
                 target_os = "emscripten",
                 target_os = "fuchsia",
-                target_os = "linux",
                 target_os = "redox",
                 target_os = "aix",
                 target_os = "haiku"
@@ -319,15 +315,12 @@
     SIGPROF, SIGWINCH, SIGSYS,
 ];
 #[cfg(all(
-    any(
-        target_os = "linux",
-        target_os = "android",
-        target_os = "emscripten",
-        target_os = "fuchsia"
-    ),
+    any(linux_android, target_os = "emscripten", target_os = "fuchsia"),
     not(any(
         target_arch = "mips",
+        target_arch = "mips32r6",
         target_arch = "mips64",
+        target_arch = "mips64r6",
         target_arch = "sparc64"
     ))
 ))]
@@ -339,13 +332,14 @@
     SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
 ];
 #[cfg(all(
+    any(linux_android, target_os = "emscripten", target_os = "fuchsia"),
     any(
-        target_os = "linux",
-        target_os = "android",
-        target_os = "emscripten",
-        target_os = "fuchsia"
-    ),
-    any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")
+        target_arch = "mips",
+        target_arch = "mips32r6",
+        target_arch = "mips64",
+        target_arch = "mips64r6",
+        target_arch = "sparc64"
+    )
 ))]
 #[cfg(feature = "signal")]
 const SIGNALS: [Signal; 30] = [
@@ -363,8 +357,7 @@
     SIGVTALRM, SIGPROF, SIGXCPU, SIGXFSZ, SIGTRAP,
 ];
 #[cfg(not(any(
-    target_os = "linux",
-    target_os = "android",
+    linux_android,
     target_os = "fuchsia",
     target_os = "emscripten",
     target_os = "aix",
@@ -439,6 +432,7 @@
         SA_NOCLDSTOP;
         /// When catching a [`Signal::SIGCHLD`] signal, the system will not
         /// create zombie processes when children of the calling process exit.
+        #[cfg(not(target_os = "hurd"))]
         SA_NOCLDWAIT;
         /// Further occurrences of the delivered signal are not masked during
         /// the execution of the handler.
@@ -486,7 +480,7 @@
 // We are using `transparent` here to be super sure that `SigSet`
 // is represented exactly like the `sigset_t` struct from C.
 #[repr(transparent)]
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq)]
 pub struct SigSet {
     sigset: libc::sigset_t
 }
@@ -577,7 +571,6 @@
     /// Suspends execution of the calling thread until one of the signals in the
     /// signal mask becomes pending, and returns the accepted signal.
     #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn wait(&self) -> Result<Signal> {
         use std::convert::TryFrom;
 
@@ -589,6 +582,35 @@
         })
     }
 
+    /// Wait for a signal
+    ///
+    /// # Return value
+    /// If `sigsuspend(2)` is interrupted (EINTR), this function returns `Ok`.
+    /// If `sigsuspend(2)` set other error, this function returns `Err`.
+    ///
+    /// For more information see the
+    /// [`sigsuspend(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html).
+    #[cfg(any(
+        bsd,
+        linux_android,
+        solarish,
+        target_os = "haiku",
+        target_os = "hurd",
+        target_os = "aix",
+        target_os = "fushsia"
+    ))]
+    #[doc(alias("sigsuspend"))]
+    pub fn suspend(&self) -> Result<()> {
+        let res = unsafe {
+            libc::sigsuspend(&self.sigset as *const libc::sigset_t)
+        };
+        match Errno::result(res).map(drop) {
+            Err(Errno::EINTR) => Ok(()),
+            Err(e) => Err(e),
+            Ok(_) => unreachable!("because this syscall always returns -1 if returns"),
+        }
+    }
+
     /// Converts a `libc::sigset_t` object to a [`SigSet`] without checking  whether the
     /// `libc::sigset_t` is already initialized.
     ///
@@ -603,6 +625,42 @@
     }
 }
 
+impl From<Signal> for SigSet {
+    fn from(signal: Signal) -> SigSet {
+        let mut sigset = SigSet::empty();
+        sigset.add(signal);
+        sigset
+    }
+}
+
+impl BitOr for Signal {
+    type Output = SigSet;
+
+    fn bitor(self, rhs: Self) -> Self::Output {
+        let mut sigset = SigSet::empty();
+        sigset.add(self);
+        sigset.add(rhs);
+        sigset
+    }
+}
+
+impl BitOr<Signal> for SigSet {
+    type Output = SigSet;
+
+    fn bitor(mut self, rhs: Signal) -> Self::Output {
+        self.add(rhs);
+        self
+    }
+}
+
+impl BitOr for SigSet {
+    type Output = Self;
+
+    fn bitor(self, rhs: Self) -> Self::Output {
+        self.iter().chain(rhs.iter()).collect()
+    }
+}
+
 impl AsRef<libc::sigset_t> for SigSet {
     fn as_ref(&self) -> &libc::sigset_t {
         &self.sigset
@@ -628,6 +686,27 @@
     }
 }
 
+impl PartialEq for SigSet {
+    fn eq(&self, other: &Self) -> bool {
+        for signal in Signal::iterator() {
+            if self.contains(signal) != other.contains(signal) {
+                return false;
+            }
+        }
+        true
+    }
+}
+
+impl Hash for SigSet {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        for signal in Signal::iterator() {
+            if self.contains(signal) {
+                signal.hash(state);
+            }
+        }
+    }
+}
+
 /// Iterator for a [`SigSet`].
 ///
 /// Call [`SigSet::iter`] to create an iterator.
@@ -670,7 +749,6 @@
     /// Use the given signal-catching function, which takes in the signal, information about how
     /// the signal was generated, and a pointer to the threads `ucontext_t`.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
 }
 
@@ -689,23 +767,27 @@
     pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
         #[cfg(not(target_os = "aix"))]
         unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
-            (*p).sa_sigaction = match handler {
-                SigHandler::SigDfl => libc::SIG_DFL,
-                SigHandler::SigIgn => libc::SIG_IGN,
-                SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
-                #[cfg(not(target_os = "redox"))]
-                SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
-            };
+            unsafe {
+                 (*p).sa_sigaction = match handler {
+                    SigHandler::SigDfl => libc::SIG_DFL,
+                    SigHandler::SigIgn => libc::SIG_IGN,
+                    SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
+                    #[cfg(not(target_os = "redox"))]
+                    SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
+                };
+            }
         }
 
         #[cfg(target_os = "aix")]
         unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
-            (*p).sa_union.__su_sigaction = match handler {
-                SigHandler::SigDfl => mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_DFL),
-                SigHandler::SigIgn => mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_IGN),
-                SigHandler::Handler(f) => mem::transmute::<extern "C" fn(i32), extern "C" fn(i32, *mut libc::siginfo_t, *mut libc::c_void)>(f),
-                SigHandler::SigAction(f) => f,
-            };
+            unsafe {
+                (*p).sa_union.__su_sigaction = match handler {
+                    SigHandler::SigDfl => unsafe { mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_DFL) },
+                    SigHandler::SigIgn => unsafe { mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_IGN) },
+                    SigHandler::Handler(f) => unsafe { mem::transmute::<extern "C" fn(i32), extern "C" fn(i32, *mut libc::siginfo_t, *mut libc::c_void)>(f) },
+                    SigHandler::SigAction(f) => f,
+                };
+            }
         }
 
         let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
@@ -810,11 +892,11 @@
 pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
     let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
 
-    let res = libc::sigaction(signal as libc::c_int,
+    let res = unsafe { libc::sigaction(signal as libc::c_int,
                               &sigaction.sigaction as *const libc::sigaction,
-                              oldact.as_mut_ptr());
+                              oldact.as_mut_ptr()) };
 
-    Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() })
+    Errno::result(res).map(|_| SigAction { sigaction: unsafe { oldact.assume_init() } })
 }
 
 /// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
@@ -872,9 +954,9 @@
 pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
     let signal = signal as libc::c_int;
     let res = match handler {
-        SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
-        SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
-        SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
+        SigHandler::SigDfl => unsafe { libc::signal(signal, libc::SIG_DFL) },
+        SigHandler::SigIgn => unsafe { libc::signal(signal, libc::SIG_IGN) },
+        SigHandler::Handler(handler) => unsafe { libc::signal(signal, handler as libc::sighandler_t) },
         #[cfg(not(target_os = "redox"))]
         SigHandler::SigAction(_) => return Err(Errno::ENOTSUP),
     };
@@ -883,9 +965,7 @@
             libc::SIG_DFL => SigHandler::SigDfl,
             libc::SIG_IGN => SigHandler::SigIgn,
             p => SigHandler::Handler(
-                *(&p as *const usize
-                     as *const extern fn(libc::c_int))
-                as extern fn(libc::c_int)),
+                unsafe { *(&p as *const usize as *const extern fn(libc::c_int)) } as extern fn(libc::c_int)),
         }
     })
 }
@@ -1019,14 +1099,14 @@
 #[cfg(target_os = "freebsd")]
 pub type type_of_thread_id = libc::lwpid_t;
 /// Identifies a thread for [`SigevNotify::SigevThreadId`]
-#[cfg(any(target_env = "gnu", target_env = "uclibc"))]
+#[cfg(all(not(target_os = "hurd"), any(target_env = "gnu", target_env = "uclibc")))]
 pub type type_of_thread_id = libc::pid_t;
 
 /// Specifies the notification method used by a [`SigEvent`]
 // sigval is actually a union of a int and a void*.  But it's never really used
 // as a pointer, because neither libc nor the kernel ever dereference it.  nix
 // therefore presents it as an intptr_t, which is how kevent uses it.
-#[cfg(not(any(target_os = "fuchsia", target_os = "openbsd", target_os = "redox")))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "hurd", target_os = "openbsd", target_os = "redox")))]
 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
 pub enum SigevNotify {
     /// No notification will be delivered
@@ -1041,8 +1121,7 @@
     },
     // Note: SIGEV_THREAD is not implemented, but could be if desired.
     /// Notify by delivering an event to a kqueue.
-    #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(freebsdlike)]
     SigevKevent {
         /// File descriptor of the kqueue to notify.
         kq: RawFd,
@@ -1051,7 +1130,6 @@
     },
     /// Notify by delivering an event to a kqueue, with optional event flags set
     #[cfg(target_os = "freebsd")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     #[cfg(feature = "event")]
     SigevKeventFlags {
         /// File descriptor of the kqueue to notify.
@@ -1067,7 +1145,6 @@
             target_env = "gnu",
             target_env = "uclibc",
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     SigevThreadId {
         /// Signal to send
         signal: Signal,
@@ -1082,10 +1159,10 @@
 
 #[cfg(not(any(
     target_os = "fuchsia",
+    target_os = "hurd",
     target_os = "openbsd",
     target_os = "redox"
 )))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 mod sigevent {
     feature! {
     #![any(feature = "aio", feature = "signal")]
@@ -1251,7 +1328,7 @@
                     sev.sigev_signo = signal as libc::c_int;
                     sev.sigev_value.sival_ptr = si_value as *mut libc::c_void
                 },
-                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+                #[cfg(freebsdlike)]
                 SigevNotify::SigevKevent{kq, udata} => {
                     sev.sigev_notify = libc::SIGEV_KEVENT;
                     sev.sigev_signo = kq;
@@ -1331,227 +1408,3 @@
     }
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    #[cfg(not(target_os = "redox"))]
-    use std::thread;
-
-    #[test]
-    fn test_contains() {
-        let mut mask = SigSet::empty();
-        mask.add(SIGUSR1);
-
-        assert!(mask.contains(SIGUSR1));
-        assert!(!mask.contains(SIGUSR2));
-
-        let all = SigSet::all();
-        assert!(all.contains(SIGUSR1));
-        assert!(all.contains(SIGUSR2));
-    }
-
-    #[test]
-    fn test_clear() {
-        let mut set = SigSet::all();
-        set.clear();
-        for signal in Signal::iterator() {
-            assert!(!set.contains(signal));
-        }
-    }
-
-    #[test]
-    fn test_from_str_round_trips() {
-        for signal in Signal::iterator() {
-            assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
-            assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
-        }
-    }
-
-    #[test]
-    fn test_from_str_invalid_value() {
-        let errval = Err(Errno::EINVAL);
-        assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
-        assert_eq!("kill".parse::<Signal>(), errval);
-        assert_eq!("9".parse::<Signal>(), errval);
-    }
-
-    #[test]
-    fn test_extend() {
-        let mut one_signal = SigSet::empty();
-        one_signal.add(SIGUSR1);
-
-        let mut two_signals = SigSet::empty();
-        two_signals.add(SIGUSR2);
-        two_signals.extend(&one_signal);
-
-        assert!(two_signals.contains(SIGUSR1));
-        assert!(two_signals.contains(SIGUSR2));
-    }
-
-    #[test]
-    #[cfg(not(target_os = "redox"))]
-    fn test_thread_signal_set_mask() {
-        thread::spawn(|| {
-            let prev_mask = SigSet::thread_get_mask()
-                .expect("Failed to get existing signal mask!");
-
-            let mut test_mask = prev_mask;
-            test_mask.add(SIGUSR1);
-
-            test_mask.thread_set_mask().expect("assertion failed");
-            let new_mask =
-                SigSet::thread_get_mask().expect("Failed to get new mask!");
-
-            assert!(new_mask.contains(SIGUSR1));
-            assert!(!new_mask.contains(SIGUSR2));
-
-            prev_mask
-                .thread_set_mask()
-                .expect("Failed to revert signal mask!");
-        })
-        .join()
-        .unwrap();
-    }
-
-    #[test]
-    #[cfg(not(target_os = "redox"))]
-    fn test_thread_signal_block() {
-        thread::spawn(|| {
-            let mut mask = SigSet::empty();
-            mask.add(SIGUSR1);
-
-            mask.thread_block().expect("assertion failed");
-
-            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
-        })
-        .join()
-        .unwrap();
-    }
-
-    #[test]
-    #[cfg(not(target_os = "redox"))]
-    fn test_thread_signal_unblock() {
-        thread::spawn(|| {
-            let mut mask = SigSet::empty();
-            mask.add(SIGUSR1);
-
-            mask.thread_unblock().expect("assertion failed");
-
-            assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
-        })
-        .join()
-        .unwrap();
-    }
-
-    #[test]
-    #[cfg(not(target_os = "redox"))]
-    fn test_thread_signal_swap() {
-        thread::spawn(|| {
-            let mut mask = SigSet::empty();
-            mask.add(SIGUSR1);
-            mask.thread_block().unwrap();
-
-            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
-
-            let mut mask2 = SigSet::empty();
-            mask2.add(SIGUSR2);
-
-            let oldmask =
-                mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap();
-
-            assert!(oldmask.contains(SIGUSR1));
-            assert!(!oldmask.contains(SIGUSR2));
-
-            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
-        })
-        .join()
-        .unwrap();
-    }
-
-    #[test]
-    fn test_from_and_into_iterator() {
-        let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]);
-        let signals = sigset.into_iter().collect::<Vec<Signal>>();
-        assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]);
-    }
-
-    #[test]
-    #[cfg(not(target_os = "redox"))]
-    fn test_sigaction() {
-        thread::spawn(|| {
-            extern "C" fn test_sigaction_handler(_: libc::c_int) {}
-            extern "C" fn test_sigaction_action(
-                _: libc::c_int,
-                _: *mut libc::siginfo_t,
-                _: *mut libc::c_void,
-            ) {
-            }
-
-            let handler_sig = SigHandler::Handler(test_sigaction_handler);
-
-            let flags =
-                SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO;
-
-            let mut mask = SigSet::empty();
-            mask.add(SIGUSR1);
-
-            let action_sig = SigAction::new(handler_sig, flags, mask);
-
-            assert_eq!(
-                action_sig.flags(),
-                SaFlags::SA_ONSTACK | SaFlags::SA_RESTART
-            );
-            assert_eq!(action_sig.handler(), handler_sig);
-
-            mask = action_sig.mask();
-            assert!(mask.contains(SIGUSR1));
-            assert!(!mask.contains(SIGUSR2));
-
-            let handler_act = SigHandler::SigAction(test_sigaction_action);
-            let action_act = SigAction::new(handler_act, flags, mask);
-            assert_eq!(action_act.handler(), handler_act);
-
-            let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
-            assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
-
-            let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
-            assert_eq!(action_ign.handler(), SigHandler::SigIgn);
-        })
-        .join()
-        .unwrap();
-    }
-
-    #[test]
-    #[cfg(not(target_os = "redox"))]
-    fn test_sigwait() {
-        thread::spawn(|| {
-            let mut mask = SigSet::empty();
-            mask.add(SIGUSR1);
-            mask.add(SIGUSR2);
-            mask.thread_block().unwrap();
-
-            raise(SIGUSR1).unwrap();
-            assert_eq!(mask.wait().unwrap(), SIGUSR1);
-        })
-        .join()
-        .unwrap();
-    }
-
-    #[test]
-    fn test_from_sigset_t_unchecked() {
-        let src_set = SigSet::empty();
-        let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
-
-        for signal in Signal::iterator() {
-            assert!(!set.contains(signal));
-        }
-
-        let src_set = SigSet::all();
-        let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
-
-        for signal in Signal::iterator() {
-            assert!(set.contains(signal));
-        }
-    }
-}
diff --git a/src/sys/signalfd.rs b/src/sys/signalfd.rs
index 2b80ea6..ccba774 100644
--- a/src/sys/signalfd.rs
+++ b/src/sys/signalfd.rs
@@ -21,7 +21,7 @@
 pub use libc::signalfd_siginfo as siginfo;
 
 use std::mem;
-use std::os::unix::io::{AsRawFd, RawFd, FromRawFd, OwnedFd, AsFd, BorrowedFd};
+use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
 
 libc_bitflags! {
     pub struct SfdFlags: libc::c_int {
@@ -45,18 +45,23 @@
 ///
 /// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html)
 #[deprecated(since = "0.27.0", note = "Use SignalFd instead")]
-pub fn signalfd<F: AsFd>(fd: Option<F>, mask: &SigSet, flags: SfdFlags) -> Result<OwnedFd> {
+pub fn signalfd<F: AsFd>(
+    fd: Option<F>,
+    mask: &SigSet,
+    flags: SfdFlags,
+) -> Result<OwnedFd> {
     _signalfd(fd, mask, flags)
 }
 
-fn _signalfd<F: AsFd>(fd: Option<F>, mask: &SigSet, flags: SfdFlags) -> Result<OwnedFd> {
-    let raw_fd = fd.map_or(-1, |x|x.as_fd().as_raw_fd());
+fn _signalfd<F: AsFd>(
+    fd: Option<F>,
+    mask: &SigSet,
+    flags: SfdFlags,
+) -> Result<OwnedFd> {
+    let raw_fd = fd.map_or(-1, |x| x.as_fd().as_raw_fd());
     unsafe {
-        Errno::result(libc::signalfd(
-            raw_fd,
-            mask.as_ref(),
-            flags.bits(),
-        )).map(|raw_fd|FromRawFd::from_raw_fd(raw_fd))
+        Errno::result(libc::signalfd(raw_fd, mask.as_ref(), flags.bits()))
+            .map(|raw_fd| FromRawFd::from_raw_fd(raw_fd))
     }
 }
 
@@ -101,7 +106,7 @@
     }
 
     pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> {
-        _signalfd(Some(self.0.as_fd()), mask, SfdFlags::empty()).map(drop)
+        self.update(mask, SfdFlags::empty())
     }
 
     pub fn read_signal(&mut self) -> Result<Option<siginfo>> {
@@ -109,7 +114,7 @@
 
         let size = mem::size_of_val(&buffer);
         let res = Errno::result(unsafe {
-            libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr() as *mut libc::c_void, size)
+            libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr().cast(), size)
         })
         .map(|r| r as usize);
         match res {
@@ -119,6 +124,14 @@
             Err(error) => Err(error),
         }
     }
+
+    fn update(&self, mask: &SigSet, flags: SfdFlags) -> Result<()> {
+        let raw_fd = self.0.as_raw_fd();
+        unsafe {
+            Errno::result(libc::signalfd(raw_fd, mask.as_ref(), flags.bits()))
+                .map(drop)
+        }
+    }
 }
 
 impl AsFd for SignalFd {
@@ -142,34 +155,3 @@
         }
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn create_signalfd() {
-        let mask = SigSet::empty();
-        SignalFd::new(&mask).unwrap();
-    }
-
-    #[test]
-    fn create_signalfd_with_opts() {
-        let mask = SigSet::empty();
-        SignalFd::with_flags(
-            &mask,
-            SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK,
-        )
-        .unwrap();
-    }
-
-    #[test]
-    fn read_empty_signalfd() {
-        let mask = SigSet::empty();
-        let mut fd =
-            SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
-
-        let res = fd.read_signal();
-        assert!(res.unwrap().is_none());
-    }
-}
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index 1783531..f6800aa 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -1,31 +1,22 @@
 #[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",
+    bsd,
+    linux_android,
+    solarish,
     target_os = "haiku",
     target_os = "fuchsia",
     target_os = "aix",
 ))]
 #[cfg(feature = "net")]
 pub use self::datalink::LinkAddr;
-#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
+#[cfg(any(linux_android, apple_targets))]
 pub use self::vsock::VsockAddr;
 use super::sa_family_t;
 use crate::errno::Errno;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 use crate::sys::socket::addr::alg::AlgAddr;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 use crate::sys::socket::addr::netlink::NetlinkAddr;
-#[cfg(all(
-    feature = "ioctl",
-    any(target_os = "ios", target_os = "macos")
-))]
+#[cfg(all(feature = "ioctl", apple_targets))]
 use crate::sys::socket::addr::sys_control::SysControlAddr;
 use crate::{NixPath, Result};
 use cfg_if::cfg_if;
@@ -33,6 +24,7 @@
 use std::convert::TryInto;
 use std::ffi::OsStr;
 use std::hash::{Hash, Hasher};
+use std::net::{Ipv4Addr, Ipv6Addr};
 use std::os::unix::ffi::OsStrExt;
 use std::path::Path;
 use std::{fmt, mem, net, ptr, slice};
@@ -41,7 +33,7 @@
 #[cfg(feature = "net")]
 pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr {
     libc::in_addr {
-        s_addr: u32::from_ne_bytes(addr.octets())
+        s_addr: u32::from_ne_bytes(addr.octets()),
     }
 }
 
@@ -49,7 +41,7 @@
 #[cfg(feature = "net")]
 pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr {
     libc::in6_addr {
-        s6_addr: addr.octets()
+        s6_addr: addr.octets(),
     }
 }
 
@@ -71,346 +63,188 @@
     /// IPv6 Internet protocols (see [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html))
     Inet6 = libc::AF_INET6,
     /// Kernel user interface device (see [`netlink(7)`](https://man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Netlink = libc::AF_NETLINK,
     /// Kernel interface for interacting with the routing table
-    #[cfg(not(any(
-        target_os = "redox",
-        target_os = "linux",
-        target_os = "android"
-    )))]
+    #[cfg(not(any(linux_android, target_os = "redox")))]
     Route = libc::PF_ROUTE,
     /// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html))
-    #[cfg(any(
-        target_os = "android",
-        target_os = "linux",
-        target_os = "illumos",
-        target_os = "fuchsia",
-        target_os = "solaris"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(linux_android, solarish, target_os = "fuchsia"))]
     Packet = libc::AF_PACKET,
     /// KEXT Controls and Notifications
-    #[cfg(any(target_os = "ios", target_os = "macos"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(apple_targets)]
     System = libc::AF_SYSTEM,
     /// Amateur radio AX.25 protocol
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Ax25 = libc::AF_AX25,
     /// IPX - Novell protocols
     #[cfg(not(any(target_os = "aix", target_os = "redox")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     Ipx = libc::AF_IPX,
     /// AppleTalk
     #[cfg(not(target_os = "redox"))]
     AppleTalk = libc::AF_APPLETALK,
     /// AX.25 packet layer protocol.
     /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetRom = libc::AF_NETROM,
     /// Can't be used for creating sockets; mostly used for bridge
     /// links in
     /// [rtnetlink(7)](https://man7.org/linux/man-pages/man7/rtnetlink.7.html)
     /// protocol commands.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Bridge = libc::AF_BRIDGE,
     /// Access to raw ATM PVCs
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     AtmPvc = libc::AF_ATMPVC,
     /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](https://man7.org/linux/man-pages/man7/x25.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     X25 = libc::AF_X25,
     /// RATS (Radio Amateur Telecommunications Society) Open
     /// Systems environment (ROSE) AX.25 packet layer protocol.
     /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Rose = libc::AF_ROSE,
     /// DECet protocol sockets.
     #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
     Decnet = libc::AF_DECnet,
     /// Reserved for "802.2LLC project"; never used.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetBeui = libc::AF_NETBEUI,
     /// This was a short-lived (between Linux 2.1.30 and
     /// 2.1.99pre2) protocol family for firewall upcalls.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Security = libc::AF_SECURITY,
     /// Key management protocol.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Key = libc::AF_KEY,
     #[allow(missing_docs)] // Not documented anywhere that I can find
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Ash = libc::AF_ASH,
     /// Acorn Econet protocol
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Econet = libc::AF_ECONET,
     /// Access to ATM Switched Virtual Circuits
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     AtmSvc = libc::AF_ATMSVC,
     /// Reliable Datagram Sockets (RDS) protocol
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Rds = libc::AF_RDS,
     /// IBM SNA
     #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
     Sna = libc::AF_SNA,
     /// Socket interface over IrDA
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Irda = libc::AF_IRDA,
     /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE)
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Pppox = libc::AF_PPPOX,
     /// Legacy protocol for wide area network (WAN) connectivity that was used
     /// by Sangoma WAN cards
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Wanpipe = libc::AF_WANPIPE,
     /// Logical link control (IEEE 802.2 LLC) protocol
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Llc = libc::AF_LLC,
     /// InfiniBand native addressing
     #[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     Ib = libc::AF_IB,
     /// Multiprotocol Label Switching
     #[cfg(all(target_os = "linux", not(target_env = "uclibc")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     Mpls = libc::AF_MPLS,
     /// Controller Area Network automotive bus protocol
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Can = libc::AF_CAN,
     /// TIPC, "cluster domain sockets" protocol
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Tipc = libc::AF_TIPC,
     /// Bluetooth low-level socket protocol
     #[cfg(not(any(
         target_os = "aix",
-        target_os = "illumos",
-        target_os = "ios",
-        target_os = "macos",
-        target_os = "solaris",
+        solarish,
+        apple_targets,
+        target_os = "hurd",
         target_os = "redox",
     )))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     Bluetooth = libc::AF_BLUETOOTH,
     /// IUCV (inter-user communication vehicle) z/VM protocol for
     /// hypervisor-guest interaction
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Iucv = libc::AF_IUCV,
     /// Rx, Andrew File System remote procedure call protocol
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     RxRpc = libc::AF_RXRPC,
     /// New "modular ISDN" driver interface protocol
     #[cfg(not(any(
         target_os = "aix",
-        target_os = "illumos",
-        target_os = "solaris",
+        solarish,
         target_os = "haiku",
+        target_os = "hurd",
         target_os = "redox",
     )))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     Isdn = libc::AF_ISDN,
     /// Nokia cellular modem IPC/RPC interface
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Phonet = libc::AF_PHONET,
     /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Ieee802154 = libc::AF_IEEE802154,
     /// Ericsson's Communication CPU to Application CPU interface (CAIF)
     /// protocol.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Caif = libc::AF_CAIF,
     /// Interface to kernel crypto API
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Alg = libc::AF_ALG,
     /// Near field communication
     #[cfg(target_os = "linux")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     Nfc = libc::AF_NFC,
     /// VMWare VSockets protocol for hypervisor-guest interaction.
-    #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(linux_android, apple_targets))]
     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_attr(docsrs, doc(cfg(all())))]
+    #[cfg(bsd)]
     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_attr(docsrs, doc(cfg(all())))]
+    #[cfg(bsd)]
     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_attr(docsrs, doc(cfg(all())))]
+    #[cfg(bsd)]
     Chaos = libc::AF_CHAOS,
     /// Novell and Xerox protocol
-    #[cfg(any(
-        target_os = "ios",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(apple_targets, netbsdlike))]
     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"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(bsd)]
     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_attr(docsrs, doc(cfg(all())))]
+    #[cfg(bsd)]
     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_attr(docsrs, doc(cfg(all())))]
+    #[cfg(bsd)]
     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_attr(docsrs, doc(cfg(all())))]
+    #[cfg(bsd)]
     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"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(bsd)]
     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_attr(docsrs, doc(cfg(all())))]
+    #[cfg(bsd)]
     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_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, solarish))]
     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_attr(docsrs, doc(cfg(all())))]
+    #[cfg(bsd)]
     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_attr(docsrs, doc(cfg(all())))]
+    #[cfg(bsd)]
     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_attr(docsrs, doc(cfg(all())))]
+    #[cfg(bsd)]
     Natm = libc::AF_NATM,
     /// Unspecified address family, (see [`getaddrinfo(3)`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     Unspec = libc::AF_UNSPEC,
 }
 
@@ -425,29 +259,17 @@
             libc::AF_UNIX => Some(AddressFamily::Unix),
             libc::AF_INET => Some(AddressFamily::Inet),
             libc::AF_INET6 => Some(AddressFamily::Inet6),
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             libc::AF_NETLINK => Some(AddressFamily::Netlink),
-            #[cfg(any(target_os = "macos", target_os = "macos"))]
+            #[cfg(apple_targets)]
             libc::AF_SYSTEM => Some(AddressFamily::System),
-            #[cfg(not(any(
-                target_os = "redox",
-                target_os = "linux",
-                target_os = "android"
-            )))]
+            #[cfg(not(any(linux_android, target_os = "redox")))]
             libc::PF_ROUTE => Some(AddressFamily::Route),
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             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(bsd, solarish))]
             libc::AF_LINK => Some(AddressFamily::Link),
-            #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
+            #[cfg(any(linux_android, apple_targets))]
             libc::AF_VSOCK => Some(AddressFamily::Vsock),
             _ => None,
         }
@@ -463,13 +285,7 @@
     /// 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",
-        target_os = "redox",
-    ))]
+    #[cfg(not(any(bsd, target_os = "haiku", target_os = "hurd")))]
     sun_len: u8,
 }
 
@@ -483,12 +299,12 @@
 enum UnixAddrKind<'a> {
     Pathname(&'a Path),
     Unnamed,
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     Abstract(&'a [u8]),
 }
 impl<'a> UnixAddrKind<'a> {
     /// Safety: sun & sun_len must be valid
-    #[allow(clippy::unnecessary_cast)]   // Not unnecessary on all platforms
+    #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms
     unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self {
         assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path));
         let path_len =
@@ -496,16 +312,19 @@
         if path_len == 0 {
             return Self::Unnamed;
         }
-        #[cfg(any(target_os = "android", target_os = "linux"))]
+        #[cfg(linux_android)]
         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 = unsafe {
+                slice::from_raw_parts(
+                    sun.sun_path.as_ptr().add(1).cast(),
+                    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 = unsafe {
+            slice::from_raw_parts(sun.sun_path.as_ptr().cast(), 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
@@ -525,7 +344,7 @@
 
 impl UnixAddr {
     /// Create a new sockaddr_un representing a filesystem path.
-    #[allow(clippy::unnecessary_cast)]   // Not unnecessary on all platforms
+    #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms
     pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> {
         path.with_nix_path(|cstr| unsafe {
             let mut ret = libc::sockaddr_un {
@@ -544,20 +363,13 @@
             .try_into()
             .unwrap();
 
-            #[cfg(any(
-                target_os = "dragonfly",
-                target_os = "freebsd",
-                target_os = "ios",
-                target_os = "macos",
-                target_os = "netbsd",
-                target_os = "openbsd"
-            ))]
+            #[cfg(any(bsd, target_os = "haiku", target_os = "hurd"))]
             {
                 ret.sun_len = sun_len;
             }
             ptr::copy_nonoverlapping(
                 bytes.as_ptr(),
-                ret.sun_path.as_mut_ptr() as *mut u8,
+                ret.sun_path.as_mut_ptr().cast(),
                 bytes.len(),
             );
 
@@ -571,9 +383,8 @@
     /// thus the input `path` is expected to be the bare name, not NUL-prefixed.
     /// This is a Linux-specific extension, primarily used to allow chrooted
     /// processes to communicate with processes having a different filesystem view.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
-    #[allow(clippy::unnecessary_cast)]   // Not unnecessary on all platforms
+    #[cfg(linux_android)]
+    #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms
     pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> {
         unsafe {
             let mut ret = libc::sockaddr_un {
@@ -593,7 +404,7 @@
             // 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,
+                ret.sun_path.as_mut_ptr().offset(1).cast(),
                 path.len(),
             );
 
@@ -602,8 +413,7 @@
     }
 
     /// 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())))]
+    #[cfg(linux_android)]
     pub fn new_unnamed() -> UnixAddr {
         let ret = libc::sockaddr_un {
             sun_family: AddressFamily::Unix as sa_family_t,
@@ -632,10 +442,9 @@
         sun_len: u8,
     ) -> UnixAddr {
         cfg_if! {
-            if #[cfg(any(target_os = "android",
+            if #[cfg(any(linux_android,
                      target_os = "fuchsia",
-                     target_os = "illumos",
-                     target_os = "linux",
+                     solarish,
                      target_os = "redox",
                 ))]
             {
@@ -664,8 +473,7 @@
     ///
     /// For abstract sockets only the bare name is returned, without the
     /// leading NUL byte. `None` is returned for unnamed or path-backed sockets.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     pub fn as_abstract(&self) -> Option<&[u8]> {
         match self.kind() {
             UnixAddrKind::Abstract(name) => Some(name),
@@ -674,8 +482,7 @@
     }
 
     /// Check if this address is an "unnamed" unix socket address.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     #[inline]
     pub fn is_unnamed(&self) -> bool {
         matches!(self.kind(), UnixAddrKind::Unnamed)
@@ -699,10 +506,9 @@
 
     fn sun_len(&self) -> u8 {
         cfg_if! {
-            if #[cfg(any(target_os = "android",
+            if #[cfg(any(linux_android,
                      target_os = "fuchsia",
-                     target_os = "illumos",
-                     target_os = "linux",
+                     solarish,
                      target_os = "redox",
                 ))]
             {
@@ -717,10 +523,10 @@
 impl private::SockaddrLikePriv for UnixAddr {}
 impl SockaddrLike for UnixAddr {
     #[cfg(any(
-        target_os = "android",
+        linux_android,
         target_os = "fuchsia",
-        target_os = "illumos",
-        target_os = "linux"
+        solarish,
+        target_os = "redox"
     ))]
     fn len(&self) -> libc::socklen_t {
         self.sun_len.into()
@@ -740,27 +546,26 @@
                 return None;
             }
         }
-        if (*addr).sa_family as i32 != libc::AF_UNIX {
+        if unsafe { (*addr).sa_family as i32 != libc::AF_UNIX } {
             return None;
         }
-        let mut su: libc::sockaddr_un = mem::zeroed();
+        let mut su: libc::sockaddr_un = unsafe { mem::zeroed() };
         let sup = &mut su as *mut libc::sockaddr_un as *mut u8;
         cfg_if! {
-            if #[cfg(any(target_os = "android",
+            if #[cfg(any(linux_android,
                          target_os = "fuchsia",
-                         target_os = "illumos",
-                         target_os = "linux",
+                         solarish,
                          target_os = "redox",
                 ))] {
                 let su_len = len.unwrap_or(
                     mem::size_of::<libc::sockaddr_un>() as libc::socklen_t
                 );
             } else {
-                let su_len = len.unwrap_or((*addr).sa_len as libc::socklen_t);
+                let su_len = unsafe { len.unwrap_or((*addr).sa_len as libc::socklen_t) };
             }
-        };
-        ptr::copy(addr as *const u8, sup, su_len as usize);
-        Some(Self::from_raw_parts(su, su_len as u8))
+        }
+        unsafe { ptr::copy(addr as *const u8, sup, su_len as usize) };
+        Some(unsafe { Self::from_raw_parts(su, su_len as u8) })
     }
 
     fn size() -> libc::socklen_t
@@ -770,14 +575,16 @@
         mem::size_of::<libc::sockaddr_un>() as libc::socklen_t
     }
 
-    unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> {
+    unsafe fn set_length(
+        &mut self,
+        new_length: usize,
+    ) -> std::result::Result<(), SocketAddressLengthNotDynamic> {
         // `new_length` is only used on some platforms, so it must be provided even when not used
         #![allow(unused_variables)]
         cfg_if! {
-            if #[cfg(any(target_os = "android",
+            if #[cfg(any(linux_android,
                          target_os = "fuchsia",
-                         target_os = "illumos",
-                         target_os = "linux",
+                         solarish,
                          target_os = "redox",
                 ))] {
                 self.sun_len = new_length as u8;
@@ -793,7 +600,7 @@
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
     use fmt::Write;
     f.write_str("@\"")?;
@@ -810,7 +617,7 @@
         match self.kind() {
             UnixAddrKind::Pathname(path) => path.display().fmt(f),
             UnixAddrKind::Unnamed => f.pad("<unbound UNIX socket>"),
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             UnixAddrKind::Abstract(name) => fmt_abstract(name, f),
         }
     }
@@ -894,12 +701,7 @@
     }
 
     cfg_if! {
-        if #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "ios",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))] {
+        if #[cfg(bsd)] {
             /// Return the length of valid data in the sockaddr structure.
             ///
             /// For fixed-size sockaddrs, this should be the size of the
@@ -946,7 +748,10 @@
     /// `new_length` must be a valid length for this type of address. Specifically, reads of that
     /// length from `self` must be valid.
     #[doc(hidden)]
-    unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> {
+    unsafe fn set_length(
+        &mut self,
+        _new_length: usize,
+    ) -> std::result::Result<(), SocketAddressLengthNotDynamic> {
         Err(SocketAddressLengthNotDynamic)
     }
 }
@@ -1006,22 +811,20 @@
 impl SockaddrIn {
     /// Returns the IP address associated with this socket address, in native
     /// endian.
-    pub const fn ip(&self) -> libc::in_addr_t {
-        u32::from_be(self.0.sin_addr.s_addr)
+    pub const fn ip(&self) -> net::Ipv4Addr {
+        let bytes = self.0.sin_addr.s_addr.to_ne_bytes();
+        let (a, b, c, d) = (bytes[0], bytes[1], bytes[2], bytes[3]);
+        Ipv4Addr::new(a, b, c, d)
     }
 
     /// 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",
+                bsd,
                 target_os = "aix",
                 target_os = "haiku",
-                target_os = "openbsd"
+                target_os = "hurd"
             ))]
             sin_len: Self::size() as u8,
             sin_family: AddressFamily::Inet as sa_family_t,
@@ -1056,10 +859,10 @@
                 return None;
             }
         }
-        if (*addr).sa_family as i32 != libc::AF_INET {
+        if unsafe { (*addr).sa_family as i32 != libc::AF_INET } {
             return None;
         }
-        Some(Self(ptr::read_unaligned(addr as *const _)))
+        Some(Self(unsafe { ptr::read_unaligned(addr as *const _) }))
     }
 }
 
@@ -1092,14 +895,10 @@
     fn from(addr: net::SocketAddrV4) -> Self {
         Self(libc::sockaddr_in {
             #[cfg(any(
-                target_os = "dragonfly",
-                target_os = "freebsd",
+                bsd,
                 target_os = "haiku",
                 target_os = "hermit",
-                target_os = "ios",
-                target_os = "macos",
-                target_os = "netbsd",
-                target_os = "openbsd"
+                target_os = "hurd"
             ))]
             sin_len: mem::size_of::<libc::sockaddr_in>() as u8,
             sin_family: AddressFamily::Inet as sa_family_t,
@@ -1143,8 +942,19 @@
     }
 
     /// Returns the IP address associated with this socket address.
-    pub fn ip(&self) -> net::Ipv6Addr {
-        net::Ipv6Addr::from(self.0.sin6_addr.s6_addr)
+    pub const fn ip(&self) -> net::Ipv6Addr {
+        let bytes = self.0.sin6_addr.s6_addr;
+        let (a, b, c, d, e, f, g, h) = (
+            ((bytes[0] as u16) << 8) | bytes[1] as u16,
+            ((bytes[2] as u16) << 8) | bytes[3] as u16,
+            ((bytes[4] as u16) << 8) | bytes[5] as u16,
+            ((bytes[6] as u16) << 8) | bytes[7] as u16,
+            ((bytes[8] as u16) << 8) | bytes[9] as u16,
+            ((bytes[10] as u16) << 8) | bytes[11] as u16,
+            ((bytes[12] as u16) << 8) | bytes[13] as u16,
+            ((bytes[14] as u16) << 8) | bytes[15] as u16,
+        );
+        Ipv6Addr::new(a, b, c, d, e, f, g, h)
     }
 
     /// Returns the port number associated with this socket address, in native
@@ -1175,10 +985,10 @@
                 return None;
             }
         }
-        if (*addr).sa_family as i32 != libc::AF_INET6 {
+        if unsafe { (*addr).sa_family as i32 != libc::AF_INET6 } {
             return None;
         }
-        Some(Self(ptr::read_unaligned(addr as *const _)))
+        Some(Self(unsafe { ptr::read_unaligned(addr as *const _) }))
     }
 }
 
@@ -1210,14 +1020,10 @@
         #[allow(clippy::needless_update)] // It isn't needless on Illumos
         Self(libc::sockaddr_in6 {
             #[cfg(any(
-                target_os = "dragonfly",
-                target_os = "freebsd",
+                bsd,
                 target_os = "haiku",
                 target_os = "hermit",
-                target_os = "ios",
-                target_os = "macos",
-                target_os = "netbsd",
-                target_os = "openbsd"
+                target_os = "hurd"
             ))]
             sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8,
             sin6_family: AddressFamily::Inet6 as sa_family_t,
@@ -1273,18 +1079,17 @@
 #[derive(Clone, Copy, Eq)]
 #[repr(C)]
 pub union SockaddrStorage {
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     alg: AlgAddr,
-    #[cfg(all(feature = "net", not(target_os = "redox")))]
+    #[cfg(all(
+        feature = "net",
+        not(any(target_os = "hurd", target_os = "redox"))
+    ))]
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     dl: LinkAddr,
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     nl: NetlinkAddr,
-    #[cfg(all(
-        feature = "ioctl",
-        any(target_os = "ios", target_os = "macos")
-    ))]
+    #[cfg(all(feature = "ioctl", apple_targets))]
     #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
     sctl: SysControlAddr,
     #[cfg(feature = "net")]
@@ -1293,8 +1098,7 @@
     sin6: SockaddrIn6,
     ss: libc::sockaddr_storage,
     su: UnixAddr,
-    #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(linux_android, apple_targets))]
     vsock: VsockAddr,
 }
 impl private::SockaddrLikePriv for SockaddrStorage {}
@@ -1316,21 +1120,22 @@
             {
                 None
             } else {
-                let mut ss: libc::sockaddr_storage = mem::zeroed();
+                let mut ss: libc::sockaddr_storage = unsafe { mem::zeroed() };
                 let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8;
-                ptr::copy(addr as *const u8, ssp, len as usize);
+                unsafe { ptr::copy(addr as *const u8, ssp, len as usize) };
                 #[cfg(any(
-                    target_os = "android",
+                    linux_android,
                     target_os = "fuchsia",
-                    target_os = "illumos",
-                    target_os = "linux"
+                    solarish,
                 ))]
                 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;
+                    unsafe {
+                        (*(&mut ss as *mut libc::sockaddr_storage
+                            as *mut UnixAddr))
+                            .sun_len = len as u8;
+                    }
                 }
                 Some(Self { ss })
             }
@@ -1338,68 +1143,47 @@
             // If length is not available and addr is of a fixed-length type,
             // copy it.  If addr is of a variable length type and len is not
             // available, then there's nothing we can do.
-            match (*addr).sa_family as i32 {
-                #[cfg(any(target_os = "android", target_os = "linux"))]
-                libc::AF_ALG => {
+            match unsafe { (*addr).sa_family as i32 } {
+                #[cfg(linux_android)]
+                libc::AF_ALG => unsafe {
                     AlgAddr::from_raw(addr, l).map(|alg| Self { alg })
-                }
+                },
                 #[cfg(feature = "net")]
-                libc::AF_INET => {
+                libc::AF_INET => unsafe {
                     SockaddrIn::from_raw(addr, l).map(|sin| Self { sin })
-                }
+                },
                 #[cfg(feature = "net")]
-                libc::AF_INET6 => {
+                libc::AF_INET6 => unsafe {
                     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(any(bsd, solarish, target_os = "haiku"))]
                 #[cfg(feature = "net")]
-                libc::AF_LINK => {
+                libc::AF_LINK => unsafe {
                     LinkAddr::from_raw(addr, l).map(|dl| Self { dl })
-                }
-                #[cfg(any(target_os = "android", target_os = "linux"))]
-                libc::AF_NETLINK => {
+                },
+                #[cfg(linux_android)]
+                libc::AF_NETLINK => unsafe {
                     NetlinkAddr::from_raw(addr, l).map(|nl| Self { nl })
-                }
-                #[cfg(any(
-                    target_os = "android",
-                    target_os = "fuchsia",
-                    target_os = "linux"
-                ))]
+                },
+                #[cfg(any(linux_android, target_os = "fuchsia"))]
                 #[cfg(feature = "net")]
-                libc::AF_PACKET => {
+                libc::AF_PACKET => unsafe {
                     LinkAddr::from_raw(addr, l).map(|dl| Self { dl })
-                }
-                #[cfg(all(
-                    feature = "ioctl",
-                    any(target_os = "ios", target_os = "macos")
-                ))]
-                libc::AF_SYSTEM => {
+                },
+                #[cfg(all(feature = "ioctl", apple_targets))]
+                libc::AF_SYSTEM => unsafe {
                     SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl })
-                }
-                #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))]
-                libc::AF_VSOCK => {
+                },
+                #[cfg(any(linux_android, apple_targets))]
+                libc::AF_VSOCK => unsafe {
                     VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock })
-                }
+                },
                 _ => None,
             }
         }
     }
 
-    #[cfg(any(
-        target_os = "android",
-        target_os = "fuchsia",
-        target_os = "illumos",
-        target_os = "linux"
-    ))]
+    #[cfg(any(linux_android, target_os = "fuchsia", solarish))]
     fn len(&self) -> libc::socklen_t {
         match self.as_unix_addr() {
             // The UnixAddr type knows its own length
@@ -1409,11 +1193,12 @@
         }
     }
 
-    unsafe fn set_length(&mut self, new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> {
+    unsafe fn set_length(
+        &mut self,
+        new_length: usize,
+    ) -> std::result::Result<(), SocketAddressLengthNotDynamic> {
         match self.as_unix_addr_mut() {
-            Some(addr) => {
-                addr.set_length(new_length)
-            },
+            Some(addr) => unsafe { addr.set_length(new_length) },
             None => Err(SocketAddressLengthNotDynamic),
         }
     }
@@ -1457,10 +1242,9 @@
     /// Downcast to an immutable `[UnixAddr]` reference.
     pub fn as_unix_addr(&self) -> Option<&UnixAddr> {
         cfg_if! {
-            if #[cfg(any(target_os = "android",
+            if #[cfg(any(linux_android,
                      target_os = "fuchsia",
-                     target_os = "illumos",
-                     target_os = "linux"
+                     solarish,
                 ))]
             {
                 let p = unsafe{ &self.ss as *const libc::sockaddr_storage };
@@ -1487,10 +1271,9 @@
     /// 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",
+            if #[cfg(any(linux_android,
                      target_os = "fuchsia",
-                     target_os = "illumos",
-                     target_os = "linux"
+                     solarish,
                 ))]
             {
                 let p = unsafe{ &self.ss as *const libc::sockaddr_storage };
@@ -1514,29 +1297,17 @@
         }
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     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(linux_android, target_os = "fuchsia"))]
     #[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"
-    ))]
+    #[cfg(any(bsd, solarish))]
     #[cfg(feature = "net")]
     accessors! {
     as_link_addr, as_link_addr_mut, LinkAddr,
@@ -1552,17 +1323,16 @@
     as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6,
     AddressFamily::Inet6, libc::sockaddr_in6, sin6}
 
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     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(all(feature = "ioctl", apple_targets))]
     #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
     accessors! {as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr,
     AddressFamily::System, libc::sockaddr_ctl, sctl}
 
-    #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(linux_android, apple_targets))]
     accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr,
     AddressFamily::Vsock, libc::sockaddr_vm, vsock}
 }
@@ -1581,37 +1351,25 @@
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         unsafe {
             match self.ss.ss_family as i32 {
-                #[cfg(any(target_os = "android", target_os = "linux"))]
+                #[cfg(linux_android)]
                 libc::AF_ALG => self.alg.fmt(f),
                 #[cfg(feature = "net")]
                 libc::AF_INET => self.sin.fmt(f),
                 #[cfg(feature = "net")]
                 libc::AF_INET6 => self.sin6.fmt(f),
-                #[cfg(any(
-                    target_os = "dragonfly",
-                    target_os = "freebsd",
-                    target_os = "ios",
-                    target_os = "macos",
-                    target_os = "illumos",
-                    target_os = "netbsd",
-                    target_os = "openbsd"
-                ))]
+                #[cfg(any(bsd, solarish))]
                 #[cfg(feature = "net")]
                 libc::AF_LINK => self.dl.fmt(f),
-                #[cfg(any(target_os = "android", target_os = "linux"))]
+                #[cfg(linux_android)]
                 libc::AF_NETLINK => self.nl.fmt(f),
-                #[cfg(any(
-                    target_os = "android",
-                    target_os = "linux",
-                    target_os = "fuchsia"
-                ))]
+                #[cfg(any(linux_android, target_os = "fuchsia"))]
                 #[cfg(feature = "net")]
                 libc::AF_PACKET => self.dl.fmt(f),
-                #[cfg(any(target_os = "ios", target_os = "macos"))]
+                #[cfg(apple_targets)]
                 #[cfg(feature = "ioctl")]
                 libc::AF_SYSTEM => self.sctl.fmt(f),
                 libc::AF_UNIX => self.su.fmt(f),
-                #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
+                #[cfg(any(linux_android, apple_targets))]
                 libc::AF_VSOCK => self.vsock.fmt(f),
                 _ => "<Address family unspecified>".fmt(f),
             }
@@ -1655,37 +1413,25 @@
     fn hash<H: Hasher>(&self, s: &mut H) {
         unsafe {
             match self.ss.ss_family as i32 {
-                #[cfg(any(target_os = "android", target_os = "linux"))]
+                #[cfg(linux_android)]
                 libc::AF_ALG => self.alg.hash(s),
                 #[cfg(feature = "net")]
                 libc::AF_INET => self.sin.hash(s),
                 #[cfg(feature = "net")]
                 libc::AF_INET6 => self.sin6.hash(s),
-                #[cfg(any(
-                    target_os = "dragonfly",
-                    target_os = "freebsd",
-                    target_os = "ios",
-                    target_os = "macos",
-                    target_os = "illumos",
-                    target_os = "netbsd",
-                    target_os = "openbsd"
-                ))]
+                #[cfg(any(bsd, solarish))]
                 #[cfg(feature = "net")]
                 libc::AF_LINK => self.dl.hash(s),
-                #[cfg(any(target_os = "android", target_os = "linux"))]
+                #[cfg(linux_android)]
                 libc::AF_NETLINK => self.nl.hash(s),
-                #[cfg(any(
-                    target_os = "android",
-                    target_os = "linux",
-                    target_os = "fuchsia"
-                ))]
+                #[cfg(any(linux_android, target_os = "fuchsia"))]
                 #[cfg(feature = "net")]
                 libc::AF_PACKET => self.dl.hash(s),
-                #[cfg(any(target_os = "ios", target_os = "macos"))]
+                #[cfg(apple_targets)]
                 #[cfg(feature = "ioctl")]
                 libc::AF_SYSTEM => self.sctl.hash(s),
                 libc::AF_UNIX => self.su.hash(s),
-                #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
+                #[cfg(any(linux_android, apple_targets))]
                 libc::AF_VSOCK => self.vsock.hash(s),
                 _ => self.ss.hash(s),
             }
@@ -1697,37 +1443,25 @@
     fn eq(&self, other: &Self) -> bool {
         unsafe {
             match (self.ss.ss_family as i32, other.ss.ss_family as i32) {
-                #[cfg(any(target_os = "android", target_os = "linux"))]
+                #[cfg(linux_android)]
                 (libc::AF_ALG, libc::AF_ALG) => self.alg == other.alg,
                 #[cfg(feature = "net")]
                 (libc::AF_INET, libc::AF_INET) => self.sin == other.sin,
                 #[cfg(feature = "net")]
                 (libc::AF_INET6, libc::AF_INET6) => self.sin6 == other.sin6,
-                #[cfg(any(
-                    target_os = "dragonfly",
-                    target_os = "freebsd",
-                    target_os = "ios",
-                    target_os = "macos",
-                    target_os = "illumos",
-                    target_os = "netbsd",
-                    target_os = "openbsd"
-                ))]
+                #[cfg(any(bsd, solarish))]
                 #[cfg(feature = "net")]
                 (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl,
-                #[cfg(any(target_os = "android", target_os = "linux"))]
+                #[cfg(linux_android)]
                 (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl,
-                #[cfg(any(
-                    target_os = "android",
-                    target_os = "fuchsia",
-                    target_os = "linux"
-                ))]
+                #[cfg(any(linux_android, target_os = "fuchsia"))]
                 #[cfg(feature = "net")]
                 (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl,
-                #[cfg(any(target_os = "ios", target_os = "macos"))]
+                #[cfg(apple_targets)]
                 #[cfg(feature = "ioctl")]
                 (libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl,
                 (libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su,
-                #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
+                #[cfg(any(linux_android, apple_targets))]
                 (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock,
                 _ => false,
             }
@@ -1751,8 +1485,7 @@
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+#[cfg(linux_android)]
 pub mod netlink {
     use super::*;
     use crate::sys::socket::addr::AddressFamily;
@@ -1805,10 +1538,10 @@
                     return None;
                 }
             }
-            if (*addr).sa_family as i32 != libc::AF_NETLINK {
+            if unsafe { (*addr).sa_family as i32 != libc::AF_NETLINK } {
                 return None;
             }
-            Some(Self(ptr::read_unaligned(addr as *const _)))
+            Some(Self(unsafe { ptr::read_unaligned(addr as *const _) }))
         }
     }
 
@@ -1825,11 +1558,10 @@
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+#[cfg(linux_android)]
 pub mod alg {
     use super::*;
-    use libc::{c_char, sockaddr_alg, AF_ALG};
+    use libc::{sockaddr_alg, AF_ALG};
     use std::ffi::CStr;
     use std::hash::{Hash, Hasher};
     use std::{fmt, mem, str};
@@ -1854,10 +1586,10 @@
                     return None;
                 }
             }
-            if (*addr).sa_family as i32 != libc::AF_ALG {
+            if unsafe { (*addr).sa_family as i32 != libc::AF_ALG } {
                 return None;
             }
-            Some(Self(ptr::read_unaligned(addr as *const _)))
+            Some(Self(unsafe { ptr::read_unaligned(addr as *const _) }))
         }
     }
 
@@ -1918,16 +1650,12 @@
 
         /// 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().cast()) }
         }
 
         /// 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().cast()) }
         }
     }
 
@@ -1951,7 +1679,7 @@
 
 feature! {
 #![feature = "ioctl"]
-#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[cfg(apple_targets)]
 pub mod sys_control {
     use crate::sys::socket::addr::AddressFamily;
     use libc::{self, c_uchar};
@@ -1994,10 +1722,10 @@
                     return None;
                 }
             }
-            if (*addr).sa_family as i32 != libc::AF_SYSTEM {
+            if unsafe { (*addr).sa_family as i32 != libc::AF_SYSTEM } {
                 return None;
             }
-            Some(Self(ptr::read_unaligned(addr as *const _)))
+            Some(Self(unsafe { ptr::read_unaligned(addr as *const _) } ))
         }
     }
 
@@ -2058,8 +1786,7 @@
 }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+#[cfg(any(linux_android, target_os = "fuchsia"))]
 mod datalink {
     feature! {
     #![feature = "net"]
@@ -2136,10 +1863,10 @@
                     return None;
                 }
             }
-            if (*addr).sa_family as i32 != libc::AF_PACKET {
+            if unsafe { (*addr).sa_family as i32 != libc::AF_PACKET } {
                 return None;
             }
-            Some(Self(ptr::read_unaligned(addr as *const _)))
+            Some(Self(unsafe { ptr::read_unaligned(addr as *const _) }))
         }
     }
 
@@ -2152,18 +1879,7 @@
     }
 }
 
-#[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 = "aix",
-    target_os = "openbsd"
-))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+#[cfg(any(bsd, solarish, target_os = "haiku", target_os = "aix"))]
 mod datalink {
     feature! {
     #![feature = "net"]
@@ -2261,10 +1977,10 @@
                     return None;
                 }
             }
-            if (*addr).sa_family as i32 != libc::AF_LINK {
+            if unsafe { (*addr).sa_family as i32 != libc::AF_LINK } {
                 return None;
             }
-            Some(Self(ptr::read_unaligned(addr as *const _)))
+            Some(Self(unsafe { ptr::read_unaligned(addr as *const _) }))
         }
     }
 
@@ -2276,8 +1992,7 @@
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+#[cfg(any(linux_android, apple_targets))]
 pub mod vsock {
     use super::*;
     use crate::sys::socket::addr::AddressFamily;
@@ -2308,10 +2023,10 @@
                     return None;
                 }
             }
-            if (*addr).sa_family as i32 != libc::AF_VSOCK {
+            if unsafe { (*addr).sa_family as i32 != libc::AF_VSOCK } {
                 return None;
             }
-            Some(Self(ptr::read_unaligned(addr as *const _)))
+            unsafe { Some(Self(ptr::read_unaligned(addr as *const _))) }
         }
     }
 
@@ -2322,32 +2037,47 @@
     }
 
     impl PartialEq for VsockAddr {
-        #[cfg(any(target_os = "android", target_os = "linux"))]
+        #[cfg(linux_android)]
         fn eq(&self, other: &Self) -> bool {
             let (inner, other) = (self.0, other.0);
             (inner.svm_family, inner.svm_cid, inner.svm_port)
                 == (other.svm_family, other.svm_cid, other.svm_port)
         }
-        #[cfg(target_os = "macos")]
+        #[cfg(apple_targets)]
         fn eq(&self, other: &Self) -> bool {
             let (inner, other) = (self.0, other.0);
-            (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len)
-                == (other.svm_family, other.svm_cid, other.svm_port, inner.svm_len)
+            (
+                inner.svm_family,
+                inner.svm_cid,
+                inner.svm_port,
+                inner.svm_len,
+            ) == (
+                other.svm_family,
+                other.svm_cid,
+                other.svm_port,
+                inner.svm_len,
+            )
         }
     }
 
     impl Eq for VsockAddr {}
 
     impl Hash for VsockAddr {
-        #[cfg(any(target_os = "android", target_os = "linux"))]
+        #[cfg(linux_android)]
         fn hash<H: Hasher>(&self, s: &mut H) {
             let inner = self.0;
             (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s);
         }
-        #[cfg(target_os = "macos")]
+        #[cfg(apple_targets)]
         fn hash<H: Hasher>(&self, s: &mut H) {
             let inner = self.0;
-            (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len).hash(s);
+            (
+                inner.svm_family,
+                inner.svm_cid,
+                inner.svm_port,
+                inner.svm_len,
+            )
+                .hash(s);
         }
     }
 
@@ -2363,9 +2093,9 @@
             addr.svm_cid = cid;
             addr.svm_port = port;
 
-            #[cfg(target_os = "macos")]
+            #[cfg(apple_targets)]
             {
-             addr.svm_len =  std::mem::size_of::<sockaddr_vm>() as u8;
+                addr.svm_len = std::mem::size_of::<sockaddr_vm>() as u8;
             }
             VsockAddr(addr)
         }
@@ -2419,27 +2149,16 @@
         }
     }
 
-    #[cfg(not(target_os = "redox"))]
+    #[cfg(not(any(target_os = "hurd", target_os = "redox")))]
     mod link {
         #![allow(clippy::cast_ptr_alignment)]
 
-        #[cfg(any(
-            target_os = "ios",
-            target_os = "macos",
-            target_os = "illumos"
-        ))]
+        #[cfg(any(apple_targets, solarish))]
         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(bsd)]
         #[test]
         fn test_datalink_display() {
             use super::super::LinkAddr;
@@ -2459,11 +2178,7 @@
         }
 
         #[cfg(all(
-            any(
-                target_os = "android",
-                target_os = "fuchsia",
-                target_os = "linux"
-            ),
+            any(linux_android, target_os = "fuchsia"),
             target_endian = "little"
         ))]
         #[test]
@@ -2474,7 +2189,7 @@
             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 sa = bytes.0.as_ptr().cast();
             let len = None;
             let sock_addr =
                 unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap();
@@ -2485,12 +2200,12 @@
             }
         }
 
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
+        #[cfg(apple_targets)]
         #[test]
         fn macos_loopback() {
             let bytes =
                 [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0];
-            let sa = bytes.as_ptr() as *const libc::sockaddr;
+            let sa = bytes.as_ptr().cast();
             let len = Some(bytes.len() as socklen_t);
             let sock_addr =
                 unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap();
@@ -2503,7 +2218,7 @@
             }
         }
 
-        #[cfg(any(target_os = "ios", target_os = "macos"))]
+        #[cfg(apple_targets)]
         #[test]
         fn macos_tap() {
             let bytes = [
@@ -2525,9 +2240,9 @@
             }
         }
 
-        #[cfg(target_os = "illumos")]
+        #[cfg(solarish)]
         #[test]
-        fn illumos_tap() {
+        fn solarish_tap() {
             let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176];
             let ptr = bytes.as_ptr();
             let sa = ptr as *const libc::sockaddr;
@@ -2548,23 +2263,9 @@
 
         #[test]
         fn size() {
-            #[cfg(any(
-                target_os = "aix",
-                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(bsd, target_os = "aix", solarish, target_os = "haiku"))]
             let l = mem::size_of::<libc::sockaddr_dl>();
-            #[cfg(any(
-                target_os = "android",
-                target_os = "fuchsia",
-                target_os = "linux"
-            ))]
+            #[cfg(any(linux_android, target_os = "fuchsia"))]
             let l = mem::size_of::<libc::sockaddr_ll>();
             assert_eq!(LinkAddr::size() as usize, l);
         }
@@ -2588,6 +2289,13 @@
                 SockaddrIn::size() as usize
             );
         }
+
+        #[test]
+        fn ip() {
+            let s = "127.0.0.1:8082";
+            let ip = SockaddrIn::from_str(s).unwrap().ip();
+            assert_eq!("127.0.0.1", format!("{ip}"));
+        }
     }
 
     mod sockaddr_in6 {
@@ -2610,6 +2318,13 @@
         }
 
         #[test]
+        fn ip() {
+            let s = "[1234:5678:90ab:cdef::1111:2222]:8080";
+            let ip = SockaddrIn6::from_str(s).unwrap().ip();
+            assert_eq!("1234:5678:90ab:cdef::1111:2222", format!("{ip}"));
+        }
+
+        #[test]
         // Ensure that we can convert to-and-from std::net variants without change.
         fn to_and_from() {
             let s = "[1234:5678:90ab:cdef::1111:2222]:8080";
@@ -2628,28 +2343,28 @@
         #[test]
         fn from_sockaddr_un_named() {
             let ua = UnixAddr::new("/var/run/mysock").unwrap();
-            let ptr = ua.as_ptr() as *const libc::sockaddr;
+            let ptr = ua.as_ptr().cast();
             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"))]
+        #[cfg(linux_android)]
         #[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 ptr = ua.as_ptr().cast();
             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"))]
+        #[cfg(linux_android)]
         #[test]
         fn from_sockaddr_un_abstract_unnamed() {
             let ua = UnixAddr::new_unnamed();
-            let ptr = ua.as_ptr() as *const libc::sockaddr;
+            let ptr = ua.as_ptr().cast();
             let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) }
                 .unwrap();
             assert_eq!(ss.len(), ua.len());
@@ -2659,7 +2374,7 @@
     mod unixaddr {
         use super::*;
 
-        #[cfg(any(target_os = "android", target_os = "linux"))]
+        #[cfg(linux_android)]
         #[test]
         fn abstract_sun_path() {
             let name = String::from("nix\0abstract\0test");
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index 78dd617..3d1651b 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -1,7 +1,7 @@
 //! Socket interface functions
 //!
 //! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html)
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "freebsd", linux_android))]
 #[cfg(feature = "uio")]
 use crate::sys::time::TimeSpec;
 #[cfg(not(target_os = "redox"))]
@@ -9,16 +9,16 @@
 use crate::sys::time::TimeVal;
 use crate::{errno::Errno, Result};
 use cfg_if::cfg_if;
-use libc::{self, c_int, c_void, size_t, socklen_t};
+use libc::{self, c_int, size_t, socklen_t};
 #[cfg(all(feature = "uio", not(target_os = "redox")))]
 use libc::{
-    iovec, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, CMSG_SPACE,
+    c_void, iovec, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, CMSG_SPACE,
 };
 #[cfg(not(target_os = "redox"))]
 use std::io::{IoSlice, IoSliceMut};
 #[cfg(feature = "net")]
 use std::net;
-use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, RawFd, OwnedFd};
+use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd};
 use std::{mem, ptr};
 
 #[deny(missing_docs)]
@@ -34,35 +34,25 @@
 
 pub use self::addr::{SockaddrLike, SockaddrStorage};
 
-#[cfg(any(target_os = "illumos", target_os = "solaris"))]
+#[cfg(solarish)]
 pub use self::addr::{AddressFamily, UnixAddr};
-#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
+#[cfg(not(solarish))]
 pub use self::addr::{AddressFamily, UnixAddr};
-#[cfg(not(any(
-    target_os = "illumos",
-    target_os = "solaris",
-    target_os = "haiku",
-    target_os = "redox",
-)))]
+#[cfg(not(any(solarish, target_os = "haiku", target_os = "hurd", target_os = "redox")))]
 #[cfg(feature = "net")]
 pub use self::addr::{LinkAddr, SockaddrIn, SockaddrIn6};
-#[cfg(any(
-    target_os = "illumos",
-    target_os = "solaris",
-    target_os = "haiku",
-    target_os = "redox",
-))]
+#[cfg(any(solarish, target_os = "haiku", target_os = "hurd", target_os = "redox"))]
 #[cfg(feature = "net")]
 pub use self::addr::{SockaddrIn, SockaddrIn6};
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 pub use crate::sys::socket::addr::alg::AlgAddr;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 pub use crate::sys::socket::addr::netlink::NetlinkAddr;
-#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[cfg(apple_targets)]
 #[cfg(feature = "ioctl")]
 pub use crate::sys::socket::addr::sys_control::SysControlAddr;
-#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
+#[cfg(any(linux_android, apple_targets))]
 pub use crate::sys::socket::addr::vsock::VsockAddr;
 
 #[cfg(all(feature = "uio", not(target_os = "redox")))]
@@ -132,121 +122,108 @@
     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"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
-    KextEvent = libc::SYSPROTO_EVENT,
     /// Allows applications to configure and control a KEXT
     /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
-    #[cfg(any(target_os = "ios", target_os = "macos"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(apple_targets)]
     KextControl = libc::SYSPROTO_CONTROL,
     /// Receives routing and link updates and may be used to modify the routing tables (both IPv4 and IPv6), IP addresses, link
     // parameters, neighbor setups, queueing disciplines, traffic classes and packet classifiers
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkRoute = libc::NETLINK_ROUTE,
     /// Reserved for user-mode socket protocols
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkUserSock = libc::NETLINK_USERSOCK,
     /// Query information about sockets of various protocol families from the kernel
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkSockDiag = libc::NETLINK_SOCK_DIAG,
     /// Netfilter/iptables ULOG.
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkNFLOG = libc::NETLINK_NFLOG,
     /// SELinux event notifications.
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkSELinux = libc::NETLINK_SELINUX,
     /// Open-iSCSI
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkISCSI = libc::NETLINK_ISCSI,
     /// Auditing
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkAudit = libc::NETLINK_AUDIT,
     /// Access to FIB lookup from user space
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP,
     /// Netfilter subsystem
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkNetFilter = libc::NETLINK_NETFILTER,
     /// SCSI Transports
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT,
     /// Infiniband RDMA
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkRDMA = libc::NETLINK_RDMA,
     /// Transport IPv6 packets from netfilter to user space.  Used by ip6_queue kernel module.
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkIPv6Firewall = libc::NETLINK_IP6_FW,
     /// DECnet routing messages
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG,
     /// Kernel messages to user space
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT,
     /// Generic netlink family for simplified netlink usage.
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkGeneric = libc::NETLINK_GENERIC,
     /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow
     /// configuration of the kernel crypto API.
     /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     NetlinkCrypto = libc::NETLINK_CRYPTO,
     /// Non-DIX type protocol number defined for the Ethernet IEEE 802.3 interface that allows packets of all protocols
     /// defined in the interface to be received.
     /// ([ref](https://man7.org/linux/man-pages/man7/packet.7.html))
     // The protocol number is fed into the socket syscall in network byte order.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     EthAll = (libc::ETH_P_ALL as u16).to_be() as i32,
-    /// The Controller Area Network raw socket protocol
-    /// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan))
-    #[cfg(target_os = "linux")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
-    CanRaw = libc::CAN_RAW,
+    /// ICMP protocol ([icmp(7)](https://man7.org/linux/man-pages/man7/icmp.7.html))
+    Icmp = libc::IPPROTO_ICMP,
+    /// ICMPv6 protocol (ICMP over IPv6)
+    IcmpV6 = libc::IPPROTO_ICMPV6,
 }
 
 impl SockProtocol {
+    /// The Controller Area Network raw socket protocol
+    /// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan))
+    #[cfg(target_os = "linux")]
+    #[allow(non_upper_case_globals)]
+    pub const CanRaw: SockProtocol = SockProtocol::Icmp; // Matches libc::CAN_RAW
+
     /// The Controller Area Network broadcast manager protocol
     /// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan))
     #[cfg(target_os = "linux")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     #[allow(non_upper_case_globals)]
     pub const CanBcm: SockProtocol = SockProtocol::NetlinkUserSock; // Matches libc::CAN_BCM
+
+    /// 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(apple_targets)]
+    #[allow(non_upper_case_globals)]
+    pub const KextEvent: SockProtocol = SockProtocol::Icmp; // Matches libc::SYSPROTO_EVENT
 }
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 libc_bitflags! {
     /// Configuration flags for `SO_TIMESTAMPING` interface
     ///
@@ -276,33 +253,23 @@
     /// Additional socket options
     pub struct SockFlag: c_int {
         /// Set non-blocking mode on the new socket
-        #[cfg(any(target_os = "android",
-                  target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "illumos",
-                  target_os = "linux",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android,
+                  freebsdlike,
+                  netbsdlike,
+                  solarish))]
         SOCK_NONBLOCK;
         /// Set close-on-exec on the new descriptor
-        #[cfg(any(target_os = "android",
-                  target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "illumos",
-                  target_os = "linux",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android,
+                  freebsdlike,
+                  netbsdlike,
+                  solarish))]
         SOCK_CLOEXEC;
         /// Return `EPIPE` instead of raising `SIGPIPE`
         #[cfg(target_os = "netbsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         SOCK_NOSIGPIPE;
         /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)`
         /// to the DNS port (typically 53)
         #[cfg(target_os = "openbsd")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         SOCK_DNS;
     }
 }
@@ -333,7 +300,6 @@
         /// the calling process and as well as other processes that hold
         /// file descriptors referring to the same open file description.
         #[cfg(not(target_os = "aix"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         MSG_DONTWAIT;
         /// Receive flags: Control Data was discarded (buffer too small)
         MSG_CTRUNC;
@@ -352,8 +318,7 @@
         /// 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())))]
+        #[cfg(linux_android)]
         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
@@ -362,44 +327,48 @@
         /// [open(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html).
         ///
         /// Only used in [`recvmsg`](fn.recvmsg.html) function.
-        #[cfg(any(target_os = "android",
-                  target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "linux",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, freebsdlike, netbsdlike))]
         MSG_CMSG_CLOEXEC;
         /// Requests not to send `SIGPIPE` errors when the other end breaks the connection.
         /// (For more details, see [send(2)](https://linux.die.net/man/2/send)).
-        #[cfg(any(target_os = "android",
-                  target_os = "dragonfly",
-                  target_os = "freebsd",
+        #[cfg(any(linux_android,
+                  freebsdlike,
+                  solarish,
+                  netbsdlike,
                   target_os = "fuchsia",
-                  target_os = "haiku",
-                  target_os = "illumos",
-                  target_os = "linux",
-                  target_os = "netbsd",
-                  target_os = "openbsd",
-                  target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  target_os = "haiku"))]
         MSG_NOSIGNAL;
         /// Turns on [`MSG_DONTWAIT`] after the first message has been received (only for
         /// `recvmmsg()`).
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
+                  netbsdlike,
                   target_os = "fuchsia",
-                  target_os = "linux",
-                  target_os = "netbsd",
-                  target_os = "freebsd",
-                  target_os = "openbsd",
-                  target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  target_os = "freebsd"))]
         MSG_WAITFORONE;
     }
 }
 
+#[cfg(target_os = "freebsd")]
+libc_enum! {
+    /// A selector for which clock to use when generating packet timestamps.
+    /// Used when setting [`TsClock`](crate::sys::socket::sockopt::TsClock) on a socket.
+    /// (For more details, see [setsockopt(2)](https://man.freebsd.org/cgi/man.cgi?setsockopt)).
+    #[repr(i32)]
+    #[non_exhaustive]
+    pub enum SocketTimestamp {
+        /// Microsecond resolution, realtime. This is the default.
+        SO_TS_REALTIME_MICRO,
+        /// Sub-nanosecond resolution, realtime.
+        SO_TS_BINTIME,
+        /// Nanosecond resolution, realtime.
+        SO_TS_REALTIME,
+        /// Nanosecond resolution, monotonic.
+        SO_TS_MONOTONIC,
+    }
+}
+
 cfg_if! {
-    if #[cfg(any(target_os = "android", target_os = "linux"))] {
+    if #[cfg(linux_android)] {
         /// Unix credentials of the sending process.
         ///
         /// This struct is used with the `SO_PEERCRED` ancillary message
@@ -454,7 +423,7 @@
                 uc.0
             }
         }
-    } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] {
+    } else if #[cfg(freebsdlike)] {
         /// Unix credentials of the sending process.
         ///
         /// This struct is used with the `SCM_CREDS` ancillary message for UNIX sockets.
@@ -487,7 +456,7 @@
             pub fn groups(&self) -> &[libc::gid_t] {
                 unsafe {
                     std::slice::from_raw_parts(
-                        self.0.cmcred_groups.as_ptr() as *const libc::gid_t,
+                        self.0.cmcred_groups.as_ptr(),
                         self.0.cmcred_ngroups as _
                     )
                 }
@@ -503,12 +472,7 @@
 }
 
 cfg_if! {
-    if #[cfg(any(
-                target_os = "dragonfly",
-                target_os = "freebsd",
-                target_os = "macos",
-                target_os = "ios"
-        ))] {
+    if #[cfg(any(freebsdlike, apple_targets))] {
         /// Return type of [`LocalPeerCred`](crate::sys::socket::sockopt::LocalPeerCred)
         #[repr(transparent)]
         #[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -603,8 +567,6 @@
 /// let _ = cmsg_space!(RawFd, TimeVal);
 /// # }
 /// ```
-// Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a
-// stack-allocated array.
 #[macro_export]
 macro_rules! cmsg_space {
     ( $( $x:ty ),* ) => {
@@ -617,7 +579,7 @@
 
 #[inline]
 #[doc(hidden)]
-pub fn cmsg_space<T>() -> usize {
+pub const fn cmsg_space<T>() -> usize {
     // SAFETY: CMSG_SPACE is always safe
     unsafe { libc::CMSG_SPACE(mem::size_of::<T>() as libc::c_uint) as usize }
 }
@@ -677,7 +639,7 @@
 }
 
 /// A type-safe wrapper around a single control message, as used with
-/// [`recvmsg`](#fn.recvmsg).
+/// [`recvmsg`].
 ///
 /// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html)
 //  Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and
@@ -692,12 +654,10 @@
     /// Received version of [`ControlMessage::ScmRights`]
     ScmRights(Vec<RawFd>),
     /// Received version of [`ControlMessage::ScmCredentials`]
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     ScmCredentials(UnixCredentials),
     /// Received version of [`ControlMessage::ScmCreds`]
-    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(freebsdlike)]
     ScmCreds(UnixCredentials),
     /// A message of type `SCM_TIMESTAMP`, containing the time the
     /// packet was received by the kernel.
@@ -760,62 +720,44 @@
     /// A set of nanosecond resolution timestamps
     ///
     /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     ScmTimestampsns(Timestamps),
     /// Nanoseconds resolution timestamp
     ///
     /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     ScmTimestampns(TimeSpec),
-    #[cfg(any(
-        target_os = "android",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-    ))]
+    /// Realtime clock timestamp
+    ///
+    /// [Further reading](https://man.freebsd.org/cgi/man.cgi?setsockopt)
+    #[cfg(target_os = "freebsd")]
+    ScmRealtime(TimeSpec),
+    /// Monotonic clock timestamp
+    ///
+    /// [Further reading](https://man.freebsd.org/cgi/man.cgi?setsockopt)
+    #[cfg(target_os = "freebsd")]
+    ScmMonotonic(TimeSpec),
+    #[cfg(any(linux_android, apple_targets, target_os = "netbsd"))]
     #[cfg(feature = "net")]
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     Ipv4PacketInfo(libc::in_pktinfo),
-    #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "openbsd",
-        target_os = "netbsd",
-    ))]
+    #[cfg(any(linux_android, bsd))]
     #[cfg(feature = "net")]
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     Ipv6PacketInfo(libc::in6_pktinfo),
-    #[cfg(any(
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd",
-    ))]
+    #[cfg(bsd)]
     #[cfg(feature = "net")]
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     Ipv4RecvIf(libc::sockaddr_dl),
-    #[cfg(any(
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd",
-    ))]
+    #[cfg(bsd)]
     #[cfg(feature = "net")]
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     Ipv4RecvDstAddr(libc::in_addr),
-    #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+    #[cfg(any(linux_android, target_os = "freebsd"))]
     #[cfg(feature = "net")]
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     Ipv4OrigDstAddr(libc::sockaddr_in),
-    #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+    #[cfg(any(linux_android, target_os = "freebsd"))]
     #[cfg(feature = "net")]
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     Ipv6OrigDstAddr(libc::sockaddr_in6),
@@ -841,28 +783,31 @@
     ///
     /// `RxqOvfl` socket option should be enabled on a socket
     /// to allow receiving the drop counter.
-    #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(linux_android, target_os = "fuchsia"))]
     RxqOvfl(u32),
 
     /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     #[cfg(feature = "net")]
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     Ipv4RecvErr(libc::sock_extended_err, Option<sockaddr_in>),
     /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     #[cfg(feature = "net")]
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     Ipv6RecvErr(libc::sock_extended_err, Option<sockaddr_in6>),
 
+    /// `SOL_TLS` messages of type `TLS_GET_RECORD_TYPE`
+    #[cfg(any(target_os = "linux"))]
+    TlsGetRecordType(TlsGetRecordType),
+
     /// Catch-all variant for unimplemented cmsg types.
     #[doc(hidden)]
     Unknown(UnknownCmsg),
 }
 
 /// For representing packet timestamps via `SO_TIMESTAMPING` interface
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub struct Timestamps {
     /// software based timestamp, usually one containing data
@@ -873,6 +818,33 @@
     pub hw_raw: TimeSpec,
 }
 
+/// These constants correspond to TLS 1.2 message types, as defined in
+/// RFC 5246, Appendix A.1
+#[cfg(any(target_os = "linux"))]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[repr(u8)]
+#[non_exhaustive]
+pub enum TlsGetRecordType {
+    ChangeCipherSpec ,
+    Alert,
+    Handshake,
+    ApplicationData,
+    Unknown(u8),
+}
+
+#[cfg(any(target_os = "linux"))]
+impl From<u8> for TlsGetRecordType {
+    fn from(x: u8) -> Self {
+        match x {
+            20 => TlsGetRecordType::ChangeCipherSpec,
+            21 => TlsGetRecordType::Alert,
+            22 => TlsGetRecordType::Handshake,
+            23 => TlsGetRecordType::ApplicationData,
+            _ => TlsGetRecordType::Unknown(x),
+        }
+    }
+}
+
 impl ControlMessageOwned {
     /// Decodes a `ControlMessageOwned` from raw bytes.
     ///
@@ -885,7 +857,7 @@
     #[allow(clippy::cast_ptr_alignment)]
     unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned
     {
-        let p = CMSG_DATA(header);
+        let p = unsafe { 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
@@ -895,158 +867,151 @@
                 let n = len / mem::size_of::<RawFd>();
                 let mut fds = Vec::with_capacity(n);
                 for i in 0..n {
-                    let fdp = (p as *const RawFd).add(i);
-                    fds.push(ptr::read_unaligned(fdp));
+                    unsafe {
+                        let fdp = (p as *const RawFd).add(i);
+                        fds.push(ptr::read_unaligned(fdp));
+                    }
                 }
                 ControlMessageOwned::ScmRights(fds)
             },
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
-                let cred: libc::ucred = ptr::read_unaligned(p as *const _);
+                let cred: libc::ucred = unsafe { ptr::read_unaligned(p as *const _) };
                 ControlMessageOwned::ScmCredentials(cred.into())
             }
-            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+            #[cfg(freebsdlike)]
             (libc::SOL_SOCKET, libc::SCM_CREDS) => {
-                let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _);
+                let cred: libc::cmsgcred = unsafe { ptr::read_unaligned(p as *const _) };
                 ControlMessageOwned::ScmCreds(cred.into())
             }
             #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
             (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
-                let tv: libc::timeval = ptr::read_unaligned(p as *const _);
+                let tv: libc::timeval = unsafe { ptr::read_unaligned(p as *const _) };
                 ControlMessageOwned::ScmTimestamp(TimeVal::from(tv))
             },
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => {
-                let ts: libc::timespec = ptr::read_unaligned(p as *const _);
+                let ts: libc::timespec = unsafe { ptr::read_unaligned(p as *const _) };
                 ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts))
             }
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(target_os = "freebsd")]
+            (libc::SOL_SOCKET, libc::SCM_REALTIME) => {
+                let ts: libc::timespec = unsafe { ptr::read_unaligned(p as *const _) };
+                ControlMessageOwned::ScmRealtime(TimeSpec::from(ts))
+            }
+            #[cfg(target_os = "freebsd")]
+            (libc::SOL_SOCKET, libc::SCM_MONOTONIC) => {
+                let ts: libc::timespec = unsafe { ptr::read_unaligned(p as *const _) };
+                ControlMessageOwned::ScmMonotonic(TimeSpec::from(ts))
+            }
+            #[cfg(linux_android)]
             (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => {
                 let tp = p as *const libc::timespec;
-                let ts: libc::timespec = ptr::read_unaligned(tp);
+                let ts: libc::timespec = unsafe { ptr::read_unaligned(tp) };
                 let system = TimeSpec::from(ts);
-                let ts: libc::timespec = ptr::read_unaligned(tp.add(1));
+                let ts: libc::timespec = unsafe { ptr::read_unaligned(tp.add(1)) };
                 let hw_trans = TimeSpec::from(ts);
-                let ts: libc::timespec = ptr::read_unaligned(tp.add(2));
+                let ts: libc::timespec = unsafe { ptr::read_unaligned(tp.add(2)) };
                 let hw_raw = TimeSpec::from(ts);
                 let timestamping = Timestamps { system, hw_trans, hw_raw };
                 ControlMessageOwned::ScmTimestampsns(timestamping)
             }
-            #[cfg(any(
-                target_os = "android",
-                target_os = "freebsd",
-                target_os = "ios",
-                target_os = "linux",
-                target_os = "macos"
-            ))]
+            #[cfg(any(target_os = "freebsd", linux_android, apple_targets))]
             #[cfg(feature = "net")]
             (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
-                let info = ptr::read_unaligned(p as *const libc::in6_pktinfo);
+                let info = unsafe { ptr::read_unaligned(p as *const libc::in6_pktinfo) };
                 ControlMessageOwned::Ipv6PacketInfo(info)
             }
-            #[cfg(any(
-                target_os = "android",
-                target_os = "ios",
-                target_os = "linux",
-                target_os = "macos",
-                target_os = "netbsd",
-            ))]
+            #[cfg(any(linux_android, apple_targets, target_os = "netbsd"))]
             #[cfg(feature = "net")]
             (libc::IPPROTO_IP, libc::IP_PKTINFO) => {
-                let info = ptr::read_unaligned(p as *const libc::in_pktinfo);
+                let info = unsafe { ptr::read_unaligned(p as *const libc::in_pktinfo) };
                 ControlMessageOwned::Ipv4PacketInfo(info)
             }
-            #[cfg(any(
-                target_os = "freebsd",
-                target_os = "ios",
-                target_os = "macos",
-                target_os = "netbsd",
-                target_os = "openbsd",
-            ))]
+            #[cfg(bsd)]
             #[cfg(feature = "net")]
             (libc::IPPROTO_IP, libc::IP_RECVIF) => {
-                let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl);
+                let dl = unsafe { ptr::read_unaligned(p as *const libc::sockaddr_dl) };
                 ControlMessageOwned::Ipv4RecvIf(dl)
             },
-            #[cfg(any(
-                target_os = "freebsd",
-                target_os = "ios",
-                target_os = "macos",
-                target_os = "netbsd",
-                target_os = "openbsd",
-            ))]
+            #[cfg(bsd)]
             #[cfg(feature = "net")]
             (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => {
-                let dl = ptr::read_unaligned(p as *const libc::in_addr);
+                let dl = unsafe { ptr::read_unaligned(p as *const libc::in_addr) };
                 ControlMessageOwned::Ipv4RecvDstAddr(dl)
             },
-            #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+            #[cfg(any(linux_android, target_os = "freebsd"))]
             #[cfg(feature = "net")]
             (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => {
-                let dl = ptr::read_unaligned(p as *const libc::sockaddr_in);
+                let dl = unsafe { ptr::read_unaligned(p as *const libc::sockaddr_in) };
                 ControlMessageOwned::Ipv4OrigDstAddr(dl)
             },
             #[cfg(target_os = "linux")]
             #[cfg(feature = "net")]
             (libc::SOL_UDP, libc::UDP_GRO) => {
-                let gso_size: u16 = ptr::read_unaligned(p as *const _);
+                let gso_size: u16 = unsafe { ptr::read_unaligned(p as *const _) };
                 ControlMessageOwned::UdpGroSegments(gso_size)
             },
-            #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+            #[cfg(any(linux_android, target_os = "fuchsia"))]
             (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => {
-                let drop_counter = ptr::read_unaligned(p as *const u32);
+                let drop_counter = unsafe { ptr::read_unaligned(p as *const u32) };
                 ControlMessageOwned::RxqOvfl(drop_counter)
             },
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             #[cfg(feature = "net")]
             (libc::IPPROTO_IP, libc::IP_RECVERR) => {
-                let (err, addr) = Self::recv_err_helper::<sockaddr_in>(p, len);
+                let (err, addr) = unsafe { Self::recv_err_helper::<sockaddr_in>(p, len) };
                 ControlMessageOwned::Ipv4RecvErr(err, addr)
             },
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             #[cfg(feature = "net")]
             (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => {
-                let (err, addr) = Self::recv_err_helper::<sockaddr_in6>(p, len);
+                let (err, addr) = unsafe { Self::recv_err_helper::<sockaddr_in6>(p, len) };
                 ControlMessageOwned::Ipv6RecvErr(err, addr)
             },
-            #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+            #[cfg(any(linux_android, target_os = "freebsd"))]
             #[cfg(feature = "net")]
             (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => {
-                let dl = ptr::read_unaligned(p as *const libc::sockaddr_in6);
+                let dl = unsafe { ptr::read_unaligned(p as *const libc::sockaddr_in6) };
                 ControlMessageOwned::Ipv6OrigDstAddr(dl)
             },
+            #[cfg(any(target_os = "linux"))]
+            (libc::SOL_TLS, libc::TLS_GET_RECORD_TYPE) => {
+                let content_type = unsafe { ptr::read_unaligned(p as *const u8) };
+                ControlMessageOwned::TlsGetRecordType(content_type.into())
+            },
             (_, _) => {
-                let sl = std::slice::from_raw_parts(p, len);
+                let sl = unsafe { std::slice::from_raw_parts(p, len) };
                 let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl));
                 ControlMessageOwned::Unknown(ucmsg)
             }
         }
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     #[cfg(feature = "net")]
     #[allow(clippy::cast_ptr_alignment)]    // False positive
     unsafe fn recv_err_helper<T>(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option<T>) {
         let ee = p as *const libc::sock_extended_err;
-        let err = ptr::read_unaligned(ee);
+        let err = unsafe { ptr::read_unaligned(ee) };
 
         // For errors originating on the network, SO_EE_OFFENDER(ee) points inside the p[..len]
         // CMSG_DATA buffer.  For local errors, there is no address included in the control
         // message, and SO_EE_OFFENDER(ee) points beyond the end of the buffer.  So, we need to
         // validate that the address object is in-bounds before we attempt to copy it.
-        let addrp = libc::SO_EE_OFFENDER(ee) as *const T;
+        let addrp = unsafe { libc::SO_EE_OFFENDER(ee) as *const T };
 
-        if addrp.offset(1) as usize - (p as usize) > len {
+        if unsafe { addrp.offset(1) } as usize - (p as usize) > len {
             (err, None)
         } else {
-            (err, Some(ptr::read_unaligned(addrp)))
+            (err, Some(unsafe { ptr::read_unaligned(addrp) }))
         }
     }
 }
 
-/// A type-safe zero-copy wrapper around a single control message, as used wih
-/// [`sendmsg`](#fn.sendmsg).  More types may be added to this enum; do not
-/// exhaustively pattern-match it.
+/// A type-safe zero-copy wrapper around a single control message, as used with
+/// [`sendmsg`].  More types may be added to this enum; do not exhaustively
+/// pattern-match it.
 ///
 /// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html)
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -1074,8 +1039,7 @@
     ///
     /// For further information, please refer to the
     /// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     ScmCredentials(&'a UnixCredentials),
     /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of
     /// a process connected to the socket.
@@ -1089,41 +1053,28 @@
     ///
     /// For further information, please refer to the
     /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page.
-    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(freebsdlike)]
     ScmCreds,
 
     /// Set IV for `AF_ALG` crypto API.
     ///
     /// For further information, please refer to the
     /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
-    #[cfg(any(
-        target_os = "android",
-        target_os = "linux",
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     AlgSetIv(&'a [u8]),
     /// Set crypto operation for `AF_ALG` crypto API. It may be one of
     /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT`
     ///
     /// For further information, please refer to the
     /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
-    #[cfg(any(
-        target_os = "android",
-        target_os = "linux",
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     AlgSetOp(&'a libc::c_int),
     /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms)
     /// for `AF_ALG` crypto API.
     ///
     /// For further information, please refer to the
     /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
-    #[cfg(any(
-        target_os = "android",
-        target_os = "linux",
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     AlgSetAeadAssoclen(&'a u32),
 
     /// UDP GSO makes it possible for applications to generate network packets
@@ -1139,51 +1090,52 @@
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     UdpGsoSegments(&'a u16),
 
-    /// Configure the sending addressing and interface for v4
+    /// Configure the sending addressing and interface for v4.
     ///
     /// For further information, please refer to the
     /// [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html) man page.
-    #[cfg(any(target_os = "linux",
-              target_os = "macos",
-              target_os = "netbsd",
-              target_os = "android",
-              target_os = "ios",))]
+    #[cfg(any(linux_android, target_os = "netbsd", apple_targets))]
     #[cfg(feature = "net")]
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     Ipv4PacketInfo(&'a libc::in_pktinfo),
 
-    /// Configure the sending addressing and interface for v6
+    /// Configure the sending addressing and interface for v6.
     ///
     /// For further information, please refer to the
     /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page.
-    #[cfg(any(target_os = "linux",
-              target_os = "macos",
+    #[cfg(any(linux_android,
               target_os = "netbsd",
               target_os = "freebsd",
-              target_os = "android",
-              target_os = "ios",))]
+              apple_targets))]
     #[cfg(feature = "net")]
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     Ipv6PacketInfo(&'a libc::in6_pktinfo),
 
     /// Configure the IPv4 source address with `IP_SENDSRCADDR`.
-    #[cfg(any(
-        target_os = "netbsd",
-        target_os = "freebsd",
-        target_os = "openbsd",
-        target_os = "dragonfly",
-    ))]
+    #[cfg(any(freebsdlike, netbsdlike))]
     #[cfg(feature = "net")]
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
     Ipv4SendSrcAddr(&'a libc::in_addr),
 
+    /// Configure the hop limit for v6 multicast traffic.
+    ///
+    /// Set the IPv6 hop limit for this message. The argument is an integer
+    /// between 0 and 255. A value of -1 will set the hop limit to the route
+    /// default if possible on the interface. Without this cmsg,  packets sent
+    /// with sendmsg have a hop limit of 1 and will not leave the local network.
+    /// For further information, please refer to the
+    /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page.
+    #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
+    #[cfg(feature = "net")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
+    Ipv6HopLimit(&'a libc::c_int),
+
     /// SO_RXQ_OVFL indicates that an unsigned 32 bit value
     /// ancilliary msg (cmsg) should be attached to recieved
     /// skbs indicating the number of packets dropped by the
     /// socket between the last recieved packet and this
     /// received packet.
-    #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(linux_android, target_os = "fuchsia"))]
     RxqOvfl(&'a u32),
 
     /// Configure the transmission time of packets.
@@ -1227,18 +1179,18 @@
             ControlMessage::ScmRights(fds) => {
                 fds as *const _ as *const u8
             },
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::ScmCredentials(creds) => {
                 &creds.0 as *const libc::ucred as *const u8
             }
-            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+            #[cfg(freebsdlike)]
             ControlMessage::ScmCreds => {
                 // The kernel overwrites the data, we just zero it
                 // to make sure it's not uninitialized memory
                 unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) };
                 return
             }
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::AlgSetIv(iv) => {
                 #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501
                 let af_alg_iv = libc::af_alg_iv {
@@ -1263,11 +1215,11 @@
 
                 return
             },
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::AlgSetOp(op) => {
                 op as *const _ as *const u8
             },
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::AlgSetAeadAssoclen(len) => {
                 len as *const _ as *const u8
             },
@@ -1276,21 +1228,20 @@
             ControlMessage::UdpGsoSegments(gso_size) => {
                 gso_size as *const _ as *const u8
             },
-            #[cfg(any(target_os = "linux", target_os = "macos",
-                      target_os = "netbsd", target_os = "android",
-                      target_os = "ios",))]
+            #[cfg(any(linux_android, target_os = "netbsd", apple_targets))]
             #[cfg(feature = "net")]
             ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8,
-            #[cfg(any(target_os = "linux", target_os = "macos",
-                      target_os = "netbsd", target_os = "freebsd",
-                      target_os = "android", target_os = "ios",))]
+            #[cfg(any(linux_android, target_os = "netbsd",
+                      target_os = "freebsd", apple_targets))]
             #[cfg(feature = "net")]
             ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8,
-            #[cfg(any(target_os = "netbsd", target_os = "freebsd",
-                      target_os = "openbsd", target_os = "dragonfly"))]
+            #[cfg(any(freebsdlike, netbsdlike))]
             #[cfg(feature = "net")]
             ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8,
-            #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+            #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
+            #[cfg(feature = "net")]
+            ControlMessage::Ipv6HopLimit(limit) => limit as *const _ as *const u8,
+            #[cfg(any(linux_android, target_os = "fuchsia"))]
             ControlMessage::RxqOvfl(drop_count) => {
                 drop_count as *const _ as *const u8
             },
@@ -1314,23 +1265,23 @@
             ControlMessage::ScmRights(fds) => {
                 mem::size_of_val(fds)
             },
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::ScmCredentials(creds) => {
                 mem::size_of_val(creds)
             }
-            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+            #[cfg(freebsdlike)]
             ControlMessage::ScmCreds => {
                 mem::size_of::<libc::cmsgcred>()
             }
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::AlgSetIv(iv) => {
                 mem::size_of::<&[u8]>() + iv.len()
             },
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::AlgSetOp(op) => {
                 mem::size_of_val(op)
             },
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::AlgSetAeadAssoclen(len) => {
                 mem::size_of_val(len)
             },
@@ -1339,21 +1290,22 @@
             ControlMessage::UdpGsoSegments(gso_size) => {
                 mem::size_of_val(gso_size)
             },
-            #[cfg(any(target_os = "linux", target_os = "macos",
-              target_os = "netbsd", target_os = "android",
-              target_os = "ios",))]
+            #[cfg(any(linux_android, target_os = "netbsd", apple_targets))]
             #[cfg(feature = "net")]
             ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info),
-            #[cfg(any(target_os = "linux", target_os = "macos",
-              target_os = "netbsd", target_os = "freebsd",
-              target_os = "android", target_os = "ios",))]
+            #[cfg(any(linux_android, target_os = "netbsd",
+                      target_os = "freebsd", apple_targets))]
             #[cfg(feature = "net")]
             ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info),
-            #[cfg(any(target_os = "netbsd", target_os = "freebsd",
-                      target_os = "openbsd", target_os = "dragonfly"))]
+            #[cfg(any(freebsdlike, netbsdlike))]
             #[cfg(feature = "net")]
             ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr),
-            #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+            #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
+            #[cfg(feature = "net")]
+            ControlMessage::Ipv6HopLimit(limit) => {
+                mem::size_of_val(limit)
+            },
+            #[cfg(any(linux_android, target_os = "fuchsia"))]
             ControlMessage::RxqOvfl(drop_count) => {
                 mem::size_of_val(drop_count)
             },
@@ -1368,31 +1320,30 @@
     fn cmsg_level(&self) -> libc::c_int {
         match *self {
             ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
-            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+            #[cfg(freebsdlike)]
             ControlMessage::ScmCreds => libc::SOL_SOCKET,
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) |
                 ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG,
             #[cfg(target_os = "linux")]
             #[cfg(feature = "net")]
             ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP,
-            #[cfg(any(target_os = "linux", target_os = "macos",
-                      target_os = "netbsd", target_os = "android",
-                      target_os = "ios",))]
+            #[cfg(any(linux_android, target_os = "netbsd", apple_targets))]
             #[cfg(feature = "net")]
             ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP,
-            #[cfg(any(target_os = "linux", target_os = "macos",
-              target_os = "netbsd", target_os = "freebsd",
-              target_os = "android", target_os = "ios",))]
+            #[cfg(any(linux_android, target_os = "netbsd",
+                      target_os = "freebsd", apple_targets))]
             #[cfg(feature = "net")]
             ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
-            #[cfg(any(target_os = "netbsd", target_os = "freebsd",
-                      target_os = "openbsd", target_os = "dragonfly"))]
+            #[cfg(any(freebsdlike, netbsdlike))]
             #[cfg(feature = "net")]
             ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP,
-            #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+            #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
+            #[cfg(feature = "net")]
+            ControlMessage::Ipv6HopLimit(_) => libc::IPPROTO_IPV6,
+            #[cfg(any(linux_android, target_os = "fuchsia"))]
             ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET,
             #[cfg(target_os = "linux")]
             ControlMessage::TxTime(_) => libc::SOL_SOCKET,
@@ -1403,19 +1354,19 @@
     fn cmsg_type(&self) -> libc::c_int {
         match *self {
             ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
-            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+            #[cfg(freebsdlike)]
             ControlMessage::ScmCreds => libc::SCM_CREDS,
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::AlgSetIv(_) => {
                 libc::ALG_SET_IV
             },
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::AlgSetOp(_) => {
                 libc::ALG_SET_OP
             },
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             ControlMessage::AlgSetAeadAssoclen(_) => {
                 libc::ALG_SET_AEAD_ASSOCLEN
             },
@@ -1424,21 +1375,20 @@
             ControlMessage::UdpGsoSegments(_) => {
                 libc::UDP_SEGMENT
             },
-            #[cfg(any(target_os = "linux", target_os = "macos",
-                      target_os = "netbsd", target_os = "android",
-                      target_os = "ios",))]
+            #[cfg(any(linux_android, target_os = "netbsd", apple_targets))]
             #[cfg(feature = "net")]
             ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO,
-            #[cfg(any(target_os = "linux", target_os = "macos",
-                      target_os = "netbsd", target_os = "freebsd",
-                      target_os = "android", target_os = "ios",))]
+            #[cfg(any(linux_android, target_os = "netbsd",
+                      target_os = "freebsd", apple_targets))]
             #[cfg(feature = "net")]
             ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO,
-            #[cfg(any(target_os = "netbsd", target_os = "freebsd",
-                      target_os = "openbsd", target_os = "dragonfly"))]
+            #[cfg(any(freebsdlike, netbsdlike))]
             #[cfg(feature = "net")]
             ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR,
-            #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+            #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
+            #[cfg(feature = "net")]
+            ControlMessage::Ipv6HopLimit(_) => libc::IPV6_HOPLIMIT,
+            #[cfg(any(linux_android, target_os = "fuchsia"))]
             ControlMessage::RxqOvfl(_) => {
                 libc::SO_RXQ_OVFL
             },
@@ -1452,10 +1402,12 @@
     // Unsafe: cmsg must point to a valid cmsghdr with enough space to
     // encode self.
     unsafe fn encode_into(&self, cmsg: *mut cmsghdr) {
-        (*cmsg).cmsg_level = self.cmsg_level();
-        (*cmsg).cmsg_type = self.cmsg_type();
-        (*cmsg).cmsg_len = self.cmsg_len();
-        self.copy_to_cmsg_data(CMSG_DATA(cmsg));
+        unsafe {
+            (*cmsg).cmsg_level = self.cmsg_level();
+            (*cmsg).cmsg_type = self.cmsg_type();
+            (*cmsg).cmsg_len = self.cmsg_len();
+            self.copy_to_cmsg_data( CMSG_DATA(cmsg) );
+        }
     }
 }
 
@@ -1479,7 +1431,7 @@
 /// let (r, w) = pipe().unwrap();
 ///
 /// let iov = [IoSlice::new(b"hello")];
-/// let fds = [r];
+/// let fds = [r.as_raw_fd()];
 /// let cmsg = ControlMessage::ScmRights(&fds);
 /// sendmsg::<()>(fd1.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), None).unwrap();
 /// ```
@@ -1496,7 +1448,7 @@
 /// let (r, w) = pipe().unwrap();
 ///
 /// let iov = [IoSlice::new(b"hello")];
-/// let fds = [r];
+/// let fds = [r.as_raw_fd()];
 /// let cmsg = ControlMessage::ScmRights(&fds);
 /// sendmsg(fd.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap();
 /// ```
@@ -1535,12 +1487,7 @@
 ///
 /// # References
 /// [`sendmsg`](fn.sendmsg.html)
-#[cfg(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "freebsd",
-    target_os = "netbsd",
-))]
+#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
 pub fn sendmmsg<'a, XS, AS, C, I, S>(
     fd: RawFd,
     data: &'a mut MultiHeaders<S>,
@@ -1556,7 +1503,7 @@
         AS: AsRef<[Option<S>]>,
         I: AsRef<[IoSlice<'a>]> + 'a,
         C: AsRef<[ControlMessage<'a>]> + 'a,
-        S: SockaddrLike + 'a
+        S: SockaddrLike + 'a,
 {
 
     let mut count = 0;
@@ -1564,11 +1511,11 @@
 
     for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() {
         let p = &mut mmsghdr.msg_hdr;
-        p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec;
+        p.msg_iov = slice.as_ref().as_ptr().cast_mut().cast();
         p.msg_iovlen = slice.as_ref().len() as _;
 
         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 _;
+        p.msg_name = addr.as_ref().map_or(ptr::null(), S::as_ptr).cast_mut().cast();
 
         // Encode each cmsg.  This must happen after initializing the header because
         // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
@@ -1583,9 +1530,16 @@
             pmhdr = unsafe { CMSG_NXTHDR(p, pmhdr) };
         }
 
-        count = i+1;
+        // Doing an unchecked addition is alright here, as the only way to obtain an instance of `MultiHeaders`
+        // is through the `preallocate` function, which takes an `usize` as an argument to define its size,
+        // which also provides an upper bound for the size of this zipped iterator. Thus, `i < usize::MAX` or in
+        // other words: `count` doesn't overflow
+        count = i + 1;
     }
 
+    // SAFETY: all pointers are guaranteed to be valid for the scope of this function. `count` does represent the
+    // maximum number of messages that can be sent safely (i.e. `count` is the minimum of the sizes of `slices`,
+    // `data.items` and `addrs`)
     let sent = Errno::result(unsafe {
         libc::sendmmsg(
             fd,
@@ -1604,12 +1558,7 @@
 }
 
 
-#[cfg(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "freebsd",
-    target_os = "netbsd",
-))]
+#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
 #[derive(Debug)]
 /// Preallocated structures needed for [`recvmmsg`] and [`sendmmsg`] functions
 pub struct MultiHeaders<S> {
@@ -1622,12 +1571,7 @@
     msg_controllen: usize,
 }
 
-#[cfg(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "freebsd",
-    target_os = "netbsd",
-))]
+#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
 impl<S> MultiHeaders<S> {
     /// Preallocate structure used by [`recvmmsg`] and [`sendmmsg`] takes number of headers to preallocate
     ///
@@ -1652,7 +1596,7 @@
             .enumerate()
             .map(|(ix, address)| {
                 let (ptr, cap) = match &mut cmsg_buffers {
-                    Some(v) => ((&mut v[ix * msg_controllen] as *mut u8), msg_controllen),
+                    Some(v) => (&mut v[ix * msg_controllen] as *mut u8, msg_controllen),
                     None => (std::ptr::null_mut(), 0),
                 };
                 let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null_mut(), 0, ptr, cap, address.as_mut_ptr()) };
@@ -1697,12 +1641,7 @@
 // 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",
-))]
+#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
 pub fn recvmmsg<'a, XS, S, I>(
     fd: RawFd,
     data: &'a mut MultiHeaders<S>,
@@ -1711,14 +1650,19 @@
     mut timeout: Option<crate::sys::time::TimeSpec>,
 ) -> crate::Result<MultiResults<'a, S>>
 where
-    XS: IntoIterator<Item = &'a I>,
-    I: AsRef<[IoSliceMut<'a>]> + 'a,
+    XS: IntoIterator<Item = &'a mut I>,
+    I: AsMut<[IoSliceMut<'a>]> + 'a,
 {
     let mut count = 0;
     for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() {
         let p = &mut mmsghdr.msg_hdr;
-        p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec;
-        p.msg_iovlen = slice.as_ref().len() as _;
+        p.msg_iov = slice.as_mut().as_mut_ptr().cast();
+        p.msg_iovlen = slice.as_mut().len() as _;
+
+        // Doing an unchecked addition is alright here, as the only way to obtain an instance of `MultiHeaders`
+        // is through the `preallocate` function, which takes an `usize` as an argument to define its size,
+        // which also provides an upper bound for the size of this zipped iterator. Thus, `i < usize::MAX` or in
+        // other words: `count` doesn't overflow
         count = i + 1;
     }
 
@@ -1726,6 +1670,8 @@
         .as_mut()
         .map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec);
 
+    // SAFETY: all pointers are guaranteed to be valid for the scope of this function. `count` does represent the
+    // maximum number of messages that can be received safely (i.e. `count` is the minimum of the sizes of `slices` and `data.items`)
     let received = Errno::result(unsafe {
         libc::recvmmsg(
             fd,
@@ -1743,16 +1689,9 @@
     })
 }
 
-#[cfg(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "freebsd",
-    target_os = "netbsd",
-))]
-#[derive(Debug)]
 /// Iterator over results of [`recvmmsg`]/[`sendmmsg`]
-///
-///
+#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
+#[derive(Debug)]
 pub struct MultiResults<'a, S> {
     // preallocated structures
     rmm: &'a MultiHeaders<S>,
@@ -1760,12 +1699,7 @@
     received: usize,
 }
 
-#[cfg(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "freebsd",
-    target_os = "netbsd",
-))]
+#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
 impl<'a, S> Iterator for MultiResults<'a, S>
 where
     S: Copy + SockaddrLike,
@@ -1838,108 +1772,6 @@
     }
 }
 
-// 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;
-    use std::os::unix::io::AsRawFd;
-
-    #[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};
-
-        let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap();
-
-        let ssock = socket(
-            AddressFamily::Inet,
-            SockType::Datagram,
-            SockFlag::empty(),
-            None,
-        )?;
-
-        let rsock = socket(
-            AddressFamily::Inet,
-            SockType::Datagram,
-            SockFlag::SOCK_NONBLOCK,
-            None,
-        )?;
-
-        crate::sys::socket::bind(rsock.as_raw_fd(), &sock_addr)?;
-
-        setsockopt(&rsock, Timestamping, &TimestampingFlag::all())?;
-
-        let sbuf = (0..400).map(|i| i as u8).collect::<Vec<_>>();
-
-        let mut recv_buf = vec![0; 1024];
-
-        let mut recv_iovs = Vec::new();
-        let mut pkt_iovs = Vec::new();
-
-        for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() {
-            pkt_iovs.push(IoSliceMut::new(chunk));
-            if ix % 2 == 1 {
-                recv_iovs.push(pkt_iovs);
-                pkt_iovs = Vec::new();
-            }
-        }
-        drop(pkt_iovs);
-
-        let flags = MsgFlags::empty();
-        let iov1 = [IoSlice::new(&sbuf)];
-
-        let cmsg = cmsg_space!(crate::sys::socket::Timestamps);
-        sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
-
-        let mut data = super::MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg));
-
-        let t = sys::time::TimeSpec::from_duration(std::time::Duration::from_secs(10));
-
-        let recv = super::recvmmsg(rsock.as_raw_fd(), &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);
-
-            for iov in rmsg.iovs() {
-                recvd += iov.len();
-            }
-            assert_eq!(recvd, 400);
-        }
-
-        Ok(())
-    }
-}
 unsafe fn read_mhdr<'a, 'i, S>(
     mhdr: msghdr,
     r: isize,
@@ -1951,19 +1783,23 @@
     // The cast is not unnecessary on all platforms.
     #[allow(clippy::unnecessary_cast)]
     let cmsghdr = {
-        if mhdr.msg_controllen > 0 {
+        let ptr = if mhdr.msg_controllen > 0 {
             debug_assert!(!mhdr.msg_control.is_null());
             debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
-            CMSG_FIRSTHDR(&mhdr as *const msghdr)
+            unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) }
         } else {
             ptr::null()
-        }.as_ref()
+        };
+
+        unsafe {
+            ptr.as_ref()
+        }
     };
 
     // Ignore errors if this socket address has statically-known length
     //
     // This is to ensure that unix socket addresses have their length set appropriately.
-    let _ = address.set_length(mhdr.msg_namelen as usize);
+    let _ = unsafe { address.set_length(mhdr.msg_namelen as usize) };
 
     RecvMsg {
         bytes: r as usize,
@@ -2000,14 +1836,16 @@
     // initialize it.
     let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
     let p = mhdr.as_mut_ptr();
-    (*p).msg_name = address 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()
+    unsafe {
+        (*p).msg_name = address 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>(
@@ -2025,7 +1863,7 @@
 
     // The message header must be initialized before the individual cmsgs.
     let cmsg_ptr = if capacity > 0 {
-        cmsg_buffer.as_mut_ptr() as *mut c_void
+        cmsg_buffer.as_mut_ptr().cast()
     } else {
         ptr::null_mut()
     };
@@ -2035,11 +1873,11 @@
         // initialize it.
         let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
         let p = mhdr.as_mut_ptr();
-        (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()) as *mut _;
+        (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()).cast_mut().cast();
         (*p).msg_namelen = addr.map(S::len).unwrap_or(0);
         // transmute iov into a mutable pointer.  sendmsg doesn't really mutate
         // the buffer, but the standard says that it takes a mutable pointer
-        (*p).msg_iov = iov.as_ref().as_ptr() as *mut _;
+        (*p).msg_iov = iov.as_ref().as_ptr().cast_mut().cast();
         (*p).msg_iovlen = iov.as_ref().len() as _;
         (*p).msg_control = cmsg_ptr;
         (*p).msg_controllen = capacity as _;
@@ -2166,17 +2004,51 @@
     Errno::result(res)?;
 
     // Safe because socketpair returned success.
-    unsafe {
-        Ok((OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1])))
+    unsafe { Ok((OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1]))) }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct Backlog(i32);
+
+impl Backlog {
+    /// Sets the listen queue size to system `SOMAXCONN` value
+    pub const MAXCONN: Self = Self(libc::SOMAXCONN);
+    /// Sets the listen queue size to -1 for system supporting it
+    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
+    pub const MAXALLOWABLE: Self = Self(-1);
+
+    /// Create a `Backlog`, an `EINVAL` will be returned if `val` is invalid.
+    pub fn new<I: Into<i32>>(val: I) -> Result<Self> {
+        cfg_if! {
+            if #[cfg(any(target_os = "linux", target_os = "freebsd"))] {
+                const MIN: i32 = -1;
+            } else {
+                const MIN: i32 = 0;
+            }
+        }
+
+        let val = val.into();
+
+        if !(MIN..Self::MAXCONN.0).contains(&val) {
+            return Err(Errno::EINVAL);
+        }
+
+        Ok(Self(val))
+    }
+}
+
+impl From<Backlog> for i32 {
+    fn from(backlog: Backlog) -> Self {
+        backlog.0
     }
 }
 
 /// Listen for connections on a socket
 ///
 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html)
-pub fn listen<F: AsFd>(sock: &F, backlog: usize) -> Result<()> {
+pub fn listen<F: AsFd>(sock: &F, backlog: Backlog) -> Result<()> {
     let fd = sock.as_fd().as_raw_fd();
-    let res = unsafe { libc::listen(fd, backlog as c_int) };
+    let res = unsafe { libc::listen(fd, backlog.into()) };
 
     Errno::result(res).map(drop)
 }
@@ -2211,14 +2083,12 @@
             target_arch = "x86_64"
         )
     ),
-    target_os = "dragonfly",
+    freebsdlike,
+    netbsdlike,
     target_os = "emscripten",
-    target_os = "freebsd",
     target_os = "fuchsia",
-    target_os = "illumos",
+    solarish,
     target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd"
 ))]
 pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
     let res = unsafe {
@@ -2245,7 +2115,7 @@
     unsafe {
         let ret = libc::recv(
             sockfd,
-            buf.as_mut_ptr() as *mut c_void,
+            buf.as_mut_ptr().cast(),
             buf.len() as size_t,
             flags.bits(),
         );
@@ -2269,20 +2139,14 @@
 
         let ret = Errno::result(libc::recvfrom(
             sockfd,
-            buf.as_mut_ptr() as *mut c_void,
+            buf.as_mut_ptr().cast(),
             buf.len() as size_t,
             0,
-            addr.as_mut_ptr() as *mut sockaddr,
+            addr.as_mut_ptr().cast(),
             &mut len as *mut socklen_t,
         ))? as usize;
 
-        Ok((
-            ret,
-            T::from_raw(
-                addr.assume_init().as_ptr(),
-                Some(len),
-            ),
-        ))
+        Ok((ret, T::from_raw(addr.assume_init().as_ptr(), Some(len))))
     }
 }
 
@@ -2298,7 +2162,7 @@
     let ret = unsafe {
         libc::sendto(
             fd,
-            buf.as_ptr() as *const c_void,
+            buf.as_ptr().cast(),
             buf.len() as size_t,
             flags.bits(),
             addr.as_ptr(),
@@ -2314,12 +2178,7 @@
 /// [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().cast(), buf.len() as size_t, flags.bits())
     };
 
     Errno::result(ret).map(|r| r as usize)
@@ -2386,8 +2245,7 @@
         let mut addr = mem::MaybeUninit::<T>::uninit();
         let mut len = T::size();
 
-        let ret =
-            libc::getpeername(fd, addr.as_mut_ptr() as *mut sockaddr, &mut len);
+        let ret = libc::getpeername(fd, addr.as_mut_ptr().cast(), &mut len);
 
         Errno::result(ret)?;
 
@@ -2403,8 +2261,7 @@
         let mut addr = mem::MaybeUninit::<T>::uninit();
         let mut len = T::size();
 
-        let ret =
-            libc::getsockname(fd, addr.as_mut_ptr() as *mut sockaddr, &mut len);
+        let ret = libc::getsockname(fd, addr.as_mut_ptr().cast(), &mut len);
 
         Errno::result(ret)?;
 
@@ -2439,27 +2296,3 @@
     }
 }
 
-#[cfg(test)]
-mod tests {
-    #[cfg(not(target_os = "redox"))]
-    #[test]
-    fn can_use_cmsg_space() {
-        let _ = cmsg_space!(u8);
-    }
-
-    #[cfg(not(any(
-        target_os = "redox",
-        target_os = "linux",
-        target_os = "android"
-    )))]
-    #[test]
-    fn can_open_routing_socket() {
-        let _ = super::socket(
-            super::AddressFamily::Route,
-            super::SockType::Raw,
-            super::SockFlag::empty(),
-            None,
-        )
-        .expect("Failed to open routing socket");
-    }
-}
diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs
index 44f3ebb..4357695 100644
--- a/src/sys/socket/sockopt.rs
+++ b/src/sys/socket/sockopt.rs
@@ -7,7 +7,6 @@
 use libc::{self, c_int, c_void, socklen_t};
 use std::ffi::{OsStr, OsString};
 use std::mem::{self, MaybeUninit};
-#[cfg(target_family = "unix")]
 use std::os::unix::ffi::OsStrExt;
 use std::os::unix::io::{AsFd, AsRawFd};
 
@@ -128,7 +127,7 @@
 ///    both of them.
 /// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for.
 /// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets*
-///    (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
+///    (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
 ///    and more. Please refer to your system manual for more options. Will be passed as the second
 ///    argument (`level`) to the `getsockopt`/`setsockopt` call.
 /// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
@@ -261,7 +260,7 @@
     libc::SO_REUSEADDR,
     bool
 );
-#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
+#[cfg(not(solarish))]
 sockopt_impl!(
     /// Permits multiple AF_INET or AF_INET6 sockets to be bound to an
     /// identical socket address.
@@ -318,7 +317,7 @@
     super::IpMembershipRequest
 );
 cfg_if! {
-    if #[cfg(any(target_os = "android", target_os = "linux"))] {
+    if #[cfg(linux_android)] {
         #[cfg(feature = "net")]
         sockopt_impl!(
             #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -329,14 +328,7 @@
             #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
             /// Leave an IPv6 multicast group.
             Ipv6DropMembership, SetOnly, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
-    } else if #[cfg(any(target_os = "dragonfly",
-                        target_os = "freebsd",
-                        target_os = "illumos",
-                        target_os = "ios",
-                        target_os = "macos",
-                        target_os = "netbsd",
-                        target_os = "openbsd",
-                        target_os = "solaris"))] {
+    } else if #[cfg(any(bsd, solarish))] {
         #[cfg(feature = "net")]
         sockopt_impl!(
             #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -365,6 +357,17 @@
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
+    /// Set or read the hop limit value of outgoing IPv6 multicast packets for
+    /// this socket.
+    Ipv6MulticastHops,
+    Both,
+    libc::IPPROTO_IPV6,
+    libc::IPV6_MULTICAST_HOPS,
+    libc::c_int
+);
+#[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,
@@ -408,7 +411,7 @@
     libc::IPV6_TCLASS,
     libc::c_int
 );
-#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "fuchsia"))]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -420,6 +423,20 @@
     libc::IP_FREEBIND,
     bool
 );
+#[cfg(linux_android)]
+#[cfg(feature = "net")]
+sockopt_impl!(
+    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
+    /// If enabled, the kernel will not reserve an ephemeral port when binding
+    /// socket with a port number of 0. The port will later be automatically
+    /// chosen at connect time, in a way that allows sharing a source port as
+    /// long as the 4-tuple is unique.
+    IpBindAddressNoPort,
+    Both,
+    libc::IPPROTO_IP,
+    libc::IP_BIND_ADDRESS_NO_PORT,
+    bool
+);
 sockopt_impl!(
     /// Specify the receiving timeout until reporting an error.
     ReceiveTimeout,
@@ -477,12 +494,7 @@
     libc::SO_KEEPALIVE,
     bool
 );
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "macos",
-    target_os = "ios"
-))]
+#[cfg(any(freebsdlike, apple_targets))]
 sockopt_impl!(
     /// Get the credentials of the peer process of a connected unix domain
     /// socket.
@@ -492,7 +504,7 @@
     libc::LOCAL_PEERCRED,
     super::XuCred
 );
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(apple_targets)]
 sockopt_impl!(
     /// Get the PID of the peer process of a connected unix domain socket.
     LocalPeerPid,
@@ -501,7 +513,7 @@
     libc::LOCAL_PEERPID,
     libc::c_int
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 sockopt_impl!(
     /// Return the credentials of the foreign process connected to this socket.
     PeerCredentials,
@@ -510,7 +522,18 @@
     libc::SO_PEERCRED,
     super::UnixCredentials
 );
-#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[cfg(target_os = "freebsd")]
+#[cfg(feature = "net")]
+sockopt_impl!(
+    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
+    /// Get backlog limit of the socket
+    ListenQLimit,
+    GetOnly,
+    libc::SOL_SOCKET,
+    libc::SO_LISTENQLIMIT,
+    u32
+);
+#[cfg(apple_targets)]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -522,12 +545,7 @@
     libc::TCP_KEEPALIVE,
     u32
 );
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux"
-))]
+#[cfg(any(freebsdlike, linux_android))]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -540,7 +558,7 @@
     u32
 );
 cfg_if! {
-    if #[cfg(any(target_os = "android", target_os = "linux"))] {
+    if #[cfg(linux_android)] {
         sockopt_impl!(
             /// The maximum segment size for outgoing TCP packets.
             TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
@@ -550,7 +568,11 @@
             TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
     }
 }
-#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "redox")))]
+#[cfg(not(any(
+    target_os = "openbsd",
+    target_os = "haiku",
+    target_os = "redox"
+)))]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -562,7 +584,7 @@
     libc::TCP_KEEPCNT,
     u32
 );
-#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "fuchsia"))]
 sockopt_impl!(
     #[allow(missing_docs)]
     // Not documented by Linux!
@@ -572,7 +594,11 @@
     libc::TCP_REPAIR,
     u32
 );
-#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "redox")))]
+#[cfg(not(any(
+    target_os = "openbsd",
+    target_os = "haiku",
+    target_os = "redox"
+)))]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -596,6 +622,26 @@
     libc::TCP_USER_TIMEOUT,
     u32
 );
+#[cfg(linux_android)]
+#[cfg(feature = "net")]
+sockopt_impl!(
+    #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
+    /// Enables TCP Fast Open (RFC 7413) on a connecting socket. If a fast open
+    /// cookie is not available (first attempt to connect), `connect` syscall
+    /// will behave as usual, except for internally trying to solicit a cookie
+    /// from remote peer. When cookie is available, the next `connect` syscall
+    /// will immediately succeed without actually establishing TCP connection.
+    /// The connection establishment will be defered till the next `write` or
+    /// `sendmsg` syscalls on the socket, allowing TCP prtocol to establish
+    /// connection and send data in the same packets. Note: calling `read` right
+    /// after `connect` without `write` on the socket will cause the blocking
+    /// socket to be blocked forever.
+    TcpFastOpenConnect,
+    Both,
+    libc::IPPROTO_TCP,
+    libc::TCP_FASTOPEN_CONNECT,
+    bool
+);
 sockopt_impl!(
     /// Sets or gets the maximum socket receive buffer in bytes.
     RcvBuf,
@@ -612,7 +658,7 @@
     libc::SO_SNDBUF,
     usize
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 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
@@ -623,7 +669,7 @@
     libc::SO_RCVBUFFORCE,
     usize
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 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
@@ -652,7 +698,7 @@
     libc::SO_ACCEPTCONN,
     bool
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 sockopt_impl!(
     /// Bind this socket to a particular device like “eth0”.
     BindToDevice,
@@ -661,7 +707,7 @@
     libc::SO_BINDTODEVICE,
     OsString<[u8; libc::IFNAMSIZ]>
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -673,7 +719,7 @@
     libc::SO_ORIGINAL_DST,
     libc::sockaddr_in
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 sockopt_impl!(
     #[allow(missing_docs)]
     // Not documented by Linux!
@@ -683,7 +729,7 @@
     libc::IP6T_SO_ORIGINAL_DST,
     libc::sockaddr_in6
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 sockopt_impl!(
     /// Specifies exact type of timestamping information collected by the kernel
     /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
@@ -693,7 +739,7 @@
     libc::SO_TIMESTAMPING,
     super::TimestampingFlag
 );
-#[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "redox")))]
+#[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "hurd", target_os = "redox")))]
 sockopt_impl!(
     /// Enable or disable the receiving of the `SO_TIMESTAMP` control message.
     ReceiveTimestamp,
@@ -702,7 +748,7 @@
     libc::SO_TIMESTAMP,
     bool
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 sockopt_impl!(
     /// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message.
     ReceiveTimestampns,
@@ -719,9 +765,9 @@
     Both,
     libc::SOL_SOCKET,
     libc::SO_TS_CLOCK,
-    i32
+    super::SocketTimestamp
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -806,7 +852,7 @@
     libc::SO_MARK,
     u32
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 sockopt_impl!(
     /// Enable or disable the receiving of the `SCM_CREDENTIALS` control
     /// message.
@@ -828,13 +874,7 @@
     libc::TCP_CONGESTION,
     OsString<[u8; TCP_CA_NAME_MAX]>
 );
-#[cfg(any(
-    target_os = "android",
-    target_os = "ios",
-    target_os = "linux",
-    target_os = "macos",
-    target_os = "netbsd",
-))]
+#[cfg(any(linux_android, apple_targets, target_os = "netbsd"))]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -846,15 +886,7 @@
     libc::IP_PKTINFO,
     bool
 );
-#[cfg(any(
-    target_os = "android",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "linux",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
+#[cfg(any(linux_android, target_os = "freebsd", apple_targets, netbsdlike))]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -866,13 +898,7 @@
     libc::IPV6_RECVPKTINFO,
     bool
 );
-#[cfg(any(
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
+#[cfg(bsd)]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -884,13 +910,7 @@
     libc::IP_RECVIF,
     bool
 );
-#[cfg(any(
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
+#[cfg(bsd)]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -902,7 +922,7 @@
     libc::IP_RECVDSTADDR,
     bool
 );
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -948,7 +968,7 @@
     libc::SO_TXTIME,
     libc::sock_txtime
 );
-#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "fuchsia"))]
 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
@@ -969,7 +989,7 @@
     libc::IPV6_V6ONLY,
     bool
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 sockopt_impl!(
     /// Enable extended reliable error message passing.
     Ipv4RecvErr,
@@ -978,7 +998,7 @@
     libc::IP_RECVERR,
     bool
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 sockopt_impl!(
     /// Control receiving of asynchronous error options.
     Ipv6RecvErr,
@@ -987,7 +1007,7 @@
     libc::IPV6_RECVERR,
     bool
 );
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 sockopt_impl!(
     /// Fetch the current system-estimated Path MTU.
     IpMtu,
@@ -996,7 +1016,7 @@
     libc::IP_MTU,
     libc::c_int
 );
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
 sockopt_impl!(
     /// Set or retrieve the current time-to-live field that is used in every
     /// packet sent from this socket.
@@ -1006,7 +1026,7 @@
     libc::IP_TTL,
     libc::c_int
 );
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
 sockopt_impl!(
     /// Set the unicast hop limit for the socket.
     Ipv6Ttl,
@@ -1015,7 +1035,7 @@
     libc::IPV6_UNICAST_HOPS,
     libc::c_int
 );
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
 #[cfg(feature = "net")]
 sockopt_impl!(
     #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -1027,7 +1047,7 @@
     libc::IPV6_ORIGDSTADDR,
     bool
 );
-#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[cfg(apple_targets)]
 sockopt_impl!(
     /// Set "don't fragment packet" flag on the IP packet.
     IpDontFrag,
@@ -1036,12 +1056,7 @@
     libc::IP_DONTFRAG,
     bool
 );
-#[cfg(any(
-    target_os = "android",
-    target_os = "ios",
-    target_os = "linux",
-    target_os = "macos",
-))]
+#[cfg(any(linux_android, apple_targets))]
 sockopt_impl!(
     /// Set "don't fragment packet" flag on the IPv6 packet.
     Ipv6DontFrag,
@@ -1053,13 +1068,13 @@
 
 #[allow(missing_docs)]
 // Not documented by Linux!
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[derive(Copy, Clone, Debug)]
 pub struct AlgSetAeadAuthSize;
 
 // ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len`
 // See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 impl SetSockOpt for AlgSetAeadAuthSize {
     type Val = usize;
 
@@ -1079,18 +1094,18 @@
 
 #[allow(missing_docs)]
 // Not documented by Linux!
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[derive(Clone, Debug)]
 pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 impl<T> Default for AlgSetKey<T> {
     fn default() -> Self {
         AlgSetKey(Default::default())
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 impl<T> SetSockOpt for AlgSetKey<T>
 where
     T: AsRef<[u8]> + Clone,
@@ -1103,7 +1118,7 @@
                 fd.as_fd().as_raw_fd(),
                 libc::SOL_ALG,
                 libc::ALG_SET_KEY,
-                val.as_ref().as_ptr() as *const _,
+                val.as_ref().as_ptr().cast(),
                 val.as_ref().len() as libc::socklen_t,
             );
             Errno::result(res).map(drop)
@@ -1111,6 +1126,160 @@
     }
 }
 
+/// Set the Upper Layer Protocol (ULP) on the TCP socket.
+///
+/// For example, to enable the TLS ULP on a socket, the C function call would be:
+///
+/// ```c
+/// setsockopt(sock, SOL_TCP, TCP_ULP, "tls", sizeof("tls"));
+/// ```
+///
+/// ... and the `nix` equivalent is:
+///
+/// ```ignore,rust
+/// setsockopt(sock, TcpUlp::default(), b"tls");
+/// ```
+///
+/// Note that the ULP name does not need a trailing NUL terminator (`\0`).
+#[cfg(linux_android)]
+#[derive(Clone, Debug)]
+pub struct TcpUlp<T>(::std::marker::PhantomData<T>);
+
+#[cfg(linux_android)]
+impl<T> Default for TcpUlp<T> {
+    fn default() -> Self {
+        TcpUlp(Default::default())
+    }
+}
+
+#[cfg(linux_android)]
+impl<T> SetSockOpt for TcpUlp<T>
+where
+    T: AsRef<[u8]> + Clone,
+{
+    type Val = T;
+
+    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
+        unsafe {
+            let res = libc::setsockopt(
+                fd.as_fd().as_raw_fd(),
+                libc::SOL_TCP,
+                libc::TCP_ULP,
+                val.as_ref().as_ptr().cast(),
+                val.as_ref().len() as libc::socklen_t,
+            );
+            Errno::result(res).map(drop)
+        }
+    }
+}
+
+/// Value used with the [`TcpTlsTx`] and [`TcpTlsRx`] socket options.
+#[cfg(target_os = "linux")]
+#[derive(Copy, Clone, Debug)]
+pub enum TlsCryptoInfo {
+    /// AES-128-GCM
+    Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128),
+
+    /// AES-256-GCM
+    Aes256Gcm(libc::tls12_crypto_info_aes_gcm_256),
+
+    /// CHACHA20-POLY1305
+    Chacha20Poly1305(libc::tls12_crypto_info_chacha20_poly1305),
+}
+
+/// Set the Kernel TLS write parameters on the TCP socket.
+///
+/// For example, the C function call would be:
+///
+/// ```c
+/// setsockopt(sock, SOL_TLS, TLS_TX, &crypto_info, sizeof(crypto_info));
+/// ```
+///
+/// ... and the `nix` equivalent is:
+///
+/// ```ignore,rust
+/// setsockopt(sock, TcpTlsTx, &crypto_info);
+/// ```
+#[cfg(target_os = "linux")]
+#[derive(Copy, Clone, Debug)]
+pub struct TcpTlsTx;
+
+#[cfg(target_os = "linux")]
+impl SetSockOpt for TcpTlsTx {
+    type Val = TlsCryptoInfo;
+
+    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
+        let (ffi_ptr, ffi_len) = match val {
+            TlsCryptoInfo::Aes128Gcm(crypto_info) => {
+                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
+            }
+            TlsCryptoInfo::Aes256Gcm(crypto_info) => {
+                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
+            }
+            TlsCryptoInfo::Chacha20Poly1305(crypto_info) => {
+                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
+            }
+        };
+        unsafe {
+            let res = libc::setsockopt(
+                fd.as_fd().as_raw_fd(),
+                libc::SOL_TLS,
+                libc::TLS_TX,
+                ffi_ptr,
+                ffi_len as libc::socklen_t,
+            );
+            Errno::result(res).map(drop)
+        }
+    }
+}
+
+/// Set the Kernel TLS read parameters on the TCP socket.
+///
+/// For example, the C function call would be:
+///
+/// ```c
+/// setsockopt(sock, SOL_TLS, TLS_RX, &crypto_info, sizeof(crypto_info));
+/// ```
+///
+/// ... and the `nix` equivalent is:
+///
+/// ```ignore,rust
+/// setsockopt(sock, TcpTlsRx, &crypto_info);
+/// ```
+#[cfg(target_os = "linux")]
+#[derive(Copy, Clone, Debug)]
+pub struct TcpTlsRx;
+
+#[cfg(target_os = "linux")]
+impl SetSockOpt for TcpTlsRx {
+    type Val = TlsCryptoInfo;
+
+    fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()> {
+        let (ffi_ptr, ffi_len) = match val {
+            TlsCryptoInfo::Aes128Gcm(crypto_info) => {
+                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
+            }
+            TlsCryptoInfo::Aes256Gcm(crypto_info) => {
+                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
+            }
+            TlsCryptoInfo::Chacha20Poly1305(crypto_info) => {
+                (<*const _>::cast(crypto_info), mem::size_of_val(crypto_info))
+            }
+        };
+        unsafe {
+            let res = libc::setsockopt(
+                fd.as_fd().as_raw_fd(),
+                libc::SOL_TLS,
+                libc::TLS_RX,
+                ffi_ptr,
+                ffi_len as libc::socklen_t,
+            );
+            Errno::result(res).map(drop)
+        }
+    }
+}
+
+
 /*
  *
  * ===== Accessor helpers =====
@@ -1158,7 +1327,7 @@
     }
 
     fn ffi_ptr(&mut self) -> *mut c_void {
-        self.val.as_mut_ptr() as *mut c_void
+        self.val.as_mut_ptr().cast()
     }
 
     fn ffi_len(&mut self) -> *mut socklen_t {
@@ -1171,7 +1340,7 @@
             mem::size_of::<T>(),
             "invalid getsockopt implementation"
         );
-        self.val.assume_init()
+        unsafe { self.val.assume_init() }
     }
 }
 
@@ -1209,7 +1378,7 @@
     }
 
     fn ffi_ptr(&mut self) -> *mut c_void {
-        self.val.as_mut_ptr() as *mut c_void
+        self.val.as_mut_ptr().cast()
     }
 
     fn ffi_len(&mut self) -> *mut socklen_t {
@@ -1222,7 +1391,7 @@
             mem::size_of::<c_int>(),
             "invalid getsockopt implementation"
         );
-        self.val.assume_init() != 0
+        unsafe { self.val.assume_init() != 0 }
     }
 }
 
@@ -1243,7 +1412,7 @@
     }
 
     fn ffi_len(&self) -> socklen_t {
-        mem::size_of::<c_int>() as socklen_t
+        mem::size_of_val(&self.val) as socklen_t
     }
 }
 
@@ -1262,7 +1431,7 @@
     }
 
     fn ffi_ptr(&mut self) -> *mut c_void {
-        self.val.as_mut_ptr() as *mut c_void
+        self.val.as_mut_ptr().cast()
     }
 
     fn ffi_len(&mut self) -> *mut socklen_t {
@@ -1275,7 +1444,7 @@
             mem::size_of::<u8>(),
             "invalid getsockopt implementation"
         );
-        self.val.assume_init()
+        unsafe { self.val.assume_init() }
     }
 }
 
@@ -1294,7 +1463,7 @@
     }
 
     fn ffi_len(&self) -> socklen_t {
-        mem::size_of::<c_int>() as socklen_t
+        mem::size_of_val(&self.val) as socklen_t
     }
 }
 
@@ -1313,7 +1482,7 @@
     }
 
     fn ffi_ptr(&mut self) -> *mut c_void {
-        self.val.as_mut_ptr() as *mut c_void
+        self.val.as_mut_ptr().cast()
     }
 
     fn ffi_len(&mut self) -> *mut socklen_t {
@@ -1326,7 +1495,7 @@
             mem::size_of::<c_int>(),
             "invalid getsockopt implementation"
         );
-        self.val.assume_init() as usize
+        unsafe { self.val.assume_init() as usize }
     }
 }
 
@@ -1345,7 +1514,7 @@
     }
 
     fn ffi_len(&self) -> socklen_t {
-        mem::size_of::<c_int>() as socklen_t
+        mem::size_of_val(&self.val) as socklen_t
     }
 }
 
@@ -1364,7 +1533,7 @@
     }
 
     fn ffi_ptr(&mut self) -> *mut c_void {
-        self.val.as_mut_ptr() as *mut c_void
+        self.val.as_mut_ptr().cast()
     }
 
     fn ffi_len(&mut self) -> *mut socklen_t {
@@ -1373,7 +1542,7 @@
 
     unsafe fn assume_init(self) -> OsString {
         let len = self.len as usize;
-        let mut v = self.val.assume_init();
+        let mut v = unsafe { self.val.assume_init() };
         OsStr::from_bytes(&v.as_mut()[0..len]).to_owned()
     }
 }
@@ -1391,7 +1560,7 @@
     }
 
     fn ffi_ptr(&self) -> *const c_void {
-        self.val.as_bytes().as_ptr() as *const c_void
+        self.val.as_bytes().as_ptr().cast()
     }
 
     fn ffi_len(&self) -> socklen_t {
@@ -1399,72 +1568,3 @@
     }
 }
 
-#[cfg(test)]
-mod test {
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    #[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_cred = getsockopt(&a, super::PeerCredentials).unwrap();
-        let b_cred = getsockopt(&b, super::PeerCredentials).unwrap();
-        assert_eq!(a_cred, b_cred);
-        assert_ne!(a_cred.pid(), 0);
-    }
-
-    #[test]
-    fn is_socket_type_unix() {
-        use super::super::*;
-
-        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);
-    }
-
-    #[test]
-    fn is_socket_type_dgram() {
-        use super::super::*;
-
-        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);
-    }
-
-    #[cfg(any(target_os = "freebsd", target_os = "linux"))]
-    #[test]
-    fn can_get_listen_on_tcp_socket() {
-        use super::super::*;
-
-        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();
-        let s_listening2 = getsockopt(&s, super::AcceptConn).unwrap();
-        assert!(s_listening2);
-    }
-}
diff --git a/src/sys/stat.rs b/src/sys/stat.rs
index 7e51c03..c5854ee 100644
--- a/src/sys/stat.rs
+++ b/src/sys/stat.rs
@@ -1,10 +1,6 @@
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))]
+#[cfg(any(apple_targets, target_os = "openbsd"))]
 pub use libc::c_uint;
-#[cfg(any(
-    target_os = "netbsd",
-    target_os = "freebsd",
-    target_os = "dragonfly"
-))]
+#[cfg(any(target_os = "netbsd", freebsdlike))]
 pub use libc::c_ulong;
 pub use libc::stat as FileStat;
 pub use libc::{dev_t, mode_t};
@@ -43,7 +39,7 @@
         S_IXUSR;
         /// Read write and execute for group.
         S_IRWXG;
-        /// Read fr group.
+        /// Read for group.
         S_IRGRP;
         /// Write for group.
         S_IWGRP;
@@ -65,26 +61,14 @@
     }
 }
 
-#[cfg(any(target_os = "macos", target_os = "ios", target_os = "openbsd"))]
+#[cfg(any(apple_targets, target_os = "openbsd"))]
 pub type type_of_file_flag = c_uint;
-#[cfg(any(
-    target_os = "netbsd",
-    target_os = "freebsd",
-    target_os = "dragonfly"
-))]
+#[cfg(any(freebsdlike, target_os = "netbsd"))]
 pub type type_of_file_flag = c_ulong;
 
-#[cfg(any(
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "freebsd",
-    target_os = "dragonfly",
-    target_os = "macos",
-    target_os = "ios"
-))]
+#[cfg(bsd)]
 libc_bitflags! {
     /// File flags.
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub struct FileFlag: type_of_file_flag {
         /// The file may only be appended to.
         SF_APPEND;
@@ -101,7 +85,7 @@
         #[cfg(any(target_os = "dragonfly"))]
         SF_NOHISTORY;
         /// The file may not be renamed or deleted.
-        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+        #[cfg(freebsdlike)]
         SF_NOUNLINK;
         /// Mask of superuser changeable flags
         SF_SETTABLE;
@@ -121,14 +105,13 @@
         #[cfg(any(target_os = "dragonfly"))]
         UF_CACHE;
         /// File is compressed at the file system level.
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         UF_COMPRESSED;
         /// The file may be hidden from directory listings at the application's
         /// discretion.
         #[cfg(any(
             target_os = "freebsd",
-            target_os = "macos",
-            target_os = "ios",
+            apple_targets,
         ))]
         UF_HIDDEN;
         /// The file may not be changed.
@@ -138,7 +121,7 @@
         #[cfg(any(target_os = "dragonfly"))]
         UF_NOHISTORY;
         /// The file may not be renamed or deleted.
-        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+        #[cfg(freebsdlike)]
         UF_NOUNLINK;
         /// The file is offline, or has the Windows and CIFS
         /// `FILE_ATTRIBUTE_OFFLINE` attribute.
@@ -162,7 +145,7 @@
         #[cfg(any(target_os = "freebsd"))]
         UF_SYSTEM;
         /// File renames and deletes are tracked.
-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        #[cfg(apple_targets)]
         UF_TRACKED;
         #[cfg(any(target_os = "dragonfly"))]
         UF_XLINK;
@@ -184,20 +167,15 @@
 }
 
 /// 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_attr(docsrs, doc(cfg(all())))]
+#[cfg(not(any(apple_targets, target_os = "redox", target_os = "haiku")))]
 pub fn mknodat<P: ?Sized + NixPath>(
-    dirfd: RawFd,
+    dirfd: Option<RawFd>,
     path: &P,
     kind: SFlag,
     perm: Mode,
     dev: dev_t,
 ) -> Result<()> {
+    let dirfd = at_rawfd(dirfd);
     let res = path.with_nix_path(|cstr| unsafe {
         libc::mknodat(
             dirfd,
@@ -211,19 +189,16 @@
 }
 
 #[cfg(target_os = "linux")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub const fn major(dev: dev_t) -> u64 {
     ((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff)
 }
 
 #[cfg(target_os = "linux")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub const fn minor(dev: dev_t) -> u64 {
     ((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff)
 }
 
 #[cfg(target_os = "linux")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub const fn makedev(major: u64, minor: u64) -> dev_t {
     ((major & 0xffff_f000) << 32)
         | ((major & 0x0000_0fff) << 8)
@@ -268,12 +243,12 @@
 }
 
 #[cfg(not(target_os = "redox"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub fn fstatat<P: ?Sized + NixPath>(
-    dirfd: RawFd,
+    dirfd: Option<RawFd>,
     pathname: &P,
     f: AtFlags,
 ) -> Result<FileStat> {
+    let dirfd = at_rawfd(dirfd);
     let mut dst = mem::MaybeUninit::uninit();
     let res = pathname.with_nix_path(|cstr| unsafe {
         libc::fstatat(
@@ -324,7 +299,6 @@
 ///
 /// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html).
 #[cfg(not(target_os = "redox"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub fn fchmodat<P: ?Sized + NixPath>(
     dirfd: Option<RawFd>,
     path: &P,
@@ -383,12 +357,10 @@
 #[cfg(any(
     target_os = "linux",
     target_os = "haiku",
-    target_os = "ios",
-    target_os = "macos",
+    apple_targets,
     target_os = "freebsd",
     target_os = "netbsd"
 ))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub fn lutimes<P: ?Sized + NixPath>(
     path: &P,
     atime: &TimeVal,
@@ -404,6 +376,9 @@
 
 /// Change the access and modification times of the file specified by a file descriptor.
 ///
+/// If you want to set the timestamp to now, use `TimeSpec::UTIME_NOW`. Use
+/// `TimeSpec::UTIME_OMIT` if you don't want to change it.
+///
 /// # References
 ///
 /// [futimens(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html).
@@ -436,11 +411,13 @@
 /// `utimes(path, times)`. The latter is a deprecated API so prefer using the
 /// former if the platforms you care about support it.
 ///
+/// If you want to set the timestamp to now, use `TimeSpec::UTIME_NOW`. Use
+/// `TimeSpec::UTIME_OMIT` if you don't want to change it.
+///
 /// # References
 ///
 /// [utimensat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html).
 #[cfg(not(target_os = "redox"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub fn utimensat<P: ?Sized + NixPath>(
     dirfd: Option<RawFd>,
     path: &P,
@@ -466,12 +443,12 @@
 }
 
 #[cfg(not(target_os = "redox"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub fn mkdirat<P: ?Sized + NixPath>(
-    fd: RawFd,
+    fd: Option<RawFd>,
     path: &P,
     mode: Mode,
 ) -> Result<()> {
+    let fd = at_rawfd(fd);
     let res = path.with_nix_path(|cstr| unsafe {
         libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t)
     })?;
diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs
index 5111df2..b2315f4 100644
--- a/src/sys/statfs.rs
+++ b/src/sys/statfs.rs
@@ -1,7 +1,7 @@
 //! Get filesystem statistics, non-portably
 //!
 //! See [`statvfs`](crate::sys::statvfs) for a portable alternative.
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
+#[cfg(not(linux_android))]
 use std::ffi::CStr;
 use std::fmt::{self, Debug};
 use std::mem;
@@ -9,16 +9,7 @@
 
 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"
-    )
-))]
+#[cfg(all(feature = "mount", bsd))]
 use crate::mount::MntFlags;
 #[cfg(target_os = "linux")]
 use crate::sys::statvfs::FsFlags;
@@ -26,15 +17,13 @@
 
 /// Identifies a mounted file system
 #[cfg(target_os = "android")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub type fsid_t = libc::__fsid_t;
 /// Identifies a mounted file system
 #[cfg(not(target_os = "android"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub type fsid_t = libc::fsid_t;
 
 cfg_if! {
-    if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] {
+    if #[cfg(any(linux_android, target_os = "fuchsia"))] {
         type type_of_statfs = libc::statfs64;
         const LIBC_FSTATFS: unsafe extern fn
             (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int
@@ -62,10 +51,12 @@
 type fs_type_t = u32;
 #[cfg(target_os = "android")]
 type fs_type_t = libc::c_ulong;
-#[cfg(all(target_os = "linux", target_arch = "s390x"))]
+#[cfg(all(target_os = "linux", target_arch = "s390x", not(target_env = "musl")))]
 type fs_type_t = libc::c_uint;
 #[cfg(all(target_os = "linux", target_env = "musl"))]
 type fs_type_t = libc::c_ulong;
+#[cfg(all(target_os = "linux", target_env = "ohos"))]
+type fs_type_t = libc::c_ulong;
 #[cfg(all(target_os = "linux", target_env = "uclibc"))]
 type fs_type_t = libc::c_int;
 #[cfg(all(
@@ -73,6 +64,7 @@
     not(any(
         target_arch = "s390x",
         target_env = "musl",
+        target_env = "ohos",
         target_env = "uclibc"
     ))
 ))]
@@ -84,6 +76,7 @@
     target_os = "android",
     all(target_os = "linux", target_arch = "s390x"),
     all(target_os = "linux", target_env = "musl"),
+    all(target_os = "linux", target_env = "ohos"),
     all(
         target_os = "linux",
         not(any(target_arch = "s390x", target_env = "musl"))
@@ -94,206 +87,203 @@
 
 // These constants are defined without documentation in the Linux headers, so we
 // can't very well document them here.
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const ADFS_SUPER_MAGIC: FsType =
     FsType(libc::ADFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const AFFS_SUPER_MAGIC: FsType =
     FsType(libc::AFFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_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"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const AUTOFS_SUPER_MAGIC: FsType =
     FsType(libc::AUTOFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_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"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const BTRFS_SUPER_MAGIC: FsType =
     FsType(libc::BTRFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const CGROUP2_SUPER_MAGIC: FsType =
     FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const CGROUP_SUPER_MAGIC: FsType =
     FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const CODA_SUPER_MAGIC: FsType =
     FsType(libc::CODA_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const DEBUGFS_MAGIC: FsType = FsType(libc::DEBUGFS_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const DEVPTS_SUPER_MAGIC: FsType =
     FsType(libc::DEVPTS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const ECRYPTFS_SUPER_MAGIC: FsType =
     FsType(libc::ECRYPTFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_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"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const EXT2_SUPER_MAGIC: FsType =
     FsType(libc::EXT2_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const EXT3_SUPER_MAGIC: FsType =
     FsType(libc::EXT3_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const EXT4_SUPER_MAGIC: FsType =
     FsType(libc::EXT4_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const F2FS_SUPER_MAGIC: FsType =
     FsType(libc::F2FS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const FUSE_SUPER_MAGIC: FsType =
     FsType(libc::FUSE_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const FUTEXFS_SUPER_MAGIC: FsType =
     FsType(libc::FUTEXFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const HOSTFS_SUPER_MAGIC: FsType =
     FsType(libc::HOSTFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const HPFS_SUPER_MAGIC: FsType =
     FsType(libc::HPFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_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"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const ISOFS_SUPER_MAGIC: FsType =
     FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const JFFS2_SUPER_MAGIC: FsType =
     FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const MINIX2_SUPER_MAGIC2: FsType =
     FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const MINIX2_SUPER_MAGIC: FsType =
     FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const MINIX3_SUPER_MAGIC: FsType =
     FsType(libc::MINIX3_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const MINIX_SUPER_MAGIC2: FsType =
     FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const MINIX_SUPER_MAGIC: FsType =
     FsType(libc::MINIX_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const MSDOS_SUPER_MAGIC: FsType =
     FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const NILFS_SUPER_MAGIC: FsType =
     FsType(libc::NILFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const OCFS2_SUPER_MAGIC: FsType =
     FsType(libc::OCFS2_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const OPENPROM_SUPER_MAGIC: FsType =
     FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const OVERLAYFS_SUPER_MAGIC: FsType =
     FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const PROC_SUPER_MAGIC: FsType =
     FsType(libc::PROC_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const QNX4_SUPER_MAGIC: FsType =
     FsType(libc::QNX4_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const QNX6_SUPER_MAGIC: FsType =
     FsType(libc::QNX6_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const RDTGROUP_SUPER_MAGIC: FsType =
     FsType(libc::RDTGROUP_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const REISERFS_SUPER_MAGIC: FsType =
     FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const SECURITYFS_MAGIC: FsType =
     FsType(libc::SECURITYFS_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const SELINUX_MAGIC: FsType = FsType(libc::SELINUX_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const SMACK_MAGIC: FsType = FsType(libc::SMACK_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const SYSFS_MAGIC: FsType = FsType(libc::SYSFS_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const TRACEFS_MAGIC: FsType = FsType(libc::TRACEFS_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const UDF_SUPER_MAGIC: FsType = FsType(libc::UDF_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const USBDEVICE_SUPER_MAGIC: FsType =
     FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const XENFS_SUPER_MAGIC: FsType =
     FsType(libc::XENFS_SUPER_MAGIC as fs_type_t);
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[allow(missing_docs)]
 pub const NSFS_MAGIC: FsType = FsType(libc::NSFS_MAGIC as fs_type_t);
-#[cfg(all(
-    any(target_os = "linux", target_os = "android"),
-    not(target_env = "musl")
-))]
+#[cfg(all(linux_android, not(target_env = "musl"), not(target_env = "ohos")))]
 #[allow(missing_docs)]
 pub const XFS_SUPER_MAGIC: FsType = FsType(libc::XFS_SUPER_MAGIC as fs_type_t);
 
@@ -302,39 +292,33 @@
     #[cfg(not(any(
         target_os = "openbsd",
         target_os = "dragonfly",
-        target_os = "ios",
-        target_os = "macos"
+        apple_targets,
     )))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn filesystem_type(&self) -> FsType {
         FsType(self.0.f_type)
     }
 
     /// Magic code defining system type
-    #[cfg(not(any(target_os = "linux", target_os = "android")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(not(linux_android))]
     pub fn filesystem_type_name(&self) -> &str {
         let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) };
         c_str.to_str().unwrap()
     }
 
     /// Optimal transfer block size
-    #[cfg(any(target_os = "ios", target_os = "macos"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(apple_targets)]
     pub fn optimal_transfer_size(&self) -> i32 {
         self.0.f_iosize
     }
 
     /// Optimal transfer block size
     #[cfg(target_os = "openbsd")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn optimal_transfer_size(&self) -> u32 {
         self.0.f_iosize
     }
 
     /// Optimal transfer block size
-    #[cfg(all(target_os = "linux", target_arch = "s390x"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(all(target_os = "linux", target_arch = "s390x", not(target_env = "musl")))]
     pub fn optimal_transfer_size(&self) -> u32 {
         self.0.f_bsize
     }
@@ -342,9 +326,9 @@
     /// Optimal transfer block size
     #[cfg(any(
         target_os = "android",
-        all(target_os = "linux", target_env = "musl")
+        all(target_os = "linux", target_env = "musl"),
+        all(target_os = "linux", target_env = "ohos")
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn optimal_transfer_size(&self) -> libc::c_ulong {
         self.0.f_bsize
     }
@@ -355,46 +339,41 @@
         not(any(
             target_arch = "s390x",
             target_env = "musl",
+            target_env = "ohos",
             target_env = "uclibc"
         ))
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn optimal_transfer_size(&self) -> libc::__fsword_t {
         self.0.f_bsize
     }
 
     /// Optimal transfer block size
     #[cfg(all(target_os = "linux", target_env = "uclibc"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn optimal_transfer_size(&self) -> libc::c_int {
         self.0.f_bsize
     }
 
     /// Optimal transfer block size
     #[cfg(target_os = "dragonfly")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn optimal_transfer_size(&self) -> libc::c_long {
         self.0.f_iosize
     }
 
     /// Optimal transfer block size
     #[cfg(target_os = "freebsd")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn optimal_transfer_size(&self) -> u64 {
         self.0.f_iosize
     }
 
     /// Size of a block
-    #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(apple_targets, target_os = "openbsd"))]
     pub fn block_size(&self) -> u32 {
         self.0.f_bsize
     }
 
     /// Size of a block
     // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
-    #[cfg(all(target_os = "linux", target_arch = "s390x"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(all(target_os = "linux", target_arch = "s390x", not(target_env = "musl")))]
     pub fn block_size(&self) -> u32 {
         self.0.f_bsize
     }
@@ -402,7 +381,13 @@
     /// Size of a block
     // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
     #[cfg(all(target_os = "linux", target_env = "musl"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    pub fn block_size(&self) -> libc::c_ulong {
+        self.0.f_bsize
+    }
+
+    /// Size of a block
+    // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
+    #[cfg(all(target_os = "linux", target_env = "ohos"))]
     pub fn block_size(&self) -> libc::c_ulong {
         self.0.f_bsize
     }
@@ -410,7 +395,6 @@
     /// Size of a block
     // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
     #[cfg(all(target_os = "linux", target_env = "uclibc"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn block_size(&self) -> libc::c_int {
         self.0.f_bsize
     }
@@ -422,47 +406,34 @@
         not(any(
             target_arch = "s390x",
             target_env = "musl",
+            target_env = "ohos",
             target_env = "uclibc"
         ))
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn block_size(&self) -> libc::__fsword_t {
         self.0.f_bsize
     }
 
     /// Size of a block
     #[cfg(target_os = "freebsd")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn block_size(&self) -> u64 {
         self.0.f_bsize
     }
 
     /// Size of a block
     #[cfg(target_os = "android")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn block_size(&self) -> libc::c_ulong {
         self.0.f_bsize
     }
 
     /// Size of a block
     #[cfg(target_os = "dragonfly")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn block_size(&self) -> libc::c_long {
         self.0.f_bsize
     }
 
     /// 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())))]
+    #[cfg(all(feature = "mount", bsd))]
     #[allow(clippy::unnecessary_cast)] // Not unnecessary on all arches
     pub fn flags(&self) -> MntFlags {
         MntFlags::from_bits_truncate(self.0.f_flags as i32)
@@ -472,35 +443,30 @@
     // 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())))]
     pub fn maximum_name_length(&self) -> u32 {
         self.0.f_namemax
     }
 
     /// Maximum length of filenames
-    #[cfg(all(target_os = "linux", target_arch = "s390x"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(all(target_os = "linux", target_arch = "s390x", not(target_env = "musl")))]
     pub fn maximum_name_length(&self) -> u32 {
         self.0.f_namelen
     }
 
     /// Maximum length of filenames
     #[cfg(all(target_os = "linux", target_env = "musl"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn maximum_name_length(&self) -> libc::c_ulong {
         self.0.f_namelen
     }
 
     /// Maximum length of filenames
     #[cfg(all(target_os = "linux", target_env = "uclibc"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn maximum_name_length(&self) -> libc::c_int {
         self.0.f_namelen
     }
@@ -511,173 +477,141 @@
         not(any(
             target_arch = "s390x",
             target_env = "musl",
+            target_env = "ohos",
             target_env = "uclibc"
         ))
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn maximum_name_length(&self) -> libc::__fsword_t {
         self.0.f_namelen
     }
 
     /// Maximum length of filenames
     #[cfg(target_os = "android")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn maximum_name_length(&self) -> libc::c_ulong {
         self.0.f_namelen
     }
 
     /// Total data blocks in filesystem
     #[cfg(any(
-        target_os = "ios",
-        target_os = "macos",
-        target_os = "android",
+        apple_targets,
+        linux_android,
         target_os = "freebsd",
         target_os = "fuchsia",
         target_os = "openbsd",
-        target_os = "linux",
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn blocks(&self) -> u64 {
         self.0.f_blocks
     }
 
     /// Total data blocks in filesystem
     #[cfg(target_os = "dragonfly")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn blocks(&self) -> libc::c_long {
         self.0.f_blocks
     }
 
     /// Total data blocks in filesystem
     #[cfg(target_os = "emscripten")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn blocks(&self) -> u32 {
         self.0.f_blocks
     }
 
     /// Free blocks in filesystem
     #[cfg(any(
-        target_os = "ios",
-        target_os = "macos",
-        target_os = "android",
+        apple_targets,
+        linux_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 {
         self.0.f_bfree
     }
 
     /// Free blocks in filesystem
     #[cfg(target_os = "dragonfly")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn blocks_free(&self) -> libc::c_long {
         self.0.f_bfree
     }
 
     /// Free blocks in filesystem
     #[cfg(target_os = "emscripten")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn blocks_free(&self) -> u32 {
         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())))]
+    #[cfg(any(apple_targets, linux_android, target_os = "fuchsia"))]
     pub fn blocks_available(&self) -> u64 {
         self.0.f_bavail
     }
 
     /// Free blocks available to unprivileged user
     #[cfg(target_os = "dragonfly")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn blocks_available(&self) -> libc::c_long {
         self.0.f_bavail
     }
 
     /// Free blocks available to unprivileged user
     #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn blocks_available(&self) -> i64 {
         self.0.f_bavail
     }
 
     /// Free blocks available to unprivileged user
     #[cfg(target_os = "emscripten")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn blocks_available(&self) -> u32 {
         self.0.f_bavail
     }
 
     /// Total file nodes in filesystem
     #[cfg(any(
-        target_os = "ios",
-        target_os = "macos",
-        target_os = "android",
+        apple_targets,
+        linux_android,
         target_os = "freebsd",
         target_os = "fuchsia",
         target_os = "openbsd",
-        target_os = "linux",
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn files(&self) -> u64 {
         self.0.f_files
     }
 
     /// Total file nodes in filesystem
     #[cfg(target_os = "dragonfly")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn files(&self) -> libc::c_long {
         self.0.f_files
     }
 
     /// Total file nodes in filesystem
     #[cfg(target_os = "emscripten")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn files(&self) -> u32 {
         self.0.f_files
     }
 
     /// Free file nodes in filesystem
     #[cfg(any(
-        target_os = "ios",
-        target_os = "macos",
-        target_os = "android",
+        apple_targets,
+        linux_android,
         target_os = "fuchsia",
         target_os = "openbsd",
-        target_os = "linux",
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn files_free(&self) -> u64 {
         self.0.f_ffree
     }
 
     /// Free file nodes in filesystem
     #[cfg(target_os = "dragonfly")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn files_free(&self) -> libc::c_long {
         self.0.f_ffree
     }
 
     /// Free file nodes in filesystem
     #[cfg(target_os = "freebsd")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn files_free(&self) -> i64 {
         self.0.f_ffree
     }
 
     /// Free file nodes in filesystem
     #[cfg(target_os = "emscripten")]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn files_free(&self) -> u32 {
         self.0.f_ffree
     }
@@ -699,16 +633,7 @@
         ds.field("files", &self.files());
         ds.field("files_free", &self.files_free());
         ds.field("filesystem_id", &self.filesystem_id());
-        #[cfg(all(
-            feature = "mount",
-            any(
-                target_os = "dragonfly",
-                target_os = "freebsd",
-                target_os = "macos",
-                target_os = "netbsd",
-                target_os = "openbsd"
-            )
-        ))]
+        #[cfg(all(feature = "mount", bsd))]
         ds.field("flags", &self.flags());
         ds.finish()
     }
@@ -747,107 +672,3 @@
             .map(|_| Statfs(stat.assume_init()))
     }
 }
-
-#[cfg(test)]
-mod test {
-    use std::fs::File;
-
-    use crate::sys::statfs::*;
-    use crate::sys::statvfs::*;
-    use std::path::Path;
-
-    #[test]
-    fn statfs_call() {
-        check_statfs("/tmp");
-        check_statfs("/dev");
-        check_statfs("/run");
-        check_statfs("/");
-    }
-
-    #[test]
-    fn fstatfs_call() {
-        check_fstatfs("/tmp");
-        check_fstatfs("/dev");
-        check_fstatfs("/run");
-        check_fstatfs("/");
-    }
-
-    fn check_fstatfs(path: &str) {
-        if !Path::new(path).exists() {
-            return;
-        }
-        let vfs = statvfs(path.as_bytes()).unwrap();
-        let file = File::open(path).unwrap();
-        let fs = fstatfs(&file).unwrap();
-        assert_fs_equals(fs, vfs);
-    }
-
-    fn check_statfs(path: &str) {
-        if !Path::new(path).exists() {
-            return;
-        }
-        let vfs = statvfs(path.as_bytes()).unwrap();
-        let fs = statfs(path.as_bytes()).unwrap();
-        assert_fs_equals(fs, vfs);
-    }
-
-    // The cast is not unnecessary on all platforms.
-    #[allow(clippy::unnecessary_cast)]
-    fn assert_fs_equals(fs: Statfs, vfs: Statvfs) {
-        assert_eq!(fs.files() as u64, vfs.files() as u64);
-        assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
-        assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
-    }
-
-    // This test is ignored because files_free/blocks_free can change after statvfs call and before
-    // statfs call.
-    #[test]
-    #[ignore]
-    fn statfs_call_strict() {
-        check_statfs_strict("/tmp");
-        check_statfs_strict("/dev");
-        check_statfs_strict("/run");
-        check_statfs_strict("/");
-    }
-
-    // This test is ignored because files_free/blocks_free can change after statvfs call and before
-    // fstatfs call.
-    #[test]
-    #[ignore]
-    fn fstatfs_call_strict() {
-        check_fstatfs_strict("/tmp");
-        check_fstatfs_strict("/dev");
-        check_fstatfs_strict("/run");
-        check_fstatfs_strict("/");
-    }
-
-    fn check_fstatfs_strict(path: &str) {
-        if !Path::new(path).exists() {
-            return;
-        }
-        let vfs = statvfs(path.as_bytes());
-        let file = File::open(path).unwrap();
-        let fs = fstatfs(&file);
-        assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
-    }
-
-    fn check_statfs_strict(path: &str) {
-        if !Path::new(path).exists() {
-            return;
-        }
-        let vfs = statvfs(path.as_bytes());
-        let fs = statfs(path.as_bytes());
-        assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
-    }
-
-    // The cast is not unnecessary on all platforms.
-    #[allow(clippy::unnecessary_cast)]
-    fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) {
-        assert_eq!(fs.files_free() as u64, vfs.files_free() as u64);
-        assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64);
-        assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64);
-        assert_eq!(fs.files() as u64, vfs.files() as u64);
-        assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
-        assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
-    }
-}
diff --git a/src/sys/statvfs.rs b/src/sys/statvfs.rs
index 35424e5..db1abdd 100644
--- a/src/sys/statvfs.rs
+++ b/src/sys/statvfs.rs
@@ -21,44 +21,34 @@
         #[cfg(not(target_os = "haiku"))]
         ST_NOSUID;
         /// Do not interpret character or block-special devices
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         ST_NODEV;
         /// Do not allow execution of binaries on the filesystem
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         ST_NOEXEC;
         /// All IO should be done synchronously
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         ST_SYNCHRONOUS;
         /// Allow mandatory locks on the filesystem
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         ST_MANDLOCK;
         /// Write on file/directory/symlink
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         ST_WRITE;
         /// Append-only file
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         ST_APPEND;
         /// Immutable file
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         ST_IMMUTABLE;
         /// Do not update access times on files
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         ST_NOATIME;
         /// Do not update access times on files
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         ST_NODIRATIME;
         /// Update access time relative to modify/change time
-        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"))))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"), not(target_env = "ohos"))))]
         ST_RELATIME;
     }
 );
@@ -114,13 +104,18 @@
     }
 
     /// Get the file system id
+    #[cfg(not(target_os = "hurd"))]
     pub fn filesystem_id(&self) -> c_ulong {
         self.0.f_fsid
     }
+    /// Get the file system id
+    #[cfg(target_os = "hurd")]
+    pub fn filesystem_id(&self) -> u64 {
+        self.0.f_fsid
+    }
 
     /// Get the mount flags
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn flags(&self) -> FsFlags {
         FsFlags::from_bits_truncate(self.0.f_flag)
     }
@@ -153,20 +148,3 @@
             .map(|_| Statvfs(stat.assume_init()))
     }
 }
-
-#[cfg(test)]
-mod test {
-    use crate::sys::statvfs::*;
-    use std::fs::File;
-
-    #[test]
-    fn statvfs_call() {
-        statvfs(&b"/"[..]).unwrap();
-    }
-
-    #[test]
-    fn fstatvfs_call() {
-        let root = File::open("/").unwrap();
-        fstatvfs(&root).unwrap();
-    }
-}
diff --git a/src/sys/termios.rs b/src/sys/termios.rs
index 74c5fc5..e006c2f 100644
--- a/src/sys/termios.rs
+++ b/src/sys/termios.rs
@@ -85,28 +85,8 @@
 //!
 //! 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(bsd, doc = " ```rust,ignore")]
+#![cfg_attr(not(bsd), doc = " ```rust")]
 //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
 //! # fn main() {
 //! # let mut t: Termios = unsafe { std::mem::zeroed() };
@@ -118,28 +98,8 @@
 //!
 //! 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(bsd, doc = " ```rust")]
+#![cfg_attr(not(bsd), doc = " ```rust,ignore")]
 //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
 //! # fn main() {
 //! # let mut t: Termios = unsafe { std::mem::zeroed() };
@@ -151,28 +111,8 @@
 //!
 //! 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(bsd, doc = " ```rust")]
+#![cfg_attr(not(bsd), doc = " ```rust,ignore")]
 //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios};
 //! # fn main() {
 //! # let mut t: Termios = unsafe { std::mem::zeroed() };
@@ -185,28 +125,8 @@
 //! 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(bsd, doc = " ```rust")]
+#![cfg_attr(not(bsd), doc = " ```rust,ignore")]
 //! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios};
 //! # fn main() {
 //! # let mut t: Termios = unsafe { std::mem::zeroed() };
@@ -246,7 +166,7 @@
     /// Control characters (see `termios.c_cc` documentation)
     pub control_chars: [libc::cc_t; NCCS],
     /// Line discipline (see `termios.c_line` documentation)
-    #[cfg(any(target_os = "linux", target_os = "android",))]
+    #[cfg(linux_android)]
     pub line_discipline: libc::cc_t,
     /// Line discipline (see `termios.c_line` documentation)
     #[cfg(target_os = "haiku")]
@@ -266,11 +186,7 @@
             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",
-            ))]
+            #[cfg(any(linux_android, target_os = "haiku"))]
             {
                 termios.c_line = self.line_discipline;
             }
@@ -292,11 +208,7 @@
             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",
-            ))]
+            #[cfg(any(linux_android, target_os = "haiku"))]
             {
                 termios.c_line = self.line_discipline;
             }
@@ -307,16 +219,12 @@
     /// Updates the wrapper values from the internal `libc::termios` data structure.
     pub(crate) fn update_wrapper(&mut self) {
         let termios = *self.inner.borrow_mut();
-        self.input_flags = InputFlags::from_bits_retain(termios.c_iflag);
-        self.output_flags = OutputFlags::from_bits_retain(termios.c_oflag);
+        self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag);
+        self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag);
         self.control_flags = ControlFlags::from_bits_retain(termios.c_cflag);
-        self.local_flags = LocalFlags::from_bits_retain(termios.c_lflag);
+        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",
-        ))]
+        #[cfg(any(linux_android, target_os = "haiku"))]
         {
             self.line_discipline = termios.c_line;
         }
@@ -327,16 +235,12 @@
     fn from(termios: libc::termios) -> Self {
         Termios {
             inner: RefCell::new(termios),
-            input_flags: InputFlags::from_bits_retain(termios.c_iflag),
-            output_flags: OutputFlags::from_bits_retain(termios.c_oflag),
-            control_flags: ControlFlags::from_bits_retain(termios.c_cflag),
-            local_flags: LocalFlags::from_bits_retain(termios.c_lflag),
+            input_flags: InputFlags::from_bits_truncate(termios.c_iflag),
+            output_flags: OutputFlags::from_bits_truncate(termios.c_oflag),
+            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",
-            ))]
+            #[cfg(any(linux_android, target_os = "haiku"))]
             line_discipline: termios.c_line,
         }
     }
@@ -356,8 +260,13 @@
     ///
     /// B0 is special and will disable the port.
     #[cfg_attr(target_os = "haiku", repr(u8))]
-    #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))]
-    #[cfg_attr(all(not(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64")), not(target_os = "haiku")), repr(u32))]
+    #[cfg_attr(target_os = "hurd", repr(i32))]
+    #[cfg_attr(all(apple_targets, target_pointer_width = "64"), repr(u64))]
+    #[cfg_attr(all(
+        not(all(apple_targets, target_pointer_width = "64")),
+        not(target_os = "haiku"),
+        not(target_os = "hurd")
+        ), repr(u32))]
     #[non_exhaustive]
     pub enum BaudRate {
         B0,
@@ -373,110 +282,62 @@
         B1800,
         B2400,
         B4800,
-        #[cfg(any(target_os = "dragonfly",
-                target_os = "freebsd",
-                target_os = "macos",
-                target_os = "netbsd",
-                target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         B7200,
         B9600,
-        #[cfg(any(target_os = "dragonfly",
-                target_os = "freebsd",
-                target_os = "macos",
-                target_os = "netbsd",
-                target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         B14400,
         B19200,
-        #[cfg(any(target_os = "dragonfly",
-                target_os = "freebsd",
-                target_os = "macos",
-                target_os = "netbsd",
-                target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         B28800,
         B38400,
         #[cfg(not(target_os = "aix"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         B57600,
-        #[cfg(any(target_os = "dragonfly",
-                target_os = "freebsd",
-                target_os = "macos",
-                target_os = "netbsd",
-                target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         B76800,
         #[cfg(not(target_os = "aix"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         B115200,
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(solarish)]
         B153600,
         #[cfg(not(target_os = "aix"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         B230400,
-        #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(solarish)]
         B307200,
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
+                  solarish,
                   target_os = "freebsd",
-                  target_os = "illumos",
-                  target_os = "linux",
-                  target_os = "netbsd",
-                  target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  target_os = "netbsd"))]
         B460800,
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         B500000,
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         B576000,
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
+                  solarish,
                   target_os = "freebsd",
-                  target_os = "illumos",
-                  target_os = "linux",
-                  target_os = "netbsd",
-                  target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  target_os = "netbsd"))]
         B921600,
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         B1000000,
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         B1152000,
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         B1500000,
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         B2000000,
         #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         B2500000,
         #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         B3000000,
         #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         B3500000,
         #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         B4000000,
     }
     impl TryFrom<libc::speed_t>
 }
 
-#[cfg(any(
-    target_os = "freebsd",
-    target_os = "dragonfly",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd"
-))]
+#[cfg(bsd)]
 impl From<BaudRate> for u32 {
     fn from(b: BaudRate) -> u32 {
         b as u32
@@ -542,80 +403,57 @@
 }
 
 // TODO: Make this usable directly as a slice index.
-#[cfg(not(target_os = "haiku"))]
 libc_enum! {
     /// Indices into the `termios.c_cc` array for special characters.
     #[repr(usize)]
     #[non_exhaustive]
     pub enum SpecialCharacterIndices {
-        #[cfg(not(target_os = "aix"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
         VDISCARD,
-        #[cfg(any(target_os = "dragonfly",
-                target_os = "freebsd",
-                target_os = "illumos",
-                target_os = "macos",
-                target_os = "netbsd",
-                target_os = "openbsd",
-                target_os = "aix",
-                target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(bsd,
+                solarish,
+                target_os = "aix"))]
         VDSUSP,
         VEOF,
         VEOL,
         VEOL2,
         VERASE,
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "illumos",
-                  target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(freebsdlike, solarish))]
         VERASE2,
         VINTR,
         VKILL,
+        #[cfg(not(target_os = "haiku"))]
         VLNEXT,
         #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"),
-                target_os = "illumos", target_os = "solaris", target_os = "aix")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                solarish, target_os = "aix", target_os = "haiku")))]
         VMIN,
         VQUIT,
+        #[cfg(not(target_os = "haiku"))]
         VREPRINT,
         VSTART,
-        #[cfg(any(target_os = "dragonfly",
-                target_os = "freebsd",
-                target_os = "illumos",
-                target_os = "macos",
-                target_os = "netbsd",
-                target_os = "openbsd",
-                target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(bsd, solarish))]
         VSTATUS,
         VSTOP,
         VSUSP,
         #[cfg(target_os = "linux")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         VSWTC,
-        #[cfg(any(target_os = "haiku", target_os = "illumos", target_os = "solaris"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(solarish, target_os = "haiku"))]
         VSWTCH,
         #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"),
-                target_os = "illumos", target_os = "solaris", target_os = "aix")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                solarish, target_os = "aix", target_os = "haiku")))]
         VTIME,
-        #[cfg(not(target_os = "aix"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
         VWERASE,
         #[cfg(target_os = "dragonfly")]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         VCHECKPT,
     }
 }
 
 #[cfg(any(
     all(target_os = "linux", target_arch = "sparc64"),
-    target_os = "illumos",
-    target_os = "solaris",
+    solarish,
     target_os = "aix",
+    target_os = "haiku",
 ))]
 impl SpecialCharacterIndices {
     pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF;
@@ -623,17 +461,7 @@
 }
 
 pub use libc::NCCS;
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "aix",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd"
-))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+#[cfg(any(linux_android, target_os = "aix", bsd))]
 pub use libc::_POSIX_VDISABLE;
 
 libc_bitflags! {
@@ -651,13 +479,10 @@
         IXON;
         IXOFF;
         #[cfg(not(target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         IXANY;
         #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         IMAXBEL;
-        #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, apple_targets))]
         IUTF8;
     }
 }
@@ -666,209 +491,119 @@
     /// Flags for configuring the output mode of a terminal
     pub struct OutputFlags: tcflag_t {
         OPOST;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "linux",
                   target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         OLCUC;
         ONLCR;
         OCRNL as tcflag_t;
         ONOCR as tcflag_t;
         ONLRET as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
-        OFILL as tcflag_t;
-        #[cfg(any(target_os = "android",
-                  target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         OFDEL as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         NL0 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         NL1 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         CR0 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         CR1 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         CR2 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         CR3 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "freebsd",
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         TAB0 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         TAB1 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         TAB2 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "freebsd",
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         TAB3 as tcflag_t;
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         XTABS;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         BS0 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         BS1 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         VT0 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         VT1 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         FF0 as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         FF1 as tcflag_t;
-        #[cfg(any(target_os = "freebsd",
-                  target_os = "dragonfly",
-                  target_os = "ios",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         OXTABS;
-        #[cfg(any(target_os = "freebsd",
-                  target_os = "dragonfly",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         ONOEOT as tcflag_t;
 
         // Bitmasks for use with OutputFlags to select specific settings
         // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110
         // is resolved.
 
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         CRDLY as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "freebsd",
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         TABDLY as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         BSDLY as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         VTDLY as tcflag_t;
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
-                  target_os = "macos"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+                  apple_targets))]
         FFDLY as tcflag_t;
     }
 }
@@ -876,13 +611,7 @@
 libc_bitflags! {
     /// Flags for setting the control mode of a terminal
     pub struct ControlFlags: tcflag_t {
-        #[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())))]
+        #[cfg(bsd)]
         CIGNORE;
         CS5;
         CS6;
@@ -895,54 +624,30 @@
         HUPCL;
         CLOCAL;
         #[cfg(not(any(target_os = "redox", target_os = "aix")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         CRTSCTS;
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         CBAUD;
         #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         CMSPAR;
         #[cfg(any(target_os = "android",
                   all(target_os = "linux",
                       not(any(target_arch = "powerpc", target_arch = "powerpc64")))))]
         CIBAUD;
-        #[cfg(any(target_os = "android", target_os = "linux"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(linux_android)]
         CBAUDEX;
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         MDMBUF;
-        #[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(netbsdlike)]
         CHWFLOW;
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(freebsdlike, netbsdlike))]
         CCTS_OFLOW;
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(freebsdlike, netbsdlike))]
         CRTS_IFLOW;
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         CDTR_IFLOW;
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         CDSR_OFLOW;
-        #[cfg(any(target_os = "dragonfly",
-                  target_os = "freebsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(freebsdlike)]
         CCAR_OFLOW;
 
         // Bitmasks for use with ControlFlags to select specific settings
@@ -957,58 +662,35 @@
     /// Flags for setting any local modes
     pub struct LocalFlags: tcflag_t {
         #[cfg(not(target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         ECHOKE;
         ECHOE;
         ECHOK;
         ECHO;
         ECHONL;
         #[cfg(not(target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         ECHOPRT;
         #[cfg(not(target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         ECHOCTL;
         ISIG;
         ICANON;
-        #[cfg(any(target_os = "freebsd",
-                  target_os = "dragonfly",
-                  target_os = "ios",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         ALTWERASE;
         IEXTEN;
         #[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "aix")))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         EXTPROC;
         TOSTOP;
         #[cfg(not(target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         FLUSHO;
-        #[cfg(any(target_os = "freebsd",
-                  target_os = "dragonfly",
-                  target_os = "ios",
-                  target_os = "macos",
-                  target_os = "netbsd",
-                  target_os = "openbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(bsd)]
         NOKERNINFO;
         #[cfg(not(target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         PENDIN;
         NOFLSH;
     }
 }
 
 cfg_if! {
-    if #[cfg(any(target_os = "freebsd",
-                 target_os = "dragonfly",
-                 target_os = "ios",
-                 target_os = "macos",
-                 target_os = "netbsd",
-                 target_os = "openbsd"))] {
+    if #[cfg(bsd)] {
         /// Get input baud rate (see
         /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
         ///
@@ -1141,7 +823,6 @@
 ///
 /// Note that this is a non-standard function, available on FreeBSD.
 #[cfg(target_os = "freebsd")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub fn cfmakesane(termios: &mut Termios) {
     let inner_termios = unsafe { termios.get_libc_termios_mut() };
     unsafe {
@@ -1242,18 +923,3 @@
     Errno::result(res).map(Pid::from_raw)
 }
 }
-
-#[cfg(test)]
-mod test {
-    use super::*;
-    use std::convert::TryFrom;
-
-    #[test]
-    fn try_from() {
-        assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0));
-        #[cfg(not(target_os = "haiku"))]
-        BaudRate::try_from(999999999).expect_err("assertion failed");
-        #[cfg(target_os = "haiku")]
-        BaudRate::try_from(99).expect_err("assertion failed");
-    }
-}
diff --git a/src/sys/time.rs b/src/sys/time.rs
index a0160e2..af436ca 100644
--- a/src/sys/time.rs
+++ b/src/sys/time.rs
@@ -2,7 +2,6 @@
 // https://github.com/rust-lang/libc/issues/1848
 pub use libc::{suseconds_t, time_t};
 use libc::{timespec, timeval};
-use std::convert::From;
 use std::time::Duration;
 use std::{cmp, fmt, ops};
 
@@ -18,7 +17,7 @@
     all(
         any(
             target_os = "freebsd",
-            target_os = "illumos",
+            solarish,
             target_os = "linux",
             target_os = "netbsd"
         ),
@@ -88,7 +87,7 @@
         Interval(TimeSpec),
     }
 
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     bitflags! {
         /// Flags that are used for arming the timer.
         #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
@@ -97,12 +96,7 @@
             const TFD_TIMER_CANCEL_ON_SET = libc::TFD_TIMER_CANCEL_ON_SET;
         }
     }
-    #[cfg(any(
-        target_os = "freebsd",
-        target_os = "netbsd",
-        target_os = "dragonfly",
-        target_os = "illumos"
-    ))]
+    #[cfg(any(freebsdlike, target_os = "netbsd", solarish))]
     bitflags! {
         /// Flags that are used for arming the timer.
         #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
@@ -334,6 +328,17 @@
 }
 
 impl TimeSpec {
+    /// Leave the timestamp unchanged.
+    #[cfg(not(target_os = "redox"))]
+    // At the time of writing this PR, redox does not support this feature
+    pub const UTIME_OMIT: TimeSpec =
+        TimeSpec::new(0, libc::UTIME_OMIT as timespec_tv_nsec_t);
+    /// Update the timestamp to `Now`
+    // At the time of writing this PR, redox does not support this feature
+    #[cfg(not(target_os = "redox"))]
+    pub const UTIME_NOW: TimeSpec =
+        TimeSpec::new(0, libc::UTIME_NOW as timespec_tv_nsec_t);
+
     /// 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 {
@@ -712,101 +717,3 @@
 fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
     (this / other, this % other)
 }
-
-#[cfg(test)]
-mod test {
-    use super::{TimeSpec, TimeVal, TimeValLike};
-    use std::time::Duration;
-
-    #[test]
-    pub fn test_timespec() {
-        assert_ne!(TimeSpec::seconds(1), TimeSpec::zero());
-        assert_eq!(
-            TimeSpec::seconds(1) + TimeSpec::seconds(2),
-            TimeSpec::seconds(3)
-        );
-        assert_eq!(
-            TimeSpec::minutes(3) + TimeSpec::seconds(2),
-            TimeSpec::seconds(182)
-        );
-    }
-
-    #[test]
-    pub fn test_timespec_from() {
-        let duration = Duration::new(123, 123_456_789);
-        let timespec = TimeSpec::nanoseconds(123_123_456_789);
-
-        assert_eq!(TimeSpec::from(duration), timespec);
-        assert_eq!(Duration::from(timespec), duration);
-    }
-
-    #[test]
-    pub fn test_timespec_neg() {
-        let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
-        let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123);
-
-        assert_eq!(a, -b);
-    }
-
-    #[test]
-    pub fn test_timespec_ord() {
-        assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000));
-        assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001));
-        assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999));
-        assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999));
-        assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001));
-    }
-
-    #[test]
-    pub fn test_timespec_fmt() {
-        assert_eq!(TimeSpec::zero().to_string(), "0 seconds");
-        assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds");
-        assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds");
-        assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds");
-        assert_eq!(
-            TimeSpec::nanoseconds(42).to_string(),
-            "0.000000042 seconds"
-        );
-        assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds");
-    }
-
-    #[test]
-    pub fn test_timeval() {
-        assert_ne!(TimeVal::seconds(1), TimeVal::zero());
-        assert_eq!(
-            TimeVal::seconds(1) + TimeVal::seconds(2),
-            TimeVal::seconds(3)
-        );
-        assert_eq!(
-            TimeVal::minutes(3) + TimeVal::seconds(2),
-            TimeVal::seconds(182)
-        );
-    }
-
-    #[test]
-    pub fn test_timeval_ord() {
-        assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000));
-        assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001));
-        assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999));
-        assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999));
-        assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001));
-    }
-
-    #[test]
-    pub fn test_timeval_neg() {
-        let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
-        let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);
-
-        assert_eq!(a, -b);
-    }
-
-    #[test]
-    pub fn test_timeval_fmt() {
-        assert_eq!(TimeVal::zero().to_string(), "0 seconds");
-        assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
-        assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
-        assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
-        assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds");
-        assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
-    }
-}
diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs
index c4337c9..68b06d6 100644
--- a/src/sys/timerfd.rs
+++ b/src/sys/timerfd.rs
@@ -53,7 +53,7 @@
 impl FromRawFd for TimerFd {
     unsafe fn from_raw_fd(fd: RawFd) -> Self {
         TimerFd {
-            fd: OwnedFd::from_raw_fd(fd),
+            fd: unsafe { OwnedFd::from_raw_fd(fd) },
         }
     }
 }
diff --git a/src/sys/uio.rs b/src/sys/uio.rs
index eaf61ed..cdf380d 100644
--- a/src/sys/uio.rs
+++ b/src/sys/uio.rs
@@ -2,7 +2,7 @@
 
 use crate::errno::Errno;
 use crate::Result;
-use libc::{self, c_int, c_void, off_t, size_t};
+use libc::{self, c_int, off_t, size_t};
 use std::io::{IoSlice, IoSliceMut};
 use std::os::unix::io::{AsFd, AsRawFd};
 
@@ -18,7 +18,11 @@
     //
     // Because it is ABI compatible, a pointer cast here is valid
     let res = unsafe {
-        libc::writev(fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len() as c_int)
+        libc::writev(
+            fd.as_fd().as_raw_fd(),
+            iov.as_ptr().cast(),
+            iov.len() as c_int,
+        )
     };
 
     Errno::result(res).map(|r| r as usize)
@@ -33,7 +37,11 @@
 pub fn readv<Fd: AsFd>(fd: Fd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> {
     // SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec
     let res = unsafe {
-        libc::readv(fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len() as c_int)
+        libc::readv(
+            fd.as_fd().as_raw_fd(),
+            iov.as_ptr().cast(),
+            iov.len() as c_int,
+        )
     };
 
     Errno::result(res).map(|r| r as usize)
@@ -45,9 +53,12 @@
 /// or an error occurs. The file offset is not changed.
 ///
 /// 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: AsFd>(fd: Fd, iov: &[IoSlice<'_>], offset: off_t) -> Result<usize> {
+#[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "solaris")))]
+pub fn pwritev<Fd: AsFd>(
+    fd: Fd,
+    iov: &[IoSlice<'_>],
+    offset: off_t,
+) -> Result<usize> {
     #[cfg(target_env = "uclibc")]
     let offset = offset as libc::off64_t; // uclibc doesn't use off_t
 
@@ -55,7 +66,7 @@
     let res = unsafe {
         libc::pwritev(
             fd.as_fd().as_raw_fd(),
-            iov.as_ptr() as *const libc::iovec,
+            iov.as_ptr().cast(),
             iov.len() as c_int,
             offset,
         )
@@ -71,8 +82,7 @@
 /// changed.
 ///
 /// 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())))]
+#[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "solaris")))]
 // Clippy doesn't know that we need to pass iov mutably only because the
 // mutation happens after converting iov to a pointer
 #[allow(clippy::needless_pass_by_ref_mut)]
@@ -88,7 +98,7 @@
     let res = unsafe {
         libc::preadv(
             fd.as_fd().as_raw_fd(),
-            iov.as_ptr() as *const libc::iovec,
+            iov.as_ptr().cast(),
             iov.len() as c_int,
             offset,
         )
@@ -105,7 +115,7 @@
     let res = unsafe {
         libc::pwrite(
             fd.as_fd().as_raw_fd(),
-            buf.as_ptr() as *const c_void,
+            buf.as_ptr().cast(),
             buf.len() as size_t,
             offset,
         )
@@ -122,7 +132,7 @@
     let res = unsafe {
         libc::pread(
             fd.as_fd().as_raw_fd(),
-            buf.as_mut_ptr() as *mut c_void,
+            buf.as_mut_ptr().cast(),
             buf.len() as size_t,
             offset,
         )
@@ -139,8 +149,7 @@
 /// therefore not represented in Rust by an actual slice as `IoSlice` is. It
 /// is used with [`process_vm_readv`](fn.process_vm_readv.html)
 /// and [`process_vm_writev`](fn.process_vm_writev.html).
-#[cfg(any(target_os = "linux", target_os = "android"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
+#[cfg(linux_android)]
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
 pub struct RemoteIoVec {
@@ -173,7 +182,7 @@
 /// [ptrace]: ../ptrace/index.html
 /// [`IoSlice`]: https://doc.rust-lang.org/std/io/struct.IoSlice.html
 /// [`RemoteIoVec`]: struct.RemoteIoVec.html
-#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))]
+#[cfg(all(linux_android, not(target_env = "uclibc")))]
 pub fn process_vm_writev(
     pid: crate::unistd::Pid,
     local_iov: &[IoSlice<'_>],
@@ -181,8 +190,8 @@
 {
     let res = unsafe {
         libc::process_vm_writev(pid.into(),
-                                local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
-                                remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
+                                local_iov.as_ptr().cast(), local_iov.len() as libc::c_ulong,
+                                remote_iov.as_ptr().cast(), remote_iov.len() as libc::c_ulong, 0)
     };
 
     Errno::result(res).map(|r| r as usize)
@@ -208,7 +217,7 @@
 /// [`ptrace`]: ../ptrace/index.html
 /// [`IoSliceMut`]: https://doc.rust-lang.org/std/io/struct.IoSliceMut.html
 /// [`RemoteIoVec`]: struct.RemoteIoVec.html
-#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))]
+#[cfg(all(linux_android, not(target_env = "uclibc")))]
 pub fn process_vm_readv(
     pid: crate::unistd::Pid,
     local_iov: &mut [IoSliceMut<'_>],
@@ -216,8 +225,8 @@
 {
     let res = unsafe {
         libc::process_vm_readv(pid.into(),
-                               local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
-                               remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
+                               local_iov.as_ptr().cast(), local_iov.len() as libc::c_ulong,
+                               remote_iov.as_ptr().cast(), remote_iov.len() as libc::c_ulong, 0)
     };
 
     Errno::result(res).map(|r| r as usize)
diff --git a/src/sys/utsname.rs b/src/sys/utsname.rs
index b48ed9f..cf4e6cc 100644
--- a/src/sys/utsname.rs
+++ b/src/sys/utsname.rs
@@ -37,7 +37,7 @@
     }
 
     /// NIS or YP domain name of this machine.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     pub fn domainname(&self) -> &OsStr {
         cast_and_trim(&self.0.domainname)
     }
@@ -62,24 +62,3 @@
 
     OsStr::from_bytes(bytes)
 }
-
-#[cfg(test)]
-mod test {
-    #[cfg(target_os = "linux")]
-    #[test]
-    pub fn test_uname_linux() {
-        assert_eq!(super::uname().unwrap().sysname(), "Linux");
-    }
-
-    #[cfg(any(target_os = "macos", target_os = "ios"))]
-    #[test]
-    pub fn test_uname_darwin() {
-        assert_eq!(super::uname().unwrap().sysname(), "Darwin");
-    }
-
-    #[cfg(target_os = "freebsd")]
-    #[test]
-    pub fn test_uname_freebsd() {
-        assert_eq!(super::uname().unwrap().sysname(), "FreeBSD");
-    }
-}
diff --git a/src/sys/wait.rs b/src/sys/wait.rs
index f7a63ff..844e165 100644
--- a/src/sys/wait.rs
+++ b/src/sys/wait.rs
@@ -24,53 +24,41 @@
         /// [`SIGSTOP`](crate::sys::signal::Signal::SIGSTOP) signal.
         WUNTRACED;
         /// Report the status of selected processes which have terminated.
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
+                  apple_targets,
                   target_os = "freebsd",
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
                   target_os = "redox",
-                  target_os = "macos",
                   target_os = "netbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         WEXITED;
         /// Report the status of selected processes that have continued from a
         /// job control stop by receiving a
         /// [`SIGCONT`](crate::sys::signal::Signal::SIGCONT) signal.
         WCONTINUED;
         /// An alias for WUNTRACED.
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
+                  apple_targets,
                   target_os = "freebsd",
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
                   target_os = "redox",
-                  target_os = "macos",
                   target_os = "netbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         WSTOPPED;
         /// Don't reap, just poll status.
-        #[cfg(any(target_os = "android",
+        #[cfg(any(linux_android,
+                  apple_targets,
                   target_os = "freebsd",
                   target_os = "haiku",
-                  target_os = "ios",
-                  target_os = "linux",
                   target_os = "redox",
-                  target_os = "macos",
                   target_os = "netbsd"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
         WNOWAIT;
         /// Don't wait on children of other threads in this group
-        #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, target_os = "redox"))]
         __WNOTHREAD;
         /// Wait on all children, regardless of type
-        #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, target_os = "redox"))]
         __WALL;
         /// Wait for "clone" children only.
-        #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
-        #[cfg_attr(docsrs, doc(cfg(all())))]
+        #[cfg(any(linux_android, target_os = "redox"))]
         __WCLONE;
     }
 );
@@ -107,16 +95,14 @@
     ///
     /// [`nix::sys::ptrace`]: ../ptrace/index.html
     /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html
-    #[cfg(any(target_os = "linux", target_os = "android"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     PtraceEvent(Pid, Signal, c_int),
     /// The traced process was stopped by execution of a system call,
     /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for
     /// more information.
     ///
     /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html
-    #[cfg(any(target_os = "linux", target_os = "android"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(linux_android)]
     PtraceSyscall(Pid),
     /// The process was previously stopped but has resumed execution
     /// after receiving a `SIGCONT` signal. This is only reported if
@@ -139,7 +125,7 @@
                 Some(p)
             }
             StillAlive => None,
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p),
         }
     }
@@ -173,7 +159,7 @@
     Signal::try_from(libc::WSTOPSIG(status))
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn syscall_stop(status: i32) -> bool {
     // From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect
     // of delivering SIGTRAP | 0x80 as the signal number for syscall
@@ -182,7 +168,7 @@
     libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn stop_additional(status: i32) -> c_int {
     (status >> 16) as c_int
 }
@@ -216,7 +202,7 @@
             WaitStatus::Signaled(pid, term_signal(status)?, dumped_core(status))
         } else if stopped(status) {
             cfg_if! {
-                if #[cfg(any(target_os = "android", target_os = "linux"))] {
+                if #[cfg(linux_android)] {
                     fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
                         let status_additional = stop_additional(status);
                         Ok(if syscall_stop(status) {
@@ -259,7 +245,7 @@
         all(target_os = "linux", not(target_env = "uclibc")),
     ))]
     unsafe fn from_siginfo(siginfo: &libc::siginfo_t) -> Result<WaitStatus> {
-        let si_pid = siginfo.si_pid();
+        let si_pid = unsafe { siginfo.si_pid() };
         if si_pid == 0 {
             return Ok(WaitStatus::StillAlive);
         }
@@ -267,7 +253,7 @@
         assert_eq!(siginfo.si_signo, libc::SIGCHLD);
 
         let pid = Pid::from_raw(si_pid);
-        let si_status = siginfo.si_status();
+        let si_status = unsafe { siginfo.si_status() };
 
         let status = match siginfo.si_code {
             libc::CLD_EXITED => WaitStatus::Exited(pid, si_status),
@@ -280,7 +266,7 @@
                 WaitStatus::Stopped(pid, Signal::try_from(si_status)?)
             }
             libc::CLD_CONTINUED => WaitStatus::Continued(pid),
-            #[cfg(any(target_os = "android", target_os = "linux"))]
+            #[cfg(linux_android)]
             libc::CLD_TRAPPED => {
                 if si_status == libc::SIGTRAP | 0x80 {
                     WaitStatus::PtraceSyscall(pid)
@@ -354,7 +340,7 @@
     /// If the PID is zero, the caller's process group is used since Linux 5.4.
     PGid(Pid),
     /// Wait for the child referred to by the given PID file descriptor
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     PIDFd(BorrowedFd<'fd>),
     /// A helper variant to resolve the unused parameter (`'fd`) problem on platforms
     /// other than Linux and Android.
@@ -376,9 +362,11 @@
         Id::All => (libc::P_ALL, 0),
         Id::Pid(pid) => (libc::P_PID, pid.as_raw() as libc::id_t),
         Id::PGid(pid) => (libc::P_PGID, pid.as_raw() as libc::id_t),
-        #[cfg(any(target_os = "android", target_os = "linux"))]
+        #[cfg(linux_android)]
         Id::PIDFd(fd) => (libc::P_PIDFD, fd.as_raw_fd() as libc::id_t),
-        Id::_Unreachable(_) => unreachable!("This variant could never be constructed"),
+        Id::_Unreachable(_) => {
+            unreachable!("This variant could never be constructed")
+        }
     };
 
     let siginfo = unsafe {
diff --git a/src/time.rs b/src/time.rs
index 2e03c46..195df71 100644
--- a/src/time.rs
+++ b/src/time.rs
@@ -1,11 +1,6 @@
+//! Sleep, query system clocks, and set system clock
 use crate::sys::time::TimeSpec;
-#[cfg(any(
-    target_os = "freebsd",
-    target_os = "dragonfly",
-    target_os = "linux",
-    target_os = "android",
-    target_os = "emscripten",
-))]
+#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
 #[cfg(feature = "process")]
 use crate::unistd::Pid;
 use crate::{Errno, Result};
@@ -14,8 +9,7 @@
 
 /// Clock identifier
 ///
-/// Newtype pattern around `clockid_t` (which is just alias). It prevents bugs caused by
-/// accidentally passing wrong value.
+/// Newtype pattern around [`libc::clockid_t`].
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
 pub struct ClockId(clockid_t);
 
@@ -28,14 +22,7 @@
     feature! {
     #![feature = "process"]
     /// Returns `ClockId` of a `pid` CPU-time clock
-    #[cfg(any(
-        target_os = "freebsd",
-        target_os = "dragonfly",
-        target_os = "linux",
-        target_os = "android",
-        target_os = "emscripten",
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
     pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> {
         clock_getcpuclockid(pid)
     }
@@ -43,7 +30,6 @@
 
     /// Returns resolution of the clock id
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn res(self) -> Result<TimeSpec> {
         clock_getres(self)
     }
@@ -55,12 +41,12 @@
 
     /// Sets time to `timespec` on the clock id
     #[cfg(not(any(
-        target_os = "macos",
         target_os = "ios",
+        target_os = "tvos",
+        target_os = "watchos",
         target_os = "redox",
-        target_os = "hermit",
+        target_os = "hermit"
     )))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub fn set_time(self, timespec: TimeSpec) -> Result<()> {
         clock_settime(self, timespec)
     }
@@ -70,135 +56,103 @@
         self.0
     }
 
-    #[cfg(any(
-        target_os = "android",
-        target_os = "emscripten",
-        target_os = "fuchsia",
-        target_os = "linux"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
+    /// Starts at zero when the kernel boots and increments monotonically in SI seconds while the
+    /// machine is running.
     pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME);
-    #[cfg(any(
-        target_os = "android",
-        target_os = "emscripten",
-        target_os = "fuchsia",
-        target_os = "linux"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    /// Like [`CLOCK_BOOTTIME`](ClockId::CLOCK_BOOTTIME), but will wake the system if it is
+    /// suspended..
+    #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
     pub const CLOCK_BOOTTIME_ALARM: ClockId =
         ClockId(libc::CLOCK_BOOTTIME_ALARM);
+    /// Increments in SI seconds.
     pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC);
-    #[cfg(any(
-        target_os = "android",
-        target_os = "emscripten",
-        target_os = "fuchsia",
-        target_os = "linux"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    /// Like [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but optimized for execution time at the expense of accuracy.
+    #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
     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())))]
+    #[cfg(freebsdlike)]
+    /// Like [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but optimized for execution time at the expense of accuracy.
     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())))]
+    #[cfg(freebsdlike)]
+    /// Like [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but optimized for accuracy at the expense of execution time.
     pub const CLOCK_MONOTONIC_PRECISE: ClockId =
         ClockId(libc::CLOCK_MONOTONIC_PRECISE);
-    #[cfg(any(
-        target_os = "android",
-        target_os = "emscripten",
-        target_os = "fuchsia",
-        target_os = "linux"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    /// Similar to [`CLOCK_MONOTONIC`](ClockId::CLOCK_MONOTONIC), but provides access to a raw
+    /// hardware-based time that is not subject to NTP adjustments.
+    #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
     pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW);
     #[cfg(any(
-        target_os = "android",
+        linux_android,
+        apple_targets,
+        freebsdlike,
         target_os = "emscripten",
         target_os = "fuchsia",
-        target_os = "macos",
-        target_os = "ios",
-        target_os = "freebsd",
-        target_os = "dragonfly",
         target_os = "redox",
-        target_os = "linux"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    /// Returns the execution time of the calling process.
     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())))]
+    #[cfg(freebsdlike)]
+    /// Increments when the CPU is running in user or kernel mode
     pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF);
+    /// Increments as a wall clock should.
     pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME);
-    #[cfg(any(
-        target_os = "android",
-        target_os = "emscripten",
-        target_os = "fuchsia",
-        target_os = "linux"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    /// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but not settable.
+    #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
     pub const CLOCK_REALTIME_ALARM: ClockId =
         ClockId(libc::CLOCK_REALTIME_ALARM);
-    #[cfg(any(
-        target_os = "android",
-        target_os = "emscripten",
-        target_os = "fuchsia",
-        target_os = "linux"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    /// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but optimized for execution time at the expense of accuracy.
+    #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
     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())))]
+    #[cfg(freebsdlike)]
+    /// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but optimized for execution time at the expense of accuracy.
     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())))]
+    #[cfg(freebsdlike)]
+    /// Like [`CLOCK_REALTIME`](ClockId::CLOCK_REALTIME), but optimized for accuracy at the expense of execution time.
     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())))]
+    #[cfg(freebsdlike)]
+    /// Returns the current second without performing a full time counter query, using an in-kernel
+    /// cached value of the current second.
     pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND);
+    #[allow(missing_docs)] // Undocumented on Linux!
     #[cfg(any(
         target_os = "emscripten",
         target_os = "fuchsia",
         all(target_os = "linux", target_env = "musl")
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE);
-    #[cfg(any(
-        target_os = "android",
-        target_os = "emscripten",
-        target_os = "fuchsia",
-        target_os = "linux"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    /// International Atomic Time.
+    ///
+    /// A nonsettable system-wide clock derived from wall-clock time but ignoring leap seconds.
+    #[cfg(any(linux_android, target_os = "emscripten", target_os = "fuchsia"))]
     pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI);
     #[cfg(any(
-        target_os = "android",
+        linux_android,
+        apple_targets,
+        freebsdlike,
         target_os = "emscripten",
         target_os = "fuchsia",
-        target_os = "ios",
-        target_os = "macos",
-        target_os = "freebsd",
-        target_os = "dragonfly",
-        target_os = "linux"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    /// Returns the execution time of the calling thread.
     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())))]
+    #[cfg(freebsdlike)]
+    /// Starts at zero when the kernel boots and increments monotonically in SI seconds while the
+    /// machine is running.
     pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME);
-    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(freebsdlike)]
+    /// Like [`CLOCK_UPTIME`](ClockId::CLOCK_UPTIME), but optimized for execution time at the expense of accuracy.
     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())))]
+    #[cfg(freebsdlike)]
+    /// Like [`CLOCK_UPTIME`](ClockId::CLOCK_UPTIME), but optimized for accuracy at the expense of execution time.
     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())))]
+    #[cfg(freebsdlike)]
+    /// Increments only when the CPU is running in user mode on behalf of the calling process.
     pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL);
 }
 
@@ -223,7 +177,6 @@
 /// Get the resolution of the specified clock, (see
 /// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)).
 #[cfg(not(target_os = "redox"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> {
     let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
     let ret =
@@ -247,12 +200,12 @@
 /// Set the time of the specified clock, (see
 /// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)).
 #[cfg(not(any(
-    target_os = "macos",
     target_os = "ios",
+    target_os = "tvos",
+    target_os = "watchos",
     target_os = "redox",
-    target_os = "hermit",
+    target_os = "hermit"
 )))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
 pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> {
     let ret =
         unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) };
@@ -261,13 +214,7 @@
 
 /// Get the clock id of the specified process id, (see
 /// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)).
-#[cfg(any(
-    target_os = "freebsd",
-    target_os = "dragonfly",
-    target_os = "linux",
-    target_os = "android",
-    target_os = "emscripten",
-))]
+#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
 #[cfg(feature = "process")]
 #[cfg_attr(docsrs, doc(cfg(feature = "process")))]
 pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
@@ -278,6 +225,61 @@
         let res = unsafe { clk_id.assume_init() };
         Ok(ClockId::from(res))
     } else {
-        Err(Errno::from_i32(ret))
+        Err(Errno::from_raw(ret))
+    }
+}
+
+#[cfg(any(
+    linux_android,
+    solarish,
+    freebsdlike,
+    target_os = "netbsd",
+    target_os = "hurd",
+    target_os = "aix"
+))]
+libc_bitflags! {
+    /// Flags that are used for arming the timer.
+    pub struct ClockNanosleepFlags: libc::c_int {
+        /// Indicates that a requested time value should be treated as absolute instead of
+        /// relative.
+        TIMER_ABSTIME;
+    }
+}
+
+/// Suspend execution of this thread for the amount of time specified by `request`
+/// and measured against the clock speficied by `clock_id`.
+///
+/// If `flags` is [`TIMER_ABSTIME`](ClockNanosleepFlags::TIMER_ABSTIME), this function will suspend
+/// execution until the time value of clock_id reaches the absolute time specified by `request`. If
+/// a signal is caught by a signal-catching function, or a signal causes the process to terminate,
+/// this sleep is interrrupted.
+///
+/// see also [man 3 clock_nanosleep](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_nanosleep.html)
+#[cfg(any(
+    linux_android,
+    solarish,
+    freebsdlike,
+    target_os = "netbsd",
+    target_os = "hurd",
+    target_os = "aix"
+))]
+pub fn clock_nanosleep(
+    clock_id: ClockId,
+    flags: ClockNanosleepFlags,
+    request: &TimeSpec,
+) -> Result<TimeSpec> {
+    let mut remain = TimeSpec::new(0, 0);
+    let ret = unsafe {
+        libc::clock_nanosleep(
+            clock_id.as_raw(),
+            flags.bits(),
+            request.as_ref() as *const _,
+            remain.as_mut() as *mut _,
+        )
+    };
+    if ret == 0 {
+        Ok(remain)
+    } else {
+        Err(Errno::from_raw(ret))
     }
 }
diff --git a/src/unistd.rs b/src/unistd.rs
index bb9f1c1..4502766 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -1,22 +1,29 @@
 //! Safe wrappers around functions found in libc "unistd.h" header
 
-use crate::errno::{self, Errno};
+use crate::errno::Errno;
+
+#[cfg(any(
+    all(feature = "fs", not(target_os = "redox")),
+    all(feature = "process", linux_android)
+))]
+use crate::fcntl::at_rawfd;
 #[cfg(not(target_os = "redox"))]
 #[cfg(feature = "fs")]
-use crate::fcntl::{at_rawfd, AtFlags};
+use crate::fcntl::AtFlags;
+
 #[cfg(feature = "fs")]
-use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag};
-#[cfg(all(
-    feature = "fs",
-    any(
-        target_os = "openbsd",
-        target_os = "netbsd",
-        target_os = "freebsd",
-        target_os = "dragonfly",
-        target_os = "macos",
-        target_os = "ios"
-    )
+#[cfg(any(
+    linux_android,
+    freebsdlike,
+    solarish,
+    netbsdlike,
+    target_os = "emscripten",
+    target_os = "fuchsia",
+    target_os = "hurd",
+    target_os = "redox",
 ))]
+use crate::fcntl::OFlag;
+#[cfg(all(feature = "fs", bsd))]
 use crate::sys::stat::FileFlag;
 #[cfg(feature = "fs")]
 use crate::sys::stat::Mode;
@@ -24,43 +31,27 @@
 #[cfg(not(target_os = "redox"))]
 use cfg_if::cfg_if;
 use libc::{
-    self, c_char, c_int, c_long, c_uint, c_void, gid_t, mode_t, off_t, pid_t,
-    size_t, uid_t, PATH_MAX,
+    c_char, c_int, c_long, c_uint, gid_t, mode_t, off_t, pid_t, size_t, uid_t,
 };
 use std::convert::Infallible;
-use std::ffi::{CStr, OsString};
 #[cfg(not(target_os = "redox"))]
-use std::ffi::{CString, OsStr};
-#[cfg(not(target_os = "redox"))]
-use std::os::unix::ffi::OsStrExt;
-use std::os::unix::ffi::OsStringExt;
-use std::os::unix::io::RawFd;
-use std::os::unix::io::{AsFd, AsRawFd};
+use std::ffi::CString;
+use std::ffi::{CStr, OsStr, OsString};
+use std::os::unix::ffi::{OsStrExt, OsStringExt};
+use std::os::unix::io::{AsFd, AsRawFd, OwnedFd, RawFd};
 use std::path::PathBuf;
 use std::{fmt, mem, ptr};
 
 feature! {
     #![feature = "fs"]
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     pub use self::pivot_root::*;
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "openbsd"
-))]
+#[cfg(any(freebsdlike, linux_android, target_os = "openbsd"))]
 pub use self::setres::*;
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "openbsd"
-))]
+#[cfg(any(freebsdlike, linux_android, target_os = "openbsd"))]
 pub use self::getres::*;
 
 feature! {
@@ -225,7 +216,12 @@
 /// you are now executing in the parent process or in the child.
 #[derive(Clone, Copy, Debug)]
 pub enum ForkResult {
-    Parent { child: Pid },
+    /// This is the parent process of the fork.
+    Parent {
+        /// The PID of the fork's child process
+        child: Pid
+    },
+    /// This is the child process of the fork.
     Child,
 }
 
@@ -260,7 +256,7 @@
 ///    }
 ///    Ok(ForkResult::Child) => {
 ///        // Unsafe to use `println!` (or `unwrap`) here. See Safety.
-///        write(libc::STDOUT_FILENO, "I'm a new child process\n".as_bytes()).ok();
+///        write(std::io::stdout(), "I'm a new child process\n".as_bytes()).ok();
 ///        unsafe { libc::_exit(0) };
 ///    }
 ///    Err(_) => println!("Fork failed"),
@@ -290,7 +286,7 @@
 #[inline]
 pub unsafe fn fork() -> Result<ForkResult> {
     use self::ForkResult::*;
-    let res = libc::fork();
+    let res = unsafe { libc::fork() };
 
     Errno::result(res).map(|res| match res {
         0 => Child,
@@ -332,6 +328,9 @@
     let res = unsafe { libc::setpgid(pid.into(), pgid.into()) };
     Errno::result(res).map(drop)
 }
+/// Get process group
+///
+/// See Also [`getpgid`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgid.html)
 #[inline]
 pub fn getpgid(pid: Option<Pid>) -> Result<Pid> {
     let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) };
@@ -366,8 +365,8 @@
 /// Get the group process id (GPID) of the foreground process group on the
 /// terminal associated to file descriptor (FD).
 #[inline]
-pub fn tcgetpgrp(fd: c_int) -> Result<Pid> {
-    let res = unsafe { libc::tcgetpgrp(fd) };
+pub fn tcgetpgrp<F: AsFd>(fd: F) -> Result<Pid> {
+    let res = unsafe { libc::tcgetpgrp(fd.as_fd().as_raw_fd()) };
     Errno::result(res).map(Pid)
 }
 /// Set the terminal foreground process group (see
@@ -376,8 +375,8 @@
 /// Get the group process id (PGID) to the foreground process group on the
 /// terminal associated to file descriptor (FD).
 #[inline]
-pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> {
-    let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) };
+pub fn tcsetpgrp<F: AsFd>(fd: F, pgrp: Pid) -> Result<()> {
+    let res = unsafe { libc::tcsetpgrp(fd.as_fd().as_raw_fd(), pgrp.into()) };
     Errno::result(res).map(drop)
 }
 }
@@ -404,7 +403,7 @@
 ///
 /// No error handling is required as a thread id should always exist for any
 /// process, even if threads are not being used.
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[inline]
 pub fn gettid() -> Pid {
     Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t })
@@ -444,30 +443,22 @@
 }
 
 /// Create a new copy of the specified file descriptor using the specified fd
-/// and flags (see [dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)).
+/// and flags (see [`dup(2)`](https://man7.org/linux/man-pages/man2/dup.2.html)).
 ///
 /// This function behaves similar to `dup2()` but allows for flags to be
 /// specified.
+#[cfg(any(
+    netbsdlike,
+    solarish,
+    target_os = "freebsd",
+    target_os = "fuchsia",
+    target_os = "hurd",
+    target_os = "linux"
+))]
 pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
-    dup3_polyfill(oldfd, newfd, flags)
-}
+    let res = unsafe { libc::dup3(oldfd, newfd, flags.bits()) };
 
-#[inline]
-fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
-    if oldfd == newfd {
-        return Err(Errno::EINVAL);
-    }
-
-    let fd = dup2(oldfd, newfd)?;
-
-    if flags.contains(OFlag::O_CLOEXEC) {
-        if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) {
-            let _ = close(fd);
-            return Err(e);
-        }
-    }
-
-    Ok(fd)
+    Errno::result(res)
 }
 
 /// Change the current working directory of the calling process (see
@@ -583,8 +574,7 @@
 // mkfifoat is not implemented in OSX or android
 #[inline]
 #[cfg(not(any(
-    target_os = "macos",
-    target_os = "ios",
+    apple_targets,
     target_os = "haiku",
     target_os = "android",
     target_os = "redox"
@@ -664,17 +654,17 @@
 /// ```
 #[inline]
 pub fn getcwd() -> Result<PathBuf> {
-    let mut buf = Vec::with_capacity(512);
+    let mut buf = Vec::<u8>::with_capacity(512);
     loop {
         unsafe {
-            let ptr = buf.as_mut_ptr() as *mut c_char;
+            let ptr = buf.as_mut_ptr().cast();
 
             // The buffer must be large enough to store the absolute pathname plus
             // a terminating null byte, or else null is returned.
             // To safely handle this we start with a reasonable size (512 bytes)
             // and double the buffer size upon every error
             if !libc::getcwd(ptr, buf.capacity()).is_null() {
-                let len = CStr::from_ptr(buf.as_ptr() as *const c_char)
+                let len = CStr::from_ptr(buf.as_ptr().cast())
                     .to_bytes()
                     .len();
                 buf.set_len(len);
@@ -688,8 +678,13 @@
                 }
             }
 
+            #[cfg(not(target_os = "hurd"))]
+            const PATH_MAX: usize = libc::PATH_MAX as usize;
+            #[cfg(target_os = "hurd")]
+            const PATH_MAX: usize = 1024; // Hurd does not define a hard limit, so try a guess first
+
             // Trigger the internal buffer resizing logic.
-            reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?;
+            reserve_double_buffer_size(&mut buf, PATH_MAX)?;
         }
     }
 }
@@ -749,11 +744,19 @@
     Errno::result(res).map(drop)
 }
 
-/// Flags for `fchownat` function.
-#[derive(Clone, Copy, Debug)]
-pub enum FchownatFlags {
-    FollowSymlink,
-    NoFollowSymlink,
+// Just a wrapper around `AtFlags` so that we can help our users migrate.
+#[allow(missing_docs)]
+#[cfg(not(target_os = "redox"))]
+pub type FchownatFlags = AtFlags;
+#[allow(missing_docs)]
+#[cfg(not(target_os = "redox"))]
+impl FchownatFlags {
+    #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")]
+    #[allow(non_upper_case_globals)]
+    pub const FollowSymlink: FchownatFlags = FchownatFlags::empty();
+    #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")]
+    #[allow(non_upper_case_globals)]
+    pub const NoFollowSymlink: FchownatFlags = FchownatFlags::AT_SYMLINK_NOFOLLOW;
 }
 
 /// Change the ownership of the file at `path` to be owned by the specified
@@ -767,10 +770,10 @@
 /// with the file descriptor `dirfd` or the current working directory
 /// if `dirfd` is `None`.
 ///
-/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link,
+/// If `flag` is `AtFlags::AT_SYMLINK_NOFOLLOW` and `path` names a symbolic link,
 /// then the mode of the symbolic link is changed.
 ///
-/// `fchownat(None, path, owner, group, FchownatFlags::NoFollowSymlink)` is identical to
+/// `fchownat(None, path, owner, group, AtFlags::AT_SYMLINK_NOFOLLOW)` is identical to
 /// a call `libc::lchown(path, owner, group)`.  That's why `lchown` is unimplemented in
 /// the `nix` crate.
 ///
@@ -783,12 +786,8 @@
     path: &P,
     owner: Option<Uid>,
     group: Option<Gid>,
-    flag: FchownatFlags,
+    flag: AtFlags,
 ) -> Result<()> {
-    let atflag = match flag {
-        FchownatFlags::FollowSymlink => AtFlags::empty(),
-        FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
-    };
     let res = path.with_nix_path(|cstr| unsafe {
         let (uid, gid) = chown_raw_ids(owner, group);
         libc::fchownat(
@@ -796,7 +795,7 @@
             cstr.as_ptr(),
             uid,
             gid,
-            atflag.bits() as libc::c_int,
+            flag.bits()
         )
     })?;
 
@@ -883,7 +882,7 @@
 /// This functions like a combination of `execvp(2)` and `execve(2)` to pass an
 /// environment and have a search path. See these two for additional
 /// information.
-#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))]
+#[cfg(any(target_os = "haiku", target_os = "hurd", target_os = "linux", target_os = "openbsd"))]
 pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(
     filename: &CStr,
     args: &[SA],
@@ -909,12 +908,7 @@
 ///
 /// This function is similar to `execve`, except that the program to be executed
 /// is referenced as a file descriptor instead of a path.
-#[cfg(any(
-    target_os = "android",
-    target_os = "linux",
-    target_os = "dragonfly",
-    target_os = "freebsd"
-))]
+#[cfg(any(linux_android, freebsdlike, target_os = "hurd"))]
 #[inline]
 pub fn fexecve<SA: AsRef<CStr>, SE: AsRef<CStr>>(
     fd: RawFd,
@@ -939,15 +933,16 @@
 ///
 /// This function is similar to `execve`, except that the program to be executed
 /// is referenced as a file descriptor to the base directory plus a path.
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[inline]
 pub fn execveat<SA: AsRef<CStr>, SE: AsRef<CStr>>(
-    dirfd: RawFd,
+    dirfd: Option<RawFd>,
     pathname: &CStr,
     args: &[SA],
     env: &[SE],
     flags: super::fcntl::AtFlags,
 ) -> Result<Infallible> {
+    let dirfd = at_rawfd(dirfd);
     let args_p = to_exec_array(args);
     let env_p = to_exec_array(env);
 
@@ -991,14 +986,10 @@
 /// * `noclose = false`: The process' stdin, stdout, and stderr will point to
 ///   `/dev/null` after daemonizing.
 #[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "illumos",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd",
-    target_os = "solaris"
+        linux_android,
+        freebsdlike,
+        solarish,
+        netbsdlike
 ))]
 pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
     let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) };
@@ -1020,19 +1011,16 @@
 pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
     // Handle some differences in type of the len arg across platforms.
     cfg_if! {
-        if #[cfg(any(target_os = "dragonfly",
-                     target_os = "freebsd",
-                     target_os = "illumos",
-                     target_os = "ios",
-                     target_os = "macos",
-                     target_os = "aix",
-                     target_os = "solaris", ))] {
+        if #[cfg(any(freebsdlike,
+                     solarish,
+                     apple_targets,
+                     target_os = "aix"))] {
             type sethostname_len_t = c_int;
         } else {
             type sethostname_len_t = size_t;
         }
     }
-    let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char;
+    let ptr = name.as_ref().as_bytes().as_ptr().cast();
     let len = name.as_ref().len() as sethostname_len_t;
 
     let res = unsafe { libc::sethostname(ptr, len) };
@@ -1056,14 +1044,14 @@
 pub fn gethostname() -> Result<OsString> {
     // The capacity is the max length of a hostname plus the NUL terminator.
     let mut buffer: Vec<u8> = Vec::with_capacity(256);
-    let ptr = buffer.as_mut_ptr() as *mut c_char;
+    let ptr = buffer.as_mut_ptr().cast();
     let len = buffer.capacity() as size_t;
 
     let res = unsafe { libc::gethostname(ptr, len) };
     Errno::result(res).map(|_| {
         unsafe {
             buffer.as_mut_ptr().wrapping_add(len - 1).write(0); // ensure always null-terminated
-            let len = CStr::from_ptr(buffer.as_ptr() as *const c_char).len();
+            let len = CStr::from_ptr(buffer.as_ptr().cast()).len();
             buffer.set_len(len);
         }
         OsString::from_vec(buffer)
@@ -1105,9 +1093,8 @@
 ///
 /// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html)
 pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> {
-    let res = unsafe {
-        libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t)
-    };
+    let res =
+        unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as size_t) };
 
     Errno::result(res).map(|r| r as usize)
 }
@@ -1115,9 +1102,13 @@
 /// Write to a raw file descriptor.
 ///
 /// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html)
-pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> {
+pub fn write<Fd: AsFd>(fd: Fd, buf: &[u8]) -> Result<usize> {
     let res = unsafe {
-        libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t)
+        libc::write(
+            fd.as_fd().as_raw_fd(),
+            buf.as_ptr().cast(),
+            buf.len() as size_t,
+        )
     };
 
     Errno::result(res).map(|r| r as usize)
@@ -1143,11 +1134,9 @@
     /// equal to offset that contains some data. If offset points to
     /// some data, then the file offset is set to offset.
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
+        freebsdlike,
+        solarish,
         target_os = "linux",
-        target_os = "solaris"
     ))]
     SeekData = libc::SEEK_DATA,
     /// Specify an offset relative to the next hole in the file greater than
@@ -1156,11 +1145,9 @@
     /// then the file offset should be adjusted to the end of the file (i.e., there
     /// is an implicit hole at the end of any file).
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
+        freebsdlike,
+        solarish,
         target_os = "linux",
-        target_os = "solaris"
     ))]
     SeekHole = libc::SEEK_HOLE,
 }
@@ -1174,7 +1161,11 @@
     Errno::result(res).map(|r| r as off_t)
 }
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
+/// Move the read/write file offset.
+///
+/// Unlike [`lseek`], it takes a 64-bit argument even on platforms where [`libc::off_t`] is
+/// 32 bits.
+#[cfg(linux_android)]
 pub fn lseek64(
     fd: RawFd,
     offset: libc::off64_t,
@@ -1189,14 +1180,15 @@
 /// Create an interprocess channel.
 ///
 /// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html)
-pub fn pipe() -> std::result::Result<(RawFd, RawFd), Error> {
-    let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
+pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> {
+    let mut fds = mem::MaybeUninit::<[OwnedFd; 2]>::uninit();
 
-    let res = unsafe { libc::pipe(fds.as_mut_ptr() as *mut c_int) };
+    let res = unsafe { libc::pipe(fds.as_mut_ptr().cast()) };
 
     Error::result(res)?;
 
-    unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }
+    let [read, write] = unsafe { fds.assume_init() };
+    Ok((read, write))
 }
 
 feature! {
@@ -1219,26 +1211,24 @@
 ///
 /// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html)
 #[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
+    linux_android,
+    freebsdlike,
+    solarish,
     target_os = "emscripten",
-    target_os = "freebsd",
-    target_os = "illumos",
-    target_os = "linux",
+    target_os = "hurd",
     target_os = "redox",
-    target_os = "netbsd",
-    target_os = "openbsd",
-    target_os = "solaris"
+    netbsdlike,
 ))]
-pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
-    let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
+pub fn pipe2(flags: OFlag) -> Result<(OwnedFd, OwnedFd)> {
+    let mut fds = mem::MaybeUninit::<[OwnedFd; 2]>::uninit();
 
     let res =
-        unsafe { libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) };
+        unsafe { libc::pipe2(fds.as_mut_ptr().cast(), flags.bits()) };
 
     Errno::result(res)?;
 
-    unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }
+    let [read, write] = unsafe { fds.assume_init() };
+    Ok((read, write))
 }
 
 /// Truncate a file to a specified length
@@ -1261,6 +1251,7 @@
     Errno::result(unsafe { libc::ftruncate(fd.as_fd().as_raw_fd(), len) }).map(drop)
 }
 
+/// Determines if the file descriptor refers to a valid terminal type device.
 pub fn isatty(fd: RawFd) -> Result<bool> {
     unsafe {
         // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so
@@ -1276,11 +1267,18 @@
     }
 }
 
-/// Flags for `linkat` function.
-#[derive(Clone, Copy, Debug)]
-pub enum LinkatFlags {
-    SymlinkFollow,
-    NoSymlinkFollow,
+#[allow(missing_docs)]
+#[cfg(not(target_os = "redox"))]
+pub type LinkatFlags = AtFlags;
+#[allow(missing_docs)]
+#[cfg(not(target_os = "redox"))]
+impl LinkatFlags {
+    #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")]
+    #[allow(non_upper_case_globals)]
+    pub const SymlinkFollow: LinkatFlags = LinkatFlags::AT_SYMLINK_FOLLOW;
+    #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")]
+    #[allow(non_upper_case_globals)]
+    pub const NoSymlinkFollow: LinkatFlags = LinkatFlags::empty();
 }
 
 /// Link one file to another file
@@ -1288,7 +1286,7 @@
 /// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the
 /// case of a relative `oldpath`, the path is interpreted relative to the directory associated
 /// with file descriptor `olddirfd` instead of the current working directory and similiarly for
-/// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and
+/// `newpath` and file descriptor `newdirfd`. In case `flag` is `AtFlags::AT_SYMLINK_FOLLOW` and
 /// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created.
 /// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath`
 /// and/or `newpath` is then interpreted relative to the current working directory of the calling
@@ -1302,13 +1300,8 @@
     oldpath: &P,
     newdirfd: Option<RawFd>,
     newpath: &P,
-    flag: LinkatFlags,
+    flag: AtFlags,
 ) -> Result<()> {
-    let atflag = match flag {
-        LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW,
-        LinkatFlags::NoSymlinkFollow => AtFlags::empty(),
-    };
-
     let res = oldpath.with_nix_path(|oldcstr| {
         newpath.with_nix_path(|newcstr| unsafe {
             libc::linkat(
@@ -1316,7 +1309,7 @@
                 oldcstr.as_ptr(),
                 at_rawfd(newdirfd),
                 newcstr.as_ptr(),
-                atflag.bits() as libc::c_int,
+                flag.bits(),
             )
         })
     })??;
@@ -1335,7 +1328,9 @@
 /// Flags for `unlinkat` function.
 #[derive(Clone, Copy, Debug)]
 pub enum UnlinkatFlags {
+    /// Remove the directory entry as a directory, not a normal file
     RemoveDir,
+    /// Remove the directory entry as a normal file, not a directory
     NoRemoveDir,
 }
 
@@ -1369,6 +1364,7 @@
     Errno::result(res).map(drop)
 }
 
+/// Change a process's root directory
 #[inline]
 #[cfg(not(target_os = "fuchsia"))]
 pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
@@ -1381,13 +1377,7 @@
 /// Commit filesystem caches to disk
 ///
 /// See also [sync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html)
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd"
-))]
+#[cfg(any(freebsdlike, linux_android, netbsdlike))]
 pub fn sync() {
     unsafe { libc::sync() };
 }
@@ -1396,7 +1386,7 @@
 /// descriptor `fd` to disk
 ///
 /// See also [syncfs(2)](https://man7.org/linux/man-pages/man2/sync.2.html)
-#[cfg(target_os = "linux")]
+#[cfg(linux_android)]
 pub fn syncfs(fd: RawFd) -> Result<()> {
     let res = unsafe { libc::syncfs(fd) };
 
@@ -1418,15 +1408,12 @@
 /// See also
 /// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html)
 #[cfg(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "emscripten",
+    linux_android,
+    solarish,
+    netbsdlike,
     target_os = "freebsd",
+    target_os = "emscripten",
     target_os = "fuchsia",
-    target_os = "netbsd",
-    target_os = "openbsd",
-    target_os = "illumos",
-    target_os = "solaris"
 ))]
 #[inline]
 pub fn fdatasync(fd: RawFd) -> Result<()> {
@@ -1527,7 +1514,7 @@
 /// ID of the caller.
 ///
 /// See also [setfsuid(2)](https://man7.org/linux/man-pages/man2/setfsuid.2.html)
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 pub fn setfsuid(uid: Uid) -> Uid {
     let prev_fsuid = unsafe { libc::setfsuid(uid.into()) };
     Uid::from_raw(prev_fsuid as uid_t)
@@ -1538,7 +1525,7 @@
 /// ID of the caller.
 ///
 /// See also [setfsgid(2)](https://man7.org/linux/man-pages/man2/setfsgid.2.html)
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 pub fn setfsgid(gid: Gid) -> Gid {
     let prev_fsgid = unsafe { libc::setfsgid(gid.into()) };
     Gid::from_raw(prev_fsgid as gid_t)
@@ -1555,14 +1542,14 @@
 /// **Note:** This function is not available for Apple platforms. On those
 /// platforms, checking group membership should be achieved via communication
 /// with the `opendirectoryd` service.
-#[cfg(not(any(target_os = "ios", target_os = "macos")))]
+#[cfg(not(apple_targets))]
 pub fn getgroups() -> Result<Vec<Gid>> {
     // First get the maximum number of groups. The value returned
     // shall always be greater than or equal to one and less than or
     // equal to the value of {NGROUPS_MAX} + 1.
     let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
         Ok(Some(n)) => (n + 1) as usize,
-        Ok(None) | Err(_) => <usize>::max_value(),
+        Ok(None) | Err(_) => usize::MAX,
     };
 
     // Next, get the number of groups so we can size our Vec
@@ -1588,7 +1575,7 @@
         let ngroups = unsafe {
             libc::getgroups(
                 groups.capacity() as c_int,
-                groups.as_mut_ptr() as *mut gid_t,
+                groups.as_mut_ptr().cast(),
             )
         };
 
@@ -1640,22 +1627,15 @@
 /// # try_main().unwrap();
 /// ```
 #[cfg(not(any(
-    target_os = "ios",
-    target_os = "macos",
+    apple_targets,
     target_os = "redox",
     target_os = "haiku"
 )))]
 pub fn setgroups(groups: &[Gid]) -> Result<()> {
     cfg_if! {
-        if #[cfg(any(target_os = "aix",
-                     target_os = "dragonfly",
-                     target_os = "freebsd",
-                     target_os = "illumos",
-                     target_os = "ios",
-                     target_os = "macos",
-                     target_os = "netbsd",
-                     target_os = "openbsd",
-                     target_os = "solaris"))] {
+        if #[cfg(any(bsd,
+                     solarish,
+                     target_os = "aix"))] {
             type setgroups_ngroups_t = c_int;
         } else {
             type setgroups_ngroups_t = size_t;
@@ -1667,7 +1647,7 @@
     let res = unsafe {
         libc::setgroups(
             groups.len() as setgroups_ngroups_t,
-            groups.as_ptr() as *const gid_t,
+            groups.as_ptr().cast(),
         )
     };
 
@@ -1696,20 +1676,19 @@
 /// will only ever return the complete list or else an error.
 #[cfg(not(any(
     target_os = "aix",
-    target_os = "illumos",
-    target_os = "ios",
-    target_os = "macos",
+    solarish,
+    apple_targets,
     target_os = "redox"
 )))]
 pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
     let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
         Ok(Some(n)) => n as c_int,
-        Ok(None) | Err(_) => <c_int>::max_value(),
+        Ok(None) | Err(_) => c_int::MAX,
     };
     use std::cmp::min;
     let mut groups = Vec::<Gid>::with_capacity(min(ngroups_max, 8) as usize);
     cfg_if! {
-        if #[cfg(any(target_os = "ios", target_os = "macos"))] {
+        if #[cfg(apple_targets)] {
             type getgrouplist_group_t = c_int;
         } else {
             type getgrouplist_group_t = gid_t;
@@ -1722,7 +1701,7 @@
             libc::getgrouplist(
                 user.as_ptr(),
                 gid as getgrouplist_group_t,
-                groups.as_mut_ptr() as *mut getgrouplist_group_t,
+                groups.as_mut_ptr().cast(),
                 &mut ngroups,
             )
         };
@@ -1781,14 +1760,13 @@
 /// # try_main().unwrap();
 /// ```
 #[cfg(not(any(
-    target_os = "ios",
-    target_os = "macos",
+    apple_targets,
     target_os = "redox",
     target_os = "haiku"
 )))]
 pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
     cfg_if! {
-        if #[cfg(any(target_os = "ios", target_os = "macos"))] {
+        if #[cfg(apple_targets)] {
             type initgroups_group_t = c_int;
         } else {
             type initgroups_group_t = gid_t;
@@ -1915,6 +1893,7 @@
 feature! {
 #![feature = "acct"]
 
+/// Process accounting
 #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
 pub mod acct {
     use crate::errno::Errno;
@@ -1970,7 +1949,7 @@
 pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
     let mut path =
         template.with_nix_path(|path| path.to_bytes_with_nul().to_owned())?;
-    let p = path.as_mut_ptr() as *mut _;
+    let p = path.as_mut_ptr().cast();
     let fd = unsafe { libc::mkstemp(p) };
     let last = path.pop(); // drop the trailing nul
     debug_assert!(last == Some(b'\0'));
@@ -1983,6 +1962,38 @@
 feature! {
 #![all(feature = "fs", feature = "feature")]
 
+/// Creates a directory which persists even after process termination
+///
+/// * `template`: a path whose rightmost characters contain some number of X, e.g. `/tmp/tmpdir_XXXXXX`
+/// * returns: filename
+///
+/// Err is returned either if no temporary filename could be created or the template had insufficient X
+///
+/// See also [mkstemp(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdtemp.html)
+///
+/// ```
+/// use nix::unistd;
+///
+/// match unistd::mkdtemp("/tmp/tempdir_XXXXXX") {
+///     Ok(_path) => {
+///         // do something with directory
+///     }
+///     Err(e) => panic!("mkdtemp failed: {}", e)
+/// };
+/// ```
+pub fn mkdtemp<P: ?Sized + NixPath>(template: &P) -> Result<PathBuf> {
+    let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?;
+    let p = path.as_mut_ptr() as *mut _;
+    let p = unsafe { libc::mkdtemp(p) };
+    if p.is_null() {
+        return Err(Errno::last());
+    }
+    let last = path.pop(); // drop the trailing nul
+    debug_assert!(last == Some(b'\0'));
+    let pathname = OsString::from_vec(path);
+    Ok(PathBuf::from(pathname))
+}
+
 /// Variable names for `pathconf`
 ///
 /// Nix uses the same naming convention for these variables as the
@@ -2004,16 +2015,13 @@
 #[non_exhaustive]
 pub enum PathconfVar {
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
+        freebsdlike,
+        netbsdlike,
         target_os = "linux",
-        target_os = "netbsd",
-        target_os = "openbsd",
         target_os = "redox"
     ))]
     /// Minimum number of bits needed to represent, as a signed integer value,
     /// the maximum size of a regular file allowed in the specified directory.
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     FILESIZEBITS = libc::_PC_FILESIZEBITS,
     /// Maximum number of links to a single file.
     LINK_MAX = libc::_PC_LINK_MAX,
@@ -2035,86 +2043,62 @@
     /// a pipe.
     PIPE_BUF = libc::_PC_PIPE_BUF,
     #[cfg(any(
-        target_os = "android",
+        linux_android,
+        solarish,
+        netbsdlike,
         target_os = "dragonfly",
-        target_os = "illumos",
-        target_os = "linux",
-        target_os = "netbsd",
-        target_os = "openbsd",
         target_os = "redox",
-        target_os = "solaris"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// Symbolic links can be created.
     POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "linux",
+        linux_android,
+        freebsdlike,
         target_os = "openbsd",
         target_os = "redox"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// Minimum number of bytes of storage actually allocated for any portion of
     /// a file.
     POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "linux",
+        freebsdlike,
+        linux_android,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// Recommended increment for file transfer sizes between the
     /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values.
     POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "linux",
+        linux_android,
+        freebsdlike,
         target_os = "openbsd",
         target_os = "redox"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// Maximum recommended file transfer size.
     POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "linux",
+        linux_android,
+        freebsdlike,
         target_os = "openbsd",
         target_os = "redox"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// Minimum recommended file transfer size.
     POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "linux",
+        linux_android,
+        freebsdlike,
         target_os = "openbsd",
         target_os = "redox"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     ///  Recommended file transfer buffer alignment.
     POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "linux",
-        target_os = "netbsd",
-        target_os = "openbsd",
+        linux_android,
+        freebsdlike,
+        solarish,
+        netbsdlike,
         target_os = "redox",
-        target_os = "solaris"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// Maximum number of bytes in a symbolic link.
     SYMLINK_MAX = libc::_PC_SYMLINK_MAX,
     /// The use of `chown` and `fchown` is restricted to a process with
@@ -2128,50 +2112,36 @@
     /// disable terminal special character handling.
     _POSIX_VDISABLE = libc::_PC_VDISABLE,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "linux",
+        linux_android,
+        freebsdlike,
+        solarish,
         target_os = "openbsd",
         target_os = "redox",
-        target_os = "solaris"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// Asynchronous input or output operations may be performed for the
     /// associated file.
     _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "linux",
+        linux_android,
+        freebsdlike,
+        solarish,
         target_os = "openbsd",
         target_os = "redox",
-        target_os = "solaris"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// Prioritized input or output operations may be performed for the
     /// associated file.
     _POSIX_PRIO_IO = libc::_PC_PRIO_IO,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "linux",
-        target_os = "netbsd",
-        target_os = "openbsd",
+        linux_android,
+        freebsdlike,
+        solarish,
+        netbsdlike,
         target_os = "redox",
-        target_os = "solaris"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// Synchronized input or output operations may be performed for the
     /// associated file.
     _POSIX_SYNC_IO = libc::_PC_SYNC_IO,
     #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The resolution in nanoseconds for all file timestamps.
     _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION,
 }
@@ -2192,13 +2162,13 @@
 /// - `Ok(None)`: the variable has no limit (for limit variables) or is
 ///     unsupported (for option variables)
 /// - `Err(x)`: an error occurred
-pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> {
+pub fn fpathconf<F: AsFd>(fd: F, var: PathconfVar) -> Result<Option<c_long>> {
     let raw = unsafe {
         Errno::clear();
-        libc::fpathconf(fd, var as c_int)
+        libc::fpathconf(fd.as_fd().as_raw_fd(), var as c_int)
     };
     if raw == -1 {
-        if errno::errno() == 0 {
+        if Errno::last_raw() == 0 {
             Ok(None)
         } else {
             Err(Errno::last())
@@ -2238,7 +2208,7 @@
         libc::pathconf(cstr.as_ptr(), var as c_int)
     })?;
     if raw == -1 {
-        if errno::errno() == 0 {
+        if Errno::last_raw() == 0 {
             Ok(None)
         } else {
             Err(Errno::last())
@@ -2275,23 +2245,17 @@
     /// Maximum number of I/O operations in a single list I/O call supported by
     /// the implementation.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX,
     /// Maximum number of outstanding asynchronous I/O operations supported by
     /// the implementation.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     AIO_MAX = libc::_SC_AIO_MAX,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        apple_targets,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The maximum amount by which a process can decrease its asynchronous I/O
     /// priority level from its own scheduling priority.
     AIO_PRIO_DELTA_MAX = libc::_SC_AIO_PRIO_DELTA_MAX,
@@ -2299,68 +2263,47 @@
     ARG_MAX = libc::_SC_ARG_MAX,
     /// Maximum number of functions that may be registered with `atexit`.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     ATEXIT_MAX = libc::_SC_ATEXIT_MAX,
     /// Maximum obase values allowed by the bc utility.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     BC_BASE_MAX = libc::_SC_BC_BASE_MAX,
     /// Maximum number of elements permitted in an array by the bc utility.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     BC_DIM_MAX = libc::_SC_BC_DIM_MAX,
     /// Maximum scale value allowed by the bc utility.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX,
     /// Maximum length of a string constant accepted by the bc utility.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     BC_STRING_MAX = libc::_SC_BC_STRING_MAX,
     /// Maximum number of simultaneous processes per real user ID.
     CHILD_MAX = libc::_SC_CHILD_MAX,
-    // The number of clock ticks per second.
+    /// The frequency of the statistics clock in ticks per second.
     CLK_TCK = libc::_SC_CLK_TCK,
     /// Maximum number of weights that can be assigned to an entry of the
     /// LC_COLLATE order keyword in the locale definition file
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX,
     /// Maximum number of timer expiration overruns.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX,
     /// Maximum number of expressions that can be nested within parentheses by
     /// the expr utility.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd",
-        target_os = "solaris"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, solarish, target_os = "linux"))]
     /// Maximum length of a host name (not including the terminating null) as
     /// returned from the `gethostname` function
     HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX,
     /// Maximum number of iovec structures that one process has available for
     /// use with `readv` or `writev`.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     IOV_MAX = libc::_SC_IOV_MAX,
     /// 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.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     LINE_MAX = libc::_SC_LINE_MAX,
     /// Maximum length of a login name.
     #[cfg(not(target_os = "haiku"))]
@@ -2369,308 +2312,176 @@
     NGROUPS_MAX = libc::_SC_NGROUPS_MAX,
     /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX,
     /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX,
     /// The maximum number of open message queue descriptors a process may hold.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX,
     /// The maximum number of message priorities supported by the implementation.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX,
     /// A value one greater than the maximum value that the system may assign to
     /// a newly-created file descriptor.
     OPEN_MAX = libc::_SC_OPEN_MAX,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
+        freebsdlike,
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Advisory Information option.
     _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd",
-        target_os = "solaris"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, solarish, target_os = "linux"))]
     /// The implementation supports barriers.
     _POSIX_BARRIERS = libc::_SC_BARRIERS,
     /// The implementation supports asynchronous input and output.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd",
-        target_os = "solaris"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, solarish, target_os = "linux"))]
     /// The implementation supports clock selection.
     _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd",
-        target_os = "solaris"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, solarish, target_os = "linux"))]
     /// The implementation supports the Process CPU-Time Clocks option.
     _POSIX_CPUTIME = libc::_SC_CPUTIME,
     /// The implementation supports the File Synchronization option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_FSYNC = libc::_SC_FSYNC,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "ios",
+        freebsdlike,
+        apple_targets,
+        solarish,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd",
-        target_os = "solaris"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the IPv6 option.
     _POSIX_IPV6 = libc::_SC_IPV6,
     /// The implementation supports job control.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL,
     /// The implementation supports memory mapped Files.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES,
     /// The implementation supports the Process Memory Locking option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_MEMLOCK = libc::_SC_MEMLOCK,
     /// The implementation supports the Range Memory Locking option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE,
     /// The implementation supports memory protection.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION,
     /// The implementation supports the Message Passing option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING,
     /// The implementation supports the Monotonic Clock option.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        solarish,
+        apple_targets,
         target_os = "openbsd",
-        target_os = "solaris"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Prioritized Input and Output option.
     _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO,
     /// The implementation supports the Process Scheduling option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "ios",
+        freebsdlike,
+        solarish,
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd",
-        target_os = "solaris"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Raw Sockets option.
     _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "ios",
+        bsd,
+        solarish,
         target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd",
-        target_os = "solaris"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports read-write locks.
     _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        apple_targets,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports realtime signals.
     _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "ios",
+        bsd,
+        solarish,
         target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd",
-        target_os = "solaris"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Regular Expression Handling option.
     _POSIX_REGEXP = libc::_SC_REGEXP,
     /// Each process has a saved set-user-ID and a saved set-group-ID.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS,
     /// The implementation supports semaphores.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES,
     /// The implementation supports the Shared Memory Objects option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux",))]
     /// The implementation supports the POSIX shell.
     _POSIX_SHELL = libc::_SC_SHELL,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux",))]
     /// The implementation supports the Spawn option.
     _POSIX_SPAWN = libc::_SC_SPAWN,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux",))]
     /// The implementation supports spin locks.
     _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
+        freebsdlike,
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Process Sporadic Server option.
     _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER,
+    /// The number of replenishment operations that can be simultaneously pending for a particular
+    /// sporadic server scheduler.
     #[cfg(any(
-        target_os = "ios",
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX,
     /// The implementation supports the Synchronized Input and Output option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO,
     /// The implementation supports the Thread Stack Address Attribute option.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR,
     /// The implementation supports the Thread Stack Size Attribute option.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE,
     #[cfg(any(
-        target_os = "ios",
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
+        netbsdlike,
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Thread CPU-Time Clocks option.
     _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME,
     /// The implementation supports the Non-Robust Mutex Priority Inheritance
     /// option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT,
     /// The implementation supports the Non-Robust Mutex Priority Protection option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT,
     /// The implementation supports the Thread Execution Scheduling option.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux"))]
     /// The implementation supports the Thread Process-Shared Synchronization
     /// option.
     _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED,
@@ -2679,7 +2490,6 @@
         target_os = "linux",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Robust Mutex Priority Inheritance option.
     _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT,
     #[cfg(any(
@@ -2687,484 +2497,319 @@
         target_os = "linux",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Robust Mutex Priority Protection option.
     _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT,
     /// The implementation supports thread-safe functions.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
+        freebsdlike,
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Thread Sporadic Server option.
     _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER,
     /// The implementation supports threads.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_THREADS = libc::_SC_THREADS,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
+        freebsdlike,
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports timeouts.
     _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS,
     /// The implementation supports timers.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_TIMERS = libc::_SC_TIMERS,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
+        freebsdlike,
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Trace option.
     _POSIX_TRACE = libc::_SC_TRACE,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
+        freebsdlike,
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Trace Event Filter option.
     _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER,
+    /// Maximum size of a trace event name in characters.
     #[cfg(any(
-        target_os = "ios",
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
+        freebsdlike,
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Trace Inherit option.
     _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
+        freebsdlike,
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Trace Log option.
     _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG,
+    /// The length in bytes of a trace generation version string or a trace stream name.
     #[cfg(any(
-        target_os = "ios",
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX,
+    /// Maximum number of times `posix_trace_create` may be called from the same or different
+    /// processes.
     #[cfg(any(
-        target_os = "ios",
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX,
+    /// Maximum number of user trace event type identifiers for a single process.
     #[cfg(any(
-        target_os = "ios",
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
+        freebsdlike,
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Typed Memory Objects option.
     _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS,
     /// Integer value indicating version of this standard (C-language binding)
     /// to which the implementation conforms. For implementations conforming to
     /// POSIX.1-2008, the value shall be 200809L.
     _POSIX_VERSION = libc::_SC_VERSION,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux"))]
     /// The implementation provides a C-language compilation environment with
     /// 32-bit `int`, `long`, `pointer`, and `off_t` types.
     _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux"))]
     /// The implementation provides a C-language compilation environment with
     /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at
     /// least 64 bits.
     _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux"))]
     /// The implementation provides a C-language compilation environment with
     /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types.
     _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux"))]
     /// The implementation provides a C-language compilation environment with an
     /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types
     /// using at least 64 bits.
     _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG,
     /// The implementation supports the C-Language Binding option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX2_C_BIND = libc::_SC_2_C_BIND,
     /// The implementation supports the C-Language Development Utilities option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX2_C_DEV = libc::_SC_2_C_DEV,
     /// The implementation supports the Terminal Characteristics option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM,
     /// The implementation supports the FORTRAN Development Utilities option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV,
     /// The implementation supports the FORTRAN Runtime Utilities option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN,
     /// The implementation supports the creation of locales by the localedef
     /// utility.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux"))]
     /// The implementation supports the Batch Environment Services and Utilities
     /// option.
     _POSIX2_PBS = libc::_SC_2_PBS,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux"))]
     /// The implementation supports the Batch Accounting option.
     _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux"))]
     /// The implementation supports the Batch Checkpoint/Restart option.
     _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux"))]
     /// The implementation supports the Locate Batch Job Request option.
     _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux"))]
     /// The implementation supports the Batch Job Message Request option.
     _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    #[cfg(any(bsd, target_os = "linux"))]
     /// The implementation supports the Track Batch Job Request option.
     _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK,
     /// The implementation supports the Software Development Utilities option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX2_SW_DEV = libc::_SC_2_SW_DEV,
     /// The implementation supports the User Portability Utilities option.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX2_UPE = libc::_SC_2_UPE,
     /// Integer value indicating version of the Shell and Utilities volume of
     /// POSIX.1 to which the implementation conforms.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _POSIX2_VERSION = libc::_SC_2_VERSION,
     /// The size of a system page in bytes.
     ///
     /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two
     /// enum constants to have the same value, so nix omits `PAGESIZE`.
     PAGE_SIZE = libc::_SC_PAGE_SIZE,
+    /// Maximum number of attempts made to destroy a thread's thread-specific data values on thread
+    /// exit.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS,
+    /// Maximum number of data keys that can be created by a process.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX,
+    /// Minimum size in bytes of thread stack storage.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN,
+    /// Maximum number of threads that can be created per process.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX,
+    /// The maximum number of repeated occurrences of a regular expression permitted when using
+    /// interval notation.
     #[cfg(not(target_os = "haiku"))]
     RE_DUP_MAX = libc::_SC_RE_DUP_MAX,
+    /// Maximum number of realtime signals reserved for application use.
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        apple_targets,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     RTSIG_MAX = libc::_SC_RTSIG_MAX,
+    /// Maximum number of semaphores that a process may have.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX,
+    /// The maximum value a semaphore may have.
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        apple_targets,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX,
+    /// Maximum number of queued signals that a process may send and have pending at the
+    /// receiver(s) at any time.
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        apple_targets,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX,
+    /// The minimum maximum number of streams that a process may have open at any one time.
     STREAM_MAX = libc::_SC_STREAM_MAX,
-    #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "netbsd",
-        target_os = "openbsd"
-    ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    /// Maximum number of symbolic links that can be reliably traversed in the resolution of a
+    /// pathname in the absence of a loop.
+    #[cfg(any(bsd, target_os = "linux"))]
     SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX,
+    /// Maximum number of timers per process supported.
     #[cfg(not(target_os = "redox"))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     TIMER_MAX = libc::_SC_TIMER_MAX,
+    /// Maximum length of terminal device name.
     TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX,
+    /// The minimum maximum number of types supported for the name of a timezone.
     TZNAME_MAX = libc::_SC_TZNAME_MAX,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        apple_targets,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the X/Open Encryption Option Group.
     _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        apple_targets,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the Issue 4, Version 2 Enhanced
     /// Internationalization Option Group.
     _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        apple_targets,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
+    /// The implementation supports the XOpen Legacy Option group.
+    ///
+    /// See Also <https://pubs.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap02.html>
     _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        apple_targets,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the X/Open Realtime Option Group.
     _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        apple_targets,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the X/Open Realtime Threads Option Group.
     _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS,
     /// The implementation supports the Issue 4, Version 2 Shared Memory Option
     /// Group.
     #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     _XOPEN_SHM = libc::_SC_XOPEN_SHM,
     #[cfg(any(
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
+        freebsdlike,
+        apple_targets,
         target_os = "linux",
-        target_os = "macos",
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the XSI STREAMS Option Group.
     _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        apple_targets,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// The implementation supports the XSI option
     _XOPEN_UNIX = libc::_SC_XOPEN_UNIX,
     #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
+        linux_android,
+        freebsdlike,
+        apple_targets,
         target_os = "openbsd"
     ))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     /// Integer value indicating version of the X/Open Portability Guide to
     /// which the implementation conforms.
     _XOPEN_VERSION = libc::_SC_XOPEN_VERSION,
     /// The number of pages of physical memory. Note that it is possible for
     /// the product of this value to overflow.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     _PHYS_PAGES = libc::_SC_PHYS_PAGES,
     /// The number of currently available pages of physical memory.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     _AVPHYS_PAGES = libc::_SC_AVPHYS_PAGES,
     /// The number of processors configured.
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     _NPROCESSORS_CONF = libc::_SC_NPROCESSORS_CONF,
     /// The number of processors currently online (available).
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     _NPROCESSORS_ONLN = libc::_SC_NPROCESSORS_ONLN,
 }
 
@@ -3190,7 +2835,7 @@
         libc::sysconf(var as c_int)
     };
     if raw == -1 {
-        if errno::errno() == 0 {
+        if Errno::last_raw() == 0 {
             Ok(None)
         } else {
             Err(Errno::last())
@@ -3201,12 +2846,15 @@
 }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[cfg(feature = "fs")]
 mod pivot_root {
     use crate::errno::Errno;
     use crate::{NixPath, Result};
 
+    /// Change the root file system.
+    ///
+    /// See Also [`pivot_root`](https://man7.org/linux/man-pages/man2/pivot_root.2.html)
     pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
         new_root: &P1,
         put_old: &P2,
@@ -3225,13 +2873,7 @@
     }
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "openbsd"
-))]
+#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))]
 mod setres {
     feature! {
     #![feature = "user"]
@@ -3276,13 +2918,7 @@
     }
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "openbsd"
-))]
+#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))]
 mod getres {
     feature! {
     #![feature = "user"]
@@ -3294,16 +2930,22 @@
     /// Real, effective and saved user IDs.
     #[derive(Debug, Copy, Clone, Eq, PartialEq)]
     pub struct ResUid {
+        /// Real UID
         pub real: Uid,
+        /// Effective UID
         pub effective: Uid,
+        /// Saved UID
         pub saved: Uid,
     }
 
     /// Real, effective and saved group IDs.
     #[derive(Debug, Copy, Clone, Eq, PartialEq)]
     pub struct ResGid {
+        /// Real GID
         pub real: Gid,
+        /// Effective GID
         pub effective: Gid,
+        /// Saved GID
         pub saved: Gid,
     }
 
@@ -3318,9 +2960,9 @@
     ///
     #[inline]
     pub fn getresuid() -> Result<ResUid> {
-        let mut ruid = libc::uid_t::max_value();
-        let mut euid = libc::uid_t::max_value();
-        let mut suid = libc::uid_t::max_value();
+        let mut ruid = libc::uid_t::MAX;
+        let mut euid = libc::uid_t::MAX;
+        let mut suid = libc::uid_t::MAX;
         let res = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) };
 
         Errno::result(res).map(|_| ResUid {
@@ -3341,9 +2983,9 @@
     ///
     #[inline]
     pub fn getresgid() -> Result<ResGid> {
-        let mut rgid = libc::gid_t::max_value();
-        let mut egid = libc::gid_t::max_value();
-        let mut sgid = libc::gid_t::max_value();
+        let mut rgid = libc::gid_t::MAX;
+        let mut egid = libc::gid_t::MAX;
+        let mut sgid = libc::gid_t::MAX;
         let res = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) };
 
         Errno::result(res).map(|_| ResGid {
@@ -3355,6 +2997,62 @@
     }
 }
 
+#[cfg(feature = "process")]
+#[cfg(target_os = "freebsd")]
+libc_bitflags! {
+    /// Flags for [`rfork`]
+    ///
+    /// subset of flags supported by FreeBSD 12.x and onwards
+    /// with a safe outcome, thus as `RFMEM` can possibly lead to undefined behavior,
+    /// it is not in the list. And `rfork_thread` is deprecated.
+    pub struct RforkFlags: libc::c_int {
+        /// creates a new process.
+        RFPROC;
+        /// the child process will detach from the parent.
+        /// however, no status will be emitted at child's exit.
+        RFNOWAIT;
+        /// the file descriptor's table will be copied
+        RFFDG;
+        /// a new file descriptor's table will be created
+        RFCFDG;
+        /// force sharing the sigacts structure between
+        /// the child and the parent.
+        RFSIGSHARE;
+        /// enables kernel thread support.
+        RFTHREAD;
+        /// sets a status to emit at child's exit.
+        RFTSIGZMB;
+        /// linux's behavior compatibility setting.
+        /// emits SIGUSR1 as opposed to SIGCHLD upon child's exit.
+        RFLINUXTHPN;
+    }
+}
+
+feature! {
+#![feature = "process"]
+#[cfg(target_os = "freebsd")]
+/// Like [`fork`], `rfork` can be used to have a tigher control about which
+/// resources child and parent process will be sharing, file descriptors,
+/// address spaces and child exit's behavior.
+///
+/// # Safety
+///
+/// The same restrictions apply as for [`fork`].
+///
+/// # See Also
+///
+/// * [rfork(2)](https://man.freebsd.org/cgi/man.cgi?query=rfork)
+pub unsafe fn rfork(flags: RforkFlags) -> Result<ForkResult> {
+    use ForkResult::*;
+    let res = unsafe { libc::rfork(flags.bits()) };
+
+    Errno::result(res).map(|res| match res {
+        0 => Child,
+        res => Parent { child: Pid(res) },
+    })
+}
+}
+
 #[cfg(feature = "fs")]
 libc_bitflags! {
     /// Options for access()
@@ -3419,9 +3117,8 @@
 /// * [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(
+    freebsdlike,
     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 {
@@ -3460,39 +3157,33 @@
     pub shell: PathBuf,
     /// Login class
     #[cfg(not(any(
+        linux_android,
+        solarish,
         target_os = "aix",
-        target_os = "android",
         target_os = "fuchsia",
         target_os = "haiku",
-        target_os = "illumos",
-        target_os = "linux",
-        target_os = "solaris"
+        target_os = "hurd",
     )))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub class: CString,
     /// Last password change
     #[cfg(not(any(
+        linux_android,
+        solarish,
         target_os = "aix",
-        target_os = "android",
         target_os = "fuchsia",
         target_os = "haiku",
-        target_os = "illumos",
-        target_os = "linux",
-        target_os = "solaris"
+        target_os = "hurd",
     )))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub change: libc::time_t,
     /// Expiration time of account
     #[cfg(not(any(
+        linux_android,
+        solarish,
         target_os = "aix",
-        target_os = "android",
         target_os = "fuchsia",
         target_os = "haiku",
-        target_os = "illumos",
-        target_os = "linux",
-        target_os = "solaris"
+        target_os = "hurd",
     )))]
-    #[cfg_attr(docsrs, doc(cfg(all())))]
     pub expire: libc::time_t,
 }
 
@@ -3539,34 +3230,31 @@
                 uid: Uid::from_raw(pw.pw_uid),
                 gid: Gid::from_raw(pw.pw_gid),
                 #[cfg(not(any(
+                    linux_android,
+                    solarish,
                     target_os = "aix",
-                    target_os = "android",
                     target_os = "fuchsia",
                     target_os = "haiku",
-                    target_os = "illumos",
-                    target_os = "linux",
-                    target_os = "solaris"
+                    target_os = "hurd",
                 )))]
                 class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes())
                     .unwrap(),
                 #[cfg(not(any(
+                    linux_android,
+                    solarish,
                     target_os = "aix",
-                    target_os = "android",
                     target_os = "fuchsia",
                     target_os = "haiku",
-                    target_os = "illumos",
-                    target_os = "linux",
-                    target_os = "solaris"
+                    target_os = "hurd",
                 )))]
                 change: pw.pw_change,
                 #[cfg(not(any(
+                    linux_android,
+                    solarish,
                     target_os = "aix",
-                    target_os = "android",
                     target_os = "fuchsia",
                     target_os = "haiku",
-                    target_os = "illumos",
-                    target_os = "linux",
-                    target_os = "solaris"
+                    target_os = "hurd",
                 )))]
                 expire: pw.pw_expire,
             }
@@ -3602,40 +3290,37 @@
             pw_uid: u.uid.0,
             pw_gid: u.gid.0,
             #[cfg(not(any(
+                linux_android,
+                solarish,
                 target_os = "aix",
-                target_os = "android",
                 target_os = "fuchsia",
                 target_os = "haiku",
-                target_os = "illumos",
-                target_os = "linux",
-                target_os = "solaris"
+                target_os = "hurd",
             )))]
             pw_class: u.class.into_raw(),
             #[cfg(not(any(
+                linux_android,
+                solarish,
                 target_os = "aix",
-                target_os = "android",
                 target_os = "fuchsia",
                 target_os = "haiku",
-                target_os = "illumos",
-                target_os = "linux",
-                target_os = "solaris"
+                target_os = "hurd",
             )))]
             pw_change: u.change,
             #[cfg(not(any(
+                linux_android,
+                solarish,
                 target_os = "aix",
-                target_os = "android",
                 target_os = "fuchsia",
                 target_os = "haiku",
-                target_os = "illumos",
-                target_os = "linux",
-                target_os = "solaris"
+                target_os = "hurd",
             )))]
             pw_expire: u.expire,
-            #[cfg(target_os = "illumos")]
+            #[cfg(solarish)]
             pw_age: CString::new("").unwrap().into_raw(),
-            #[cfg(target_os = "illumos")]
+            #[cfg(solarish)]
             pw_comment: CString::new("").unwrap().into_raw(),
-            #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+            #[cfg(freebsdlike)]
             pw_fields: 0,
         }
     }
@@ -3680,7 +3365,7 @@
                 } else {
                     // SAFETY: `f` guarantees that `pwd` is initialized if `res`
                     // is not null.
-                    let pwd = pwd.assume_init();
+                    let pwd = unsafe { pwd.assume_init() };
                     return Ok(Some(User::from(&pwd)));
                 }
             } else if Errno::last() == Errno::ERANGE {
@@ -3790,18 +3475,17 @@
         let mut ret = Vec::new();
 
         for i in 0.. {
-            let u = mem.offset(i);
-            if (*u).is_null() {
+            let u = unsafe { mem.offset(i).read_unaligned() };
+            if u.is_null() {
                 break;
             } else {
-                let s = CStr::from_ptr(*u).to_string_lossy().into_owned();
+                let s = unsafe {CStr::from_ptr(u).to_string_lossy().into_owned()};
                 ret.push(s);
             }
         }
 
         ret
     }
-
     /// # Safety
     ///
     /// If `f` writes to its `*mut *mut libc::group` parameter, then it must
@@ -3839,7 +3523,7 @@
                 } else {
                     // SAFETY: `f` guarantees that `grp` is initialized if `res`
                     // is not null.
-                    let grp = grp.assume_init();
+                    let grp = unsafe { grp.assume_init() };
                     return Ok(Some(Group::from(&grp)));
                 }
             } else if Errno::last() == Errno::ERANGE {
@@ -3913,19 +3597,22 @@
 /// Get the name of the terminal device that is open on file descriptor fd
 /// (see [`ttyname(3)`](https://man7.org/linux/man-pages/man3/ttyname.3.html)).
 #[cfg(not(target_os = "fuchsia"))]
-pub fn ttyname(fd: RawFd) -> Result<PathBuf> {
+pub fn ttyname<F: AsFd>(fd: F) -> Result<PathBuf> {
+    #[cfg(not(target_os = "hurd"))]
     const PATH_MAX: usize = libc::PATH_MAX as usize;
+    #[cfg(target_os = "hurd")]
+    const PATH_MAX: usize = 1024; // Hurd does not define a hard limit, so try a guess first
     let mut buf = vec![0_u8; PATH_MAX];
-    let c_buf = buf.as_mut_ptr() as *mut libc::c_char;
+    let c_buf = buf.as_mut_ptr().cast();
 
-    let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) };
+    let ret = unsafe { libc::ttyname_r(fd.as_fd().as_raw_fd(), c_buf, buf.len()) };
     if ret != 0 {
-        return Err(Errno::from_i32(ret));
+        return Err(Errno::from_raw(ret));
     }
 
-    let nul = buf.iter().position(|c| *c == b'\0').unwrap();
-    buf.truncate(nul);
-    Ok(OsString::from_vec(buf).into())
+    CStr::from_bytes_until_nul(&buf[..])
+        .map(|s| OsStr::from_bytes(s.to_bytes()).into())
+        .map_err(|_| Errno::EINVAL)
 }
 }
 
@@ -3935,19 +3622,12 @@
 /// Get the effective user ID and group ID associated with a Unix domain socket.
 ///
 /// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid)
-#[cfg(any(
-    target_os = "macos",
-    target_os = "ios",
-    target_os = "freebsd",
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "dragonfly",
-))]
-pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> {
+#[cfg(bsd)]
+pub fn getpeereid<F: AsFd>(fd: F) -> Result<(Uid, Gid)> {
     let mut uid = 1;
     let mut gid = 1;
 
-    let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) };
+    let ret = unsafe { libc::getpeereid(fd.as_fd().as_raw_fd(), &mut uid, &mut gid) };
 
     Errno::result(ret).map(|_| (Uid(uid), Gid(gid)))
 }
@@ -3959,14 +3639,7 @@
 /// Set the file flags.
 ///
 /// See also [chflags(2)](https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2)
-#[cfg(any(
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "freebsd",
-    target_os = "dragonfly",
-    target_os = "macos",
-    target_os = "ios"
-))]
+#[cfg(bsd)]
 pub fn chflags<P: ?Sized + NixPath>(path: &P, flags: FileFlag) -> Result<()> {
     let res = path.with_nix_path(|cstr| unsafe {
         libc::chflags(cstr.as_ptr(), flags.bits())
diff --git a/test/common/mod.rs b/test/common/mod.rs
index bb056aa..db4aed2 100644
--- a/test/common/mod.rs
+++ b/test/common/mod.rs
@@ -2,18 +2,18 @@
 
 #[macro_export]
 macro_rules! skip {
-    ($($reason: expr),+) => {
+    ($($reason: expr),+) => {{
         use ::std::io::{self, Write};
 
         let stderr = io::stderr();
         let mut handle = stderr.lock();
         writeln!(handle, $($reason),+).unwrap();
         return;
-    }
+    }}
 }
 
 cfg_if! {
-    if #[cfg(any(target_os = "android", target_os = "linux"))] {
+    if #[cfg(linux_android)] {
         #[macro_export] macro_rules! require_capability {
             ($name:expr, $capname:ident) => {
                 use ::caps::{Capability, CapSet, has_cap};
@@ -51,7 +51,7 @@
     };
 }
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[macro_export]
 macro_rules! skip_if_cirrus {
     ($reason:expr) => {
@@ -87,7 +87,7 @@
 }
 
 cfg_if! {
-    if #[cfg(any(target_os = "android", target_os = "linux"))] {
+    if #[cfg(linux_android)] {
         #[macro_export] macro_rules! skip_if_seccomp {
             ($name:expr) => {
                 if let Ok(s) = std::fs::read_to_string("/proc/self/status") {
diff --git a/test/sys/mod.rs b/test/sys/mod.rs
index 2031212..fb3f6be 100644
--- a/test/sys/mod.rs
+++ b/test/sys/mod.rs
@@ -7,16 +7,16 @@
 // cases on DragonFly.
 #[cfg(any(
     target_os = "freebsd",
-    target_os = "ios",
+    apple_targets,
     all(target_os = "linux", not(target_env = "uclibc")),
-    target_os = "macos",
     target_os = "netbsd"
 ))]
 mod test_aio;
 #[cfg(not(any(
     target_os = "redox",
     target_os = "fuchsia",
-    target_os = "haiku"
+    target_os = "haiku",
+    target_os = "hurd"
 )))]
 mod test_ioctl;
 #[cfg(not(target_os = "redox"))]
@@ -30,7 +30,7 @@
 #[cfg(not(any(target_os = "redox")))]
 mod test_sockopt;
 mod test_stat;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 mod test_sysinfo;
 #[cfg(not(any(
     target_os = "redox",
@@ -41,20 +41,44 @@
 mod test_uio;
 mod test_wait;
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 mod test_epoll;
 #[cfg(target_os = "linux")]
+mod test_fanotify;
+#[cfg(target_os = "linux")]
 mod test_inotify;
 mod test_pthread;
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd"
-))]
+
+#[cfg(any(linux_android, freebsdlike, netbsdlike, apple_targets))]
 mod test_ptrace;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 mod test_timerfd;
+
+#[cfg(all(
+    any(
+        target_os = "freebsd",
+        solarish,
+        target_os = "linux",
+        target_os = "netbsd"
+    ),
+    feature = "time",
+    feature = "signal"
+))]
+mod test_timer;
+
+#[cfg(bsd)]
+mod test_event;
+mod test_statvfs;
+mod test_time;
+mod test_utsname;
+
+#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "openbsd"))]
+mod test_statfs;
+
+#[cfg(not(any(
+    target_os = "redox",
+    target_os = "fuchsia",
+    solarish,
+    target_os = "haiku"
+)))]
+mod test_resource;
diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs
index 5035b5a..ba5ad02 100644
--- a/test/sys/test_aio.rs
+++ b/test/sys/test_aio.rs
@@ -67,7 +67,7 @@
     // Skip on Linux, because Linux's AIO implementation can't detect errors
     // synchronously
     #[test]
-    #[cfg(any(target_os = "freebsd", target_os = "macos"))]
+    #[cfg(any(target_os = "freebsd", apple_targets))]
     fn error() {
         use std::mem;
 
@@ -157,7 +157,7 @@
     // Skip on Linux, because Linux's AIO implementation can't detect errors
     // synchronously
     #[test]
-    #[cfg(any(target_os = "freebsd", target_os = "macos"))]
+    #[cfg(any(target_os = "freebsd", apple_targets))]
     fn error() {
         const INITIAL: &[u8] = b"abcdef123456";
         let mut rbuf = vec![0; 4];
@@ -411,7 +411,7 @@
     // Skip on Linux, because Linux's AIO implementation can't detect errors
     // synchronously
     #[test]
-    #[cfg(any(target_os = "freebsd", target_os = "macos"))]
+    #[cfg(any(target_os = "freebsd", apple_targets))]
     fn error() {
         let wbuf = "CDEF".to_string().into_bytes();
         let mut aiow = Box::pin(AioWrite::new(
@@ -498,7 +498,9 @@
     any(
         all(target_env = "musl", target_arch = "x86_64"),
         target_arch = "mips",
-        target_arch = "mips64"
+        target_arch = "mips32r6",
+        target_arch = "mips64",
+        target_arch = "mips64r6"
     ),
     ignore
 )]
@@ -567,12 +569,6 @@
 }
 
 #[test]
-// On Cirrus on Linux, this test fails due to a glibc bug.
-// https://github.com/nix-rust/nix/issues/1099
-#[cfg_attr(target_os = "linux", ignore)]
-// On Cirrus, aio_suspend is failing with EINVAL
-// https://github.com/nix-rust/nix/issues/1361
-#[cfg_attr(target_os = "macos", ignore)]
 fn test_aio_suspend() {
     const INITIAL: &[u8] = b"abcdef123456";
     const WBUF: &[u8] = b"CDEFG";
@@ -622,3 +618,53 @@
     assert_eq!(wcb.as_mut().aio_return().unwrap(), WBUF.len());
     assert_eq!(rcb.as_mut().aio_return().unwrap(), rlen);
 }
+
+/// aio_suspend relies on casting Rust Aio* struct pointers to libc::aiocb
+/// pointers.  This test ensures that such casts are valid.
+#[test]
+fn casting() {
+    let sev = SigevNotify::SigevNone;
+    let aiof = AioFsync::new(666, AioFsyncMode::O_SYNC, 0, sev);
+    assert_eq!(
+        aiof.as_ref() as *const libc::aiocb,
+        &aiof as *const AioFsync as *const libc::aiocb
+    );
+
+    let mut rbuf = [];
+    let aior = AioRead::new(666, 0, &mut rbuf, 0, sev);
+    assert_eq!(
+        aior.as_ref() as *const libc::aiocb,
+        &aior as *const AioRead as *const libc::aiocb
+    );
+
+    let wbuf = [];
+    let aiow = AioWrite::new(666, 0, &wbuf, 0, sev);
+    assert_eq!(
+        aiow.as_ref() as *const libc::aiocb,
+        &aiow as *const AioWrite as *const libc::aiocb
+    );
+}
+
+#[cfg(target_os = "freebsd")]
+#[test]
+fn casting_vectored() {
+    use std::io::{IoSlice, IoSliceMut};
+
+    let sev = SigevNotify::SigevNone;
+
+    let mut rbuf = [];
+    let mut rbufs = [IoSliceMut::new(&mut rbuf)];
+    let aiorv = AioReadv::new(666, 0, &mut rbufs[..], 0, sev);
+    assert_eq!(
+        aiorv.as_ref() as *const libc::aiocb,
+        &aiorv as *const AioReadv as *const libc::aiocb
+    );
+
+    let wbuf = [];
+    let wbufs = [IoSlice::new(&wbuf)];
+    let aiowv = AioWritev::new(666, 0, &wbufs, 0, sev);
+    assert_eq!(
+        aiowv.as_ref() as *const libc::aiocb,
+        &aiowv as *const AioWritev as *const libc::aiocb
+    );
+}
diff --git a/test/sys/test_aio_drop.rs b/test/sys/test_aio_drop.rs
index bbe6623..54106dd 100644
--- a/test/sys/test_aio_drop.rs
+++ b/test/sys/test_aio_drop.rs
@@ -8,8 +8,7 @@
     not(target_env = "uclibc"),
     any(
         target_os = "linux",
-        target_os = "ios",
-        target_os = "macos",
+        apple_targets,
         target_os = "freebsd",
         target_os = "netbsd"
     )
diff --git a/test/sys/test_event.rs b/test/sys/test_event.rs
new file mode 100644
index 0000000..a10b1e5
--- /dev/null
+++ b/test/sys/test_event.rs
@@ -0,0 +1,41 @@
+use libc::intptr_t;
+use nix::sys::event::{EventFilter, EventFlag, FilterFlag, KEvent};
+
+#[test]
+fn test_struct_kevent() {
+    use std::mem;
+
+    let udata: intptr_t = 12345;
+    let data: intptr_t = 0x1337;
+
+    let actual = KEvent::new(
+        0xdead_beef,
+        EventFilter::EVFILT_READ,
+        EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
+        FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
+        data,
+        udata,
+    );
+    assert_eq!(0xdead_beef, actual.ident());
+    assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap());
+    assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits());
+    assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits());
+    assert_eq!(data, actual.data());
+    assert_eq!(udata, actual.udata());
+    assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>());
+}
+
+#[test]
+fn test_kevent_filter() {
+    let udata: intptr_t = 12345;
+
+    let actual = KEvent::new(
+        0xdead_beef,
+        EventFilter::EVFILT_READ,
+        EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
+        FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
+        0x1337,
+        udata,
+    );
+    assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap());
+}
diff --git a/test/sys/test_fanotify.rs b/test/sys/test_fanotify.rs
new file mode 100644
index 0000000..20226c2
--- /dev/null
+++ b/test/sys/test_fanotify.rs
@@ -0,0 +1,149 @@
+use crate::*;
+use nix::sys::fanotify::{
+    EventFFlags, Fanotify, FanotifyResponse, InitFlags, MarkFlags, MaskFlags,
+    Response,
+};
+use std::fs::{read_link, File, OpenOptions};
+use std::io::ErrorKind;
+use std::io::{Read, Write};
+use std::os::fd::AsRawFd;
+use std::thread;
+
+#[test]
+/// Run fanotify tests sequentially to avoid tmp files races
+pub fn test_fanotify() {
+    require_capability!("test_fanotify", CAP_SYS_ADMIN);
+
+    test_fanotify_notifications();
+    test_fanotify_responses();
+}
+
+fn test_fanotify_notifications() {
+    let group =
+        Fanotify::init(InitFlags::FAN_CLASS_NOTIF, EventFFlags::O_RDONLY)
+            .unwrap();
+    let tempdir = tempfile::tempdir().unwrap();
+    let tempfile = tempdir.path().join("test");
+    OpenOptions::new()
+        .write(true)
+        .create_new(true)
+        .open(&tempfile)
+        .unwrap();
+
+    group
+        .mark(
+            MarkFlags::FAN_MARK_ADD,
+            MaskFlags::FAN_OPEN | MaskFlags::FAN_MODIFY | MaskFlags::FAN_CLOSE,
+            None,
+            Some(&tempfile),
+        )
+        .unwrap();
+
+    // modify test file
+    {
+        let mut f = OpenOptions::new().write(true).open(&tempfile).unwrap();
+        f.write_all(b"hello").unwrap();
+    }
+
+    let mut events = group.read_events().unwrap();
+    assert_eq!(events.len(), 1, "should have read exactly one event");
+    let event = events.pop().unwrap();
+    assert!(event.check_version());
+    assert_eq!(
+        event.mask(),
+        MaskFlags::FAN_OPEN
+            | MaskFlags::FAN_MODIFY
+            | MaskFlags::FAN_CLOSE_WRITE
+    );
+    let fd_opt = event.fd();
+    let fd = fd_opt.as_ref().unwrap();
+    let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap();
+    assert_eq!(path, tempfile);
+
+    // read test file
+    {
+        let mut f = File::open(&tempfile).unwrap();
+        let mut s = String::new();
+        f.read_to_string(&mut s).unwrap();
+    }
+
+    let mut events = group.read_events().unwrap();
+    assert_eq!(events.len(), 1, "should have read exactly one event");
+    let event = events.pop().unwrap();
+    assert!(event.check_version());
+    assert_eq!(
+        event.mask(),
+        MaskFlags::FAN_OPEN | MaskFlags::FAN_CLOSE_NOWRITE
+    );
+    let fd_opt = event.fd();
+    let fd = fd_opt.as_ref().unwrap();
+    let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap();
+    assert_eq!(path, tempfile);
+}
+
+fn test_fanotify_responses() {
+    let group =
+        Fanotify::init(InitFlags::FAN_CLASS_CONTENT, EventFFlags::O_RDONLY)
+            .unwrap();
+    let tempdir = tempfile::tempdir().unwrap();
+    let tempfile = tempdir.path().join("test");
+    OpenOptions::new()
+        .write(true)
+        .create_new(true)
+        .open(&tempfile)
+        .unwrap();
+
+    group
+        .mark(
+            MarkFlags::FAN_MARK_ADD,
+            MaskFlags::FAN_OPEN_PERM,
+            None,
+            Some(&tempfile),
+        )
+        .unwrap();
+
+    let file_thread = thread::spawn({
+        let tempfile = tempfile.clone();
+
+        move || {
+            // first open, should fail
+            let Err(e) = File::open(&tempfile) else {
+                panic!("The first open should fail");
+            };
+            assert_eq!(e.kind(), ErrorKind::PermissionDenied);
+
+            // second open, should succeed
+            File::open(&tempfile).unwrap();
+        }
+    });
+
+    // Deny the first open try
+    let mut events = group.read_events().unwrap();
+    assert_eq!(events.len(), 1, "should have read exactly one event");
+    let event = events.pop().unwrap();
+    assert!(event.check_version());
+    assert_eq!(event.mask(), MaskFlags::FAN_OPEN_PERM);
+    let fd_opt = event.fd();
+    let fd = fd_opt.as_ref().unwrap();
+    let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap();
+    assert_eq!(path, tempfile);
+    group
+        .write_response(FanotifyResponse::new(*fd, Response::FAN_DENY))
+        .unwrap();
+
+    // Allow the second open try
+    let mut events = group.read_events().unwrap();
+    assert_eq!(events.len(), 1, "should have read exactly one event");
+    let event = events.pop().unwrap();
+    assert!(event.check_version());
+    assert_eq!(event.mask(), MaskFlags::FAN_OPEN_PERM);
+    let fd_opt = event.fd();
+    let fd = fd_opt.as_ref().unwrap();
+    let path = read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())).unwrap();
+    assert_eq!(path, tempfile);
+    group
+        .write_response(FanotifyResponse::new(*fd, Response::FAN_ALLOW))
+        .unwrap();
+
+    file_thread.join().unwrap();
+}
diff --git a/test/sys/test_ioctl.rs b/test/sys/test_ioctl.rs
index 40f60cf..08843bf 100644
--- a/test/sys/test_ioctl.rs
+++ b/test/sys/test_ioctl.rs
@@ -28,7 +28,7 @@
 // TODO:  Need a way to compute these constants at test time.  Using precomputed
 // values is fragile and needs to be maintained.
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 mod linux {
     // The cast is not unnecessary on all platforms.
     #[allow(clippy::unnecessary_cast)]
@@ -36,7 +36,9 @@
     fn test_op_none() {
         if cfg!(any(
             target_arch = "mips",
+            target_arch = "mips32r6",
             target_arch = "mips64",
+            target_arch = "mips64r6",
             target_arch = "powerpc",
             target_arch = "powerpc64"
         )) {
@@ -54,7 +56,9 @@
     fn test_op_write() {
         if cfg!(any(
             target_arch = "mips",
+            target_arch = "mips32r6",
             target_arch = "mips64",
+            target_arch = "mips64r6",
             target_arch = "powerpc",
             target_arch = "powerpc64"
         )) {
@@ -69,7 +73,11 @@
     #[cfg(target_pointer_width = "64")]
     #[test]
     fn test_op_write_64() {
-        if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) {
+        if cfg!(any(
+            target_arch = "mips64",
+            target_arch = "mips64r6",
+            target_arch = "powerpc64"
+        )) {
             assert_eq!(
                 request_code_write!(b'z', 10, 1u64 << 32) as u32,
                 0x8000_7A0A
@@ -88,7 +96,9 @@
     fn test_op_read() {
         if cfg!(any(
             target_arch = "mips",
+            target_arch = "mips32r6",
             target_arch = "mips64",
+            target_arch = "mips64r6",
             target_arch = "powerpc",
             target_arch = "powerpc64"
         )) {
@@ -103,7 +113,11 @@
     #[cfg(target_pointer_width = "64")]
     #[test]
     fn test_op_read_64() {
-        if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) {
+        if cfg!(any(
+            target_arch = "mips64",
+            target_arch = "mips64r6",
+            target_arch = "powerpc64"
+        )) {
             assert_eq!(
                 request_code_read!(b'z', 10, 1u64 << 32) as u32,
                 0x4000_7A0A
@@ -134,14 +148,7 @@
     }
 }
 
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd"
-))]
+#[cfg(bsd)]
 mod bsd {
     #[test]
     fn test_op_none() {
@@ -149,7 +156,7 @@
         assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
     }
 
-    #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+    #[cfg(freebsdlike)]
     #[test]
     fn test_op_write_int() {
         assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604);
@@ -193,7 +200,7 @@
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 mod linux_ioctls {
     use std::mem;
     use std::os::unix::io::AsRawFd;
diff --git a/test/sys/test_mman.rs b/test/sys/test_mman.rs
index b4674e5..3689f64 100644
--- a/test/sys/test_mman.rs
+++ b/test/sys/test_mman.rs
@@ -1,44 +1,44 @@
-use nix::sys::mman::{mmap, MapFlags, ProtFlags};
-use std::{num::NonZeroUsize, os::unix::io::BorrowedFd};
+#![allow(clippy::redundant_slicing)]
+
+use nix::sys::mman::{mmap_anonymous, MapFlags, ProtFlags};
+use std::num::NonZeroUsize;
 
 #[test]
 fn test_mmap_anonymous() {
     unsafe {
-        let ptr = mmap::<BorrowedFd>(
+        let mut ptr = mmap_anonymous(
             None,
             NonZeroUsize::new(1).unwrap(),
             ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
-            MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
-            None,
-            0,
+            MapFlags::MAP_PRIVATE,
         )
-        .unwrap() as *mut u8;
-        assert_eq!(*ptr, 0x00u8);
-        *ptr = 0xffu8;
-        assert_eq!(*ptr, 0xffu8);
+        .unwrap()
+        .cast::<u8>();
+        assert_eq!(*ptr.as_ref(), 0x00u8);
+        *ptr.as_mut() = 0xffu8;
+        assert_eq!(*ptr.as_ref(), 0xffu8);
     }
 }
 
 #[test]
 #[cfg(any(target_os = "linux", target_os = "netbsd"))]
 fn test_mremap_grow() {
-    use nix::libc::{c_void, size_t};
+    use nix::libc::size_t;
     use nix::sys::mman::{mremap, MRemapFlags};
+    use std::ptr::NonNull;
 
     const ONE_K: size_t = 1024;
     let one_k_non_zero = NonZeroUsize::new(ONE_K).unwrap();
 
     let slice: &mut [u8] = unsafe {
-        let mem = mmap::<BorrowedFd>(
+        let mem = mmap_anonymous(
             None,
             one_k_non_zero,
             ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
-            MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE,
-            None,
-            0,
+            MapFlags::MAP_PRIVATE,
         )
         .unwrap();
-        std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
+        std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
     };
     assert_eq!(slice[ONE_K - 1], 0x00);
     slice[ONE_K - 1] = 0xFF;
@@ -47,7 +47,7 @@
     let slice: &mut [u8] = unsafe {
         #[cfg(target_os = "linux")]
         let mem = mremap(
-            slice.as_mut_ptr() as *mut c_void,
+            NonNull::from(&mut slice[..]).cast(),
             ONE_K,
             10 * ONE_K,
             MRemapFlags::MREMAP_MAYMOVE,
@@ -56,14 +56,14 @@
         .unwrap();
         #[cfg(target_os = "netbsd")]
         let mem = mremap(
-            slice.as_mut_ptr() as *mut c_void,
+            NonNull::from(&mut slice[..]).cast(),
             ONE_K,
             10 * ONE_K,
             MRemapFlags::MAP_REMAPDUP,
             None,
         )
         .unwrap();
-        std::slice::from_raw_parts_mut(mem as *mut u8, 10 * ONE_K)
+        std::slice::from_raw_parts_mut(mem.cast().as_ptr(), 10 * ONE_K)
     };
 
     // The first KB should still have the old data in it.
@@ -80,23 +80,22 @@
 // Segfaults for unknown reasons under QEMU for 32-bit targets
 #[cfg_attr(all(target_pointer_width = "32", qemu), ignore)]
 fn test_mremap_shrink() {
-    use nix::libc::{c_void, size_t};
+    use nix::libc::size_t;
     use nix::sys::mman::{mremap, MRemapFlags};
     use std::num::NonZeroUsize;
+    use std::ptr::NonNull;
 
     const ONE_K: size_t = 1024;
     let ten_one_k = NonZeroUsize::new(10 * ONE_K).unwrap();
     let slice: &mut [u8] = unsafe {
-        let mem = mmap::<BorrowedFd>(
+        let mem = mmap_anonymous(
             None,
             ten_one_k,
             ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
-            MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE,
-            None,
-            0,
+            MapFlags::MAP_PRIVATE,
         )
         .unwrap();
-        std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
+        std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
     };
     assert_eq!(slice[ONE_K - 1], 0x00);
     slice[ONE_K - 1] = 0xFF;
@@ -104,7 +103,7 @@
 
     let slice: &mut [u8] = unsafe {
         let mem = mremap(
-            slice.as_mut_ptr() as *mut c_void,
+            NonNull::from(&mut slice[..]).cast(),
             ten_one_k.into(),
             ONE_K,
             MRemapFlags::empty(),
@@ -113,8 +112,8 @@
         .unwrap();
         // Since we didn't supply MREMAP_MAYMOVE, the address should be the
         // same.
-        assert_eq!(mem, slice.as_mut_ptr() as *mut c_void);
-        std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
+        assert_eq!(mem.as_ptr(), NonNull::from(&mut slice[..]).cast().as_ptr());
+        std::slice::from_raw_parts_mut(mem.as_ptr().cast(), ONE_K)
     };
 
     // The first KB should still be accessible and have the old data in it.
diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs
index 530560f..246b354 100644
--- a/test/sys/test_ptrace.rs
+++ b/test/sys/test_ptrace.rs
@@ -6,11 +6,11 @@
 use memoffset::offset_of;
 use nix::errno::Errno;
 use nix::sys::ptrace;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 use nix::sys::ptrace::Options;
 use nix::unistd::getpid;
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 use std::mem;
 
 use crate::*;
@@ -28,7 +28,7 @@
 
 // Just make sure ptrace_setoptions can be called at all, for now.
 #[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn test_ptrace_setoptions() {
     require_capability!("test_ptrace_setoptions", CAP_SYS_PTRACE);
     let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD)
@@ -38,7 +38,7 @@
 
 // Just make sure ptrace_getevent can be called at all, for now.
 #[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn test_ptrace_getevent() {
     require_capability!("test_ptrace_getevent", CAP_SYS_PTRACE);
     let err = ptrace::getevent(getpid()).unwrap_err();
@@ -47,7 +47,7 @@
 
 // Just make sure ptrace_getsiginfo can be called at all, for now.
 #[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn test_ptrace_getsiginfo() {
     require_capability!("test_ptrace_getsiginfo", CAP_SYS_PTRACE);
     if let Err(Errno::EOPNOTSUPP) = ptrace::getsiginfo(getpid()) {
@@ -57,7 +57,7 @@
 
 // Just make sure ptrace_setsiginfo can be called at all, for now.
 #[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn test_ptrace_setsiginfo() {
     require_capability!("test_ptrace_setsiginfo", CAP_SYS_PTRACE);
     let siginfo = unsafe { mem::zeroed() };
diff --git a/test/sys/test_resource.rs b/test/sys/test_resource.rs
new file mode 100644
index 0000000..8b12a94
--- /dev/null
+++ b/test/sys/test_resource.rs
@@ -0,0 +1,43 @@
+use nix::sys::resource::{getrlimit, setrlimit, Resource};
+use nix::sys::resource::{getrusage, UsageWho};
+
+/// Tests the RLIMIT_NOFILE functionality of getrlimit(), where the resource RLIMIT_NOFILE refers
+/// to the maximum file descriptor number that can be opened by the process (aka the maximum number
+/// of file descriptors that the process can open, since Linux 4.5).
+///
+/// We first fetch the existing file descriptor maximum values using getrlimit(), then edit the
+/// soft limit to make sure it has a new and distinct value to the hard limit. We then setrlimit()
+/// to put the new soft limit in effect, and then getrlimit() once more to ensure the limits have
+/// been updated.
+#[test]
+pub fn test_resource_limits_nofile() {
+    let (mut soft_limit, hard_limit) =
+        getrlimit(Resource::RLIMIT_NOFILE).unwrap();
+
+    soft_limit -= 1;
+    assert_ne!(soft_limit, hard_limit);
+    setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap();
+
+    let (new_soft_limit, _) = getrlimit(Resource::RLIMIT_NOFILE).unwrap();
+    assert_eq!(new_soft_limit, soft_limit);
+}
+
+#[test]
+pub fn test_self_cpu_time() {
+    // Make sure some CPU time is used.
+    let mut numbers: Vec<i32> = (1..1_000_000).collect();
+    numbers.iter_mut().for_each(|item| *item *= 2);
+
+    // FIXME: this is here to help ensure the compiler does not optimize the whole
+    // thing away. Replace the assert with test::black_box once stabilized.
+    assert_eq!(numbers[100..200].iter().sum::<i32>(), 30_100);
+
+    let usage = getrusage(UsageWho::RUSAGE_SELF)
+        .expect("Failed to call getrusage for SELF");
+    let rusage = usage.as_ref();
+
+    let user = usage.user_time();
+    assert!(user.tv_sec() > 0 || user.tv_usec() > 0);
+    assert_eq!(user.tv_sec(), rusage.ru_utime.tv_sec);
+    assert_eq!(user.tv_usec(), rusage.ru_utime.tv_usec);
+}
diff --git a/test/sys/test_select.rs b/test/sys/test_select.rs
index 79f75de..e39a319 100644
--- a/test/sys/test_select.rs
+++ b/test/sys/test_select.rs
@@ -1,22 +1,20 @@
 use nix::sys::select::*;
 use nix::sys::signal::SigSet;
-use nix::sys::time::{TimeSpec, TimeValLike};
+use nix::sys::time::{TimeSpec, TimeVal, TimeValLike};
 use nix::unistd::{pipe, write};
-use std::os::unix::io::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd};
+use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
 
 #[test]
 pub fn test_pselect() {
     let _mtx = crate::SIGNAL_MTX.lock();
 
     let (r1, w1) = pipe().unwrap();
-    write(w1, b"hi!").unwrap();
-    let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
+    write(&w1, b"hi!").unwrap();
     let (r2, _w2) = pipe().unwrap();
-    let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
 
     let mut fd_set = FdSet::new();
-    fd_set.insert(&r1);
-    fd_set.insert(&r2);
+    fd_set.insert(r1.as_fd());
+    fd_set.insert(r2.as_fd());
 
     let timeout = TimeSpec::seconds(10);
     let sigmask = SigSet::empty();
@@ -24,21 +22,19 @@
         1,
         pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap()
     );
-    assert!(fd_set.contains(&r1));
-    assert!(!fd_set.contains(&r2));
+    assert!(fd_set.contains(r1.as_fd()));
+    assert!(!fd_set.contains(r2.as_fd()));
 }
 
 #[test]
 pub fn test_pselect_nfds2() {
     let (r1, w1) = pipe().unwrap();
-    write(w1, b"hi!").unwrap();
-    let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
+    write(&w1, b"hi!").unwrap();
     let (r2, _w2) = pipe().unwrap();
-    let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
 
     let mut fd_set = FdSet::new();
-    fd_set.insert(&r1);
-    fd_set.insert(&r2);
+    fd_set.insert(r1.as_fd());
+    fd_set.insert(r2.as_fd());
 
     let timeout = TimeSpec::seconds(10);
     assert_eq!(
@@ -53,8 +49,8 @@
         )
         .unwrap()
     );
-    assert!(fd_set.contains(&r1));
-    assert!(!fd_set.contains(&r2));
+    assert!(fd_set.contains(r1.as_fd()));
+    assert!(!fd_set.contains(r2.as_fd()));
 }
 
 macro_rules! generate_fdset_bad_fd_tests {
@@ -64,7 +60,7 @@
             #[should_panic]
             fn $method() {
                 let bad_fd = unsafe{BorrowedFd::borrow_raw($fd)};
-                FdSet::new().$method(&bad_fd);
+                FdSet::new().$method(bad_fd);
             }
         )*
     }
@@ -72,7 +68,6 @@
 
 mod test_fdset_too_large_fd {
     use super::*;
-    use std::convert::TryInto;
     generate_fdset_bad_fd_tests!(
         FD_SETSIZE.try_into().unwrap(),
         insert,
@@ -80,3 +75,219 @@
         contains,
     );
 }
+
+#[test]
+fn fdset_insert() {
+    let mut fd_set = FdSet::new();
+
+    for i in 0..FD_SETSIZE {
+        let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+        assert!(!fd_set.contains(borrowed_i));
+    }
+
+    let fd_seven = unsafe { BorrowedFd::borrow_raw(7) };
+    fd_set.insert(fd_seven);
+
+    assert!(fd_set.contains(fd_seven));
+}
+
+#[test]
+fn fdset_remove() {
+    let mut fd_set = FdSet::new();
+
+    for i in 0..FD_SETSIZE {
+        let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+        assert!(!fd_set.contains(borrowed_i));
+    }
+
+    let fd_seven = unsafe { BorrowedFd::borrow_raw(7) };
+    fd_set.insert(fd_seven);
+    fd_set.remove(fd_seven);
+
+    for i in 0..FD_SETSIZE {
+        let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+        assert!(!fd_set.contains(borrowed_i));
+    }
+}
+
+#[test]
+#[allow(non_snake_case)]
+fn fdset_clear() {
+    let mut fd_set = FdSet::new();
+    let fd_one = unsafe { BorrowedFd::borrow_raw(1) };
+    let fd_FD_SETSIZE_divided_by_two =
+        unsafe { BorrowedFd::borrow_raw((FD_SETSIZE / 2) as RawFd) };
+    let fd_FD_SETSIZE_minus_one =
+        unsafe { BorrowedFd::borrow_raw((FD_SETSIZE - 1) as RawFd) };
+    fd_set.insert(fd_one);
+    fd_set.insert(fd_FD_SETSIZE_divided_by_two);
+    fd_set.insert(fd_FD_SETSIZE_minus_one);
+
+    fd_set.clear();
+
+    for i in 0..FD_SETSIZE {
+        let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+        assert!(!fd_set.contains(borrowed_i));
+    }
+}
+
+#[test]
+fn fdset_highest() {
+    let mut set = FdSet::new();
+    assert_eq!(
+        set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+        None
+    );
+    let fd_zero = unsafe { BorrowedFd::borrow_raw(0) };
+    let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) };
+    set.insert(fd_zero);
+    assert_eq!(
+        set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+        Some(0)
+    );
+    set.insert(fd_ninety);
+    assert_eq!(
+        set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+        Some(90)
+    );
+    set.remove(fd_zero);
+    assert_eq!(
+        set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+        Some(90)
+    );
+    set.remove(fd_ninety);
+    assert_eq!(
+        set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+        None
+    );
+
+    let fd_four = unsafe { BorrowedFd::borrow_raw(4) };
+    let fd_five = unsafe { BorrowedFd::borrow_raw(5) };
+    let fd_seven = unsafe { BorrowedFd::borrow_raw(7) };
+    set.insert(fd_four);
+    set.insert(fd_five);
+    set.insert(fd_seven);
+    assert_eq!(
+        set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+        Some(7)
+    );
+}
+
+#[test]
+fn fdset_fds() {
+    let mut set = FdSet::new();
+    let fd_zero = unsafe { BorrowedFd::borrow_raw(0) };
+    let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) };
+    assert_eq!(
+        set.fds(None)
+            .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+            .collect::<Vec<_>>(),
+        vec![]
+    );
+    set.insert(fd_zero);
+    assert_eq!(
+        set.fds(None)
+            .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+            .collect::<Vec<_>>(),
+        vec![0]
+    );
+    set.insert(fd_ninety);
+    assert_eq!(
+        set.fds(None)
+            .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+            .collect::<Vec<_>>(),
+        vec![0, 90]
+    );
+
+    // highest limit
+    assert_eq!(
+        set.fds(Some(89))
+            .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+            .collect::<Vec<_>>(),
+        vec![0]
+    );
+    assert_eq!(
+        set.fds(Some(90))
+            .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+            .collect::<Vec<_>>(),
+        vec![0, 90]
+    );
+}
+
+#[test]
+fn test_select() {
+    let (r1, w1) = pipe().unwrap();
+    let (r2, _w2) = pipe().unwrap();
+
+    write(&w1, b"hi!").unwrap();
+    let mut fd_set = FdSet::new();
+    fd_set.insert(r1.as_fd());
+    fd_set.insert(r2.as_fd());
+
+    let mut timeout = TimeVal::seconds(10);
+    assert_eq!(
+        1,
+        select(None, &mut fd_set, None, None, &mut timeout).unwrap()
+    );
+    assert!(fd_set.contains(r1.as_fd()));
+    assert!(!fd_set.contains(r2.as_fd()));
+}
+
+#[test]
+fn test_select_nfds() {
+    let (r1, w1) = pipe().unwrap();
+    let (r2, _w2) = pipe().unwrap();
+
+    write(&w1, b"hi!").unwrap();
+    let mut fd_set = FdSet::new();
+    fd_set.insert(r1.as_fd());
+    fd_set.insert(r2.as_fd());
+
+    let mut timeout = TimeVal::seconds(10);
+    {
+        assert_eq!(
+            1,
+            select(
+                Some(
+                    fd_set
+                        .highest()
+                        .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+                        .unwrap()
+                        + 1
+                ),
+                &mut fd_set,
+                None,
+                None,
+                &mut timeout
+            )
+            .unwrap()
+        );
+    }
+    assert!(fd_set.contains(r1.as_fd()));
+    assert!(!fd_set.contains(r2.as_fd()));
+}
+
+#[test]
+fn test_select_nfds2() {
+    let (r1, w1) = pipe().unwrap();
+    write(&w1, b"hi!").unwrap();
+    let (r2, _w2) = pipe().unwrap();
+    let mut fd_set = FdSet::new();
+    fd_set.insert(r1.as_fd());
+    fd_set.insert(r2.as_fd());
+
+    let mut timeout = TimeVal::seconds(10);
+    assert_eq!(
+        1,
+        select(
+            std::cmp::max(r1.as_raw_fd(), r2.as_raw_fd()) + 1,
+            &mut fd_set,
+            None,
+            None,
+            &mut timeout
+        )
+        .unwrap()
+    );
+    assert!(fd_set.contains(r1.as_fd()));
+    assert!(!fd_set.contains(r2.as_fd()));
+}
diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs
index ca25ff9..bf60749 100644
--- a/test/sys/test_signal.rs
+++ b/test/sys/test_signal.rs
@@ -1,9 +1,10 @@
-#[cfg(not(target_os = "redox"))]
 use nix::errno::Errno;
 use nix::sys::signal::*;
 use nix::unistd::*;
-use std::convert::TryFrom;
+use std::hash::{Hash, Hasher};
 use std::sync::atomic::{AtomicBool, Ordering};
+#[cfg(not(target_os = "redox"))]
+use std::thread;
 
 #[test]
 fn test_kill_none() {
@@ -124,7 +125,7 @@
     raise(Signal::SIGINT).unwrap();
     assert!(SIGNALED.load(Ordering::Relaxed));
 
-    #[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
+    #[cfg(not(solarish))]
     assert_eq!(
         unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
         handler
@@ -132,7 +133,7 @@
 
     // System V based OSes (e.g. illumos and Solaris) always resets the
     // disposition to SIG_DFL prior to calling the signal handler
-    #[cfg(any(target_os = "illumos", target_os = "solaris"))]
+    #[cfg(solarish)]
     assert_eq!(
         unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(),
         SigHandler::SigDfl
@@ -141,3 +142,314 @@
     // Restore default signal handler
     unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap();
 }
+
+#[test]
+fn test_contains() {
+    let mut mask = SigSet::empty();
+    mask.add(SIGUSR1);
+
+    assert!(mask.contains(SIGUSR1));
+    assert!(!mask.contains(SIGUSR2));
+
+    let all = SigSet::all();
+    assert!(all.contains(SIGUSR1));
+    assert!(all.contains(SIGUSR2));
+}
+
+#[test]
+fn test_clear() {
+    let mut set = SigSet::all();
+    set.clear();
+    for signal in Signal::iterator() {
+        assert!(!set.contains(signal));
+    }
+}
+
+#[test]
+fn test_from_str_round_trips() {
+    for signal in Signal::iterator() {
+        assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
+        assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
+    }
+}
+
+#[test]
+fn test_from_str_invalid_value() {
+    let errval = Err(Errno::EINVAL);
+    assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
+    assert_eq!("kill".parse::<Signal>(), errval);
+    assert_eq!("9".parse::<Signal>(), errval);
+}
+
+#[test]
+fn test_extend() {
+    let mut one_signal = SigSet::empty();
+    one_signal.add(SIGUSR1);
+
+    let mut two_signals = SigSet::empty();
+    two_signals.add(SIGUSR2);
+    two_signals.extend(&one_signal);
+
+    assert!(two_signals.contains(SIGUSR1));
+    assert!(two_signals.contains(SIGUSR2));
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn test_thread_signal_set_mask() {
+    thread::spawn(|| {
+        let prev_mask = SigSet::thread_get_mask()
+            .expect("Failed to get existing signal mask!");
+
+        let mut test_mask = prev_mask;
+        test_mask.add(SIGUSR1);
+
+        test_mask.thread_set_mask().expect("assertion failed");
+        let new_mask =
+            SigSet::thread_get_mask().expect("Failed to get new mask!");
+
+        assert!(new_mask.contains(SIGUSR1));
+        assert!(!new_mask.contains(SIGUSR2));
+
+        prev_mask
+            .thread_set_mask()
+            .expect("Failed to revert signal mask!");
+    })
+    .join()
+    .unwrap();
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn test_thread_signal_block() {
+    thread::spawn(|| {
+        let mut mask = SigSet::empty();
+        mask.add(SIGUSR1);
+
+        mask.thread_block().expect("assertion failed");
+
+        assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
+    })
+    .join()
+    .unwrap();
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn test_thread_signal_unblock() {
+    thread::spawn(|| {
+        let mut mask = SigSet::empty();
+        mask.add(SIGUSR1);
+
+        mask.thread_unblock().expect("assertion failed");
+
+        assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
+    })
+    .join()
+    .unwrap();
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn test_thread_signal_swap() {
+    thread::spawn(|| {
+        let mut mask = SigSet::empty();
+        mask.add(SIGUSR1);
+        mask.thread_block().unwrap();
+
+        assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
+
+        let mut mask2 = SigSet::empty();
+        mask2.add(SIGUSR2);
+
+        let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap();
+
+        assert!(oldmask.contains(SIGUSR1));
+        assert!(!oldmask.contains(SIGUSR2));
+
+        assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
+    })
+    .join()
+    .unwrap();
+}
+
+#[test]
+fn test_from_and_into_iterator() {
+    let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]);
+    let signals = sigset.into_iter().collect::<Vec<Signal>>();
+    assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]);
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn test_sigaction() {
+    thread::spawn(|| {
+        extern "C" fn test_sigaction_handler(_: libc::c_int) {}
+        extern "C" fn test_sigaction_action(
+            _: libc::c_int,
+            _: *mut libc::siginfo_t,
+            _: *mut libc::c_void,
+        ) {
+        }
+
+        let handler_sig = SigHandler::Handler(test_sigaction_handler);
+
+        let flags =
+            SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO;
+
+        let mut mask = SigSet::empty();
+        mask.add(SIGUSR1);
+
+        let action_sig = SigAction::new(handler_sig, flags, mask);
+
+        assert_eq!(
+            action_sig.flags(),
+            SaFlags::SA_ONSTACK | SaFlags::SA_RESTART
+        );
+        assert_eq!(action_sig.handler(), handler_sig);
+
+        mask = action_sig.mask();
+        assert!(mask.contains(SIGUSR1));
+        assert!(!mask.contains(SIGUSR2));
+
+        let handler_act = SigHandler::SigAction(test_sigaction_action);
+        let action_act = SigAction::new(handler_act, flags, mask);
+        assert_eq!(action_act.handler(), handler_act);
+
+        let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
+        assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
+
+        let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
+        assert_eq!(action_ign.handler(), SigHandler::SigIgn);
+    })
+    .join()
+    .unwrap();
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn test_sigwait() {
+    thread::spawn(|| {
+        let mut mask = SigSet::empty();
+        mask.add(SIGUSR1);
+        mask.add(SIGUSR2);
+        mask.thread_block().unwrap();
+
+        raise(SIGUSR1).unwrap();
+        assert_eq!(mask.wait().unwrap(), SIGUSR1);
+    })
+    .join()
+    .unwrap();
+}
+
+#[cfg(any(
+    bsd,
+    linux_android,
+    solarish,
+    target_os = "haiku",
+    target_os = "hurd",
+    target_os = "aix",
+    target_os = "fushsia"
+))]
+#[test]
+fn test_sigsuspend() {
+    // This test change signal handler
+    let _m = crate::SIGNAL_MTX.lock();
+    static SIGNAL_RECIEVED: AtomicBool = AtomicBool::new(false);
+    extern "C" fn test_sigsuspend_handler(_: libc::c_int) {
+        assert!(!SIGNAL_RECIEVED.swap(true, Ordering::SeqCst));
+    }
+    thread::spawn(|| {
+        const SIGNAL: Signal = Signal::SIGUSR1;
+
+        // Add signal mask to this thread
+        let mut signal_set = SigSet::empty();
+        signal_set.add(SIGNAL);
+        signal_set.thread_block().unwrap();
+
+        // Set signal handler and save old one.
+        let act = SigAction::new(
+            SigHandler::Handler(test_sigsuspend_handler),
+            SaFlags::empty(),
+            SigSet::empty(),
+        );
+        let old_act = unsafe { sigaction(SIGNAL, &act) }
+            .expect("expect to be able to set new action and get old action");
+
+        raise(SIGNAL).expect("expect be able to send signal");
+        // Now `SIGNAL` was sended but it is blocked.
+        let mut not_wait_set = SigSet::all();
+        not_wait_set.remove(SIGNAL);
+        // signal handler must run in SigSet::suspend()
+        assert!(!SIGNAL_RECIEVED.load(Ordering::SeqCst));
+        not_wait_set.suspend().unwrap();
+        assert!(SIGNAL_RECIEVED.load(Ordering::SeqCst));
+
+        // Restore the signal handler.
+        unsafe { sigaction(SIGNAL, &old_act) }
+            .expect("expect to be able to restore old action ");
+    })
+    .join()
+    .unwrap();
+}
+
+#[test]
+fn test_from_sigset_t_unchecked() {
+    let src_set = SigSet::empty();
+    let set = unsafe { SigSet::from_sigset_t_unchecked(*src_set.as_ref()) };
+
+    for signal in Signal::iterator() {
+        assert!(!set.contains(signal));
+    }
+
+    let src_set = SigSet::all();
+    let set = unsafe { SigSet::from_sigset_t_unchecked(*src_set.as_ref()) };
+
+    for signal in Signal::iterator() {
+        assert!(set.contains(signal));
+    }
+}
+
+#[test]
+fn test_eq_empty() {
+    let set0 = SigSet::empty();
+    let set1 = SigSet::empty();
+    assert_eq!(set0, set1);
+}
+
+#[test]
+fn test_eq_all() {
+    let set0 = SigSet::all();
+    let set1 = SigSet::all();
+    assert_eq!(set0, set1);
+}
+
+#[test]
+fn test_hash_empty() {
+    use std::collections::hash_map::DefaultHasher;
+
+    let set0 = SigSet::empty();
+    let mut h0 = DefaultHasher::new();
+    set0.hash(&mut h0);
+
+    let set1 = SigSet::empty();
+    let mut h1 = DefaultHasher::new();
+    set1.hash(&mut h1);
+
+    assert_eq!(h0.finish(), h1.finish());
+}
+
+#[test]
+fn test_hash_all() {
+    use std::collections::hash_map::DefaultHasher;
+
+    let set0 = SigSet::all();
+    let mut h0 = DefaultHasher::new();
+    set0.hash(&mut h0);
+
+    let set1 = SigSet::all();
+    let mut h1 = DefaultHasher::new();
+    set1.hash(&mut h1);
+
+    assert_eq!(h0.finish(), h1.finish());
+}
diff --git a/test/sys/test_signalfd.rs b/test/sys/test_signalfd.rs
index 87153c9..4e0971a 100644
--- a/test/sys/test_signalfd.rs
+++ b/test/sys/test_signalfd.rs
@@ -1,6 +1,40 @@
 use std::convert::TryFrom;
 
 #[test]
+fn create_signalfd() {
+    use nix::sys::{signal::SigSet, signalfd::SignalFd};
+
+    let mask = SigSet::empty();
+    SignalFd::new(&mask).unwrap();
+}
+
+#[test]
+fn create_signalfd_with_opts() {
+    use nix::sys::{
+        signal::SigSet,
+        signalfd::{SfdFlags, SignalFd},
+    };
+
+    let mask = SigSet::empty();
+    SignalFd::with_flags(&mask, SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK)
+        .unwrap();
+}
+
+#[test]
+fn read_empty_signalfd() {
+    use nix::sys::{
+        signal::SigSet,
+        signalfd::{SfdFlags, SignalFd},
+    };
+
+    let mask = SigSet::empty();
+    let mut fd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
+
+    let res = fd.read_signal();
+    assert!(res.unwrap().is_none());
+}
+
+#[test]
 fn test_signalfd() {
     use nix::sys::signal::{self, raise, SigSet, Signal};
     use nix::sys::signalfd::SignalFd;
@@ -25,3 +59,32 @@
     let signo = Signal::try_from(res.ssi_signo as i32).unwrap();
     assert_eq!(signo, signal::SIGUSR1);
 }
+
+/// Update the signal mask of an already existing signalfd.
+#[test]
+fn test_signalfd_setmask() {
+    use nix::sys::signal::{self, raise, SigSet, Signal};
+    use nix::sys::signalfd::SignalFd;
+
+    // Grab the mutex for altering signals so we don't interfere with other tests.
+    let _m = crate::SIGNAL_MTX.lock();
+
+    // Block the SIGUSR1 signal from automatic processing for this thread
+    let mut mask = SigSet::empty();
+
+    let mut fd = SignalFd::new(&mask).unwrap();
+
+    mask.add(signal::SIGUSR1);
+    mask.thread_block().unwrap();
+    fd.set_mask(&mask).unwrap();
+
+    // Send a SIGUSR1 signal to the current process. Note that this uses `raise` instead of `kill`
+    // because `kill` with `getpid` isn't correct during multi-threaded execution like during a
+    // cargo test session. Instead use `raise` which does the correct thing by default.
+    raise(signal::SIGUSR1).expect("Error: raise(SIGUSR1) failed");
+
+    // And now catch that same signal.
+    let res = fd.read_signal().unwrap().unwrap();
+    let signo = Signal::try_from(res.ssi_signo as i32).unwrap();
+    assert_eq!(signo, signal::SIGUSR1);
+}
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs
index ed1686e..90b8a6f 100644
--- a/test/sys/test_socket.rs
+++ b/test/sys/test_socket.rs
@@ -1,4 +1,4 @@
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 use crate::*;
 use libc::c_char;
 use nix::sys::socket::{getsockname, AddressFamily, UnixAddr};
@@ -21,7 +21,7 @@
     };
     use std::io::{IoSlice, IoSliceMut};
 
-    let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap();
+    let sock_addr = SockaddrIn::from_str("127.0.0.1:6797").unwrap();
 
     let ssock = socket(
         AddressFamily::Inet,
@@ -72,15 +72,134 @@
     assert!(std::time::Duration::from(diff).as_secs() < 60);
 }
 
+#[cfg(target_os = "freebsd")]
+#[test]
+pub fn test_timestamping_realtime() {
+    use nix::sys::socket::{
+        recvmsg, sendmsg, setsockopt, socket, sockopt::ReceiveTimestamp,
+        sockopt::TsClock, ControlMessageOwned, MsgFlags, SockFlag, SockType,
+        SockaddrIn, SocketTimestamp,
+    };
+    use std::io::{IoSlice, IoSliceMut};
+
+    let sock_addr = SockaddrIn::from_str("127.0.0.1:6792").unwrap();
+
+    let ssock = socket(
+        AddressFamily::Inet,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .expect("send socket failed");
+
+    let rsock = socket(
+        AddressFamily::Inet,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .unwrap();
+    nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap();
+
+    setsockopt(&rsock, ReceiveTimestamp, &true).unwrap();
+    setsockopt(&rsock, TsClock, &SocketTimestamp::SO_TS_REALTIME).unwrap();
+
+    let sbuf = [0u8; 2048];
+    let mut rbuf = [0u8; 2048];
+    let flags = MsgFlags::empty();
+    let iov1 = [IoSlice::new(&sbuf)];
+    let mut iov2 = [IoSliceMut::new(&mut rbuf)];
+
+    let mut cmsg = cmsg_space!(nix::sys::time::TimeVal);
+    sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
+    let recv =
+        recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags)
+            .unwrap();
+
+    let mut ts = None;
+    for c in recv.cmsgs() {
+        if let ControlMessageOwned::ScmRealtime(timeval) = c {
+            ts = Some(timeval);
+        }
+    }
+    let ts = ts.expect("ScmRealtime is present");
+    let sys_time =
+        ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME)
+            .unwrap();
+    let diff = if ts > sys_time {
+        ts - sys_time
+    } else {
+        sys_time - ts
+    };
+    assert!(std::time::Duration::from(diff).as_secs() < 60);
+}
+
+#[cfg(target_os = "freebsd")]
+#[test]
+pub fn test_timestamping_monotonic() {
+    use nix::sys::socket::{
+        recvmsg, sendmsg, setsockopt, socket, sockopt::ReceiveTimestamp,
+        sockopt::TsClock, ControlMessageOwned, MsgFlags, SockFlag, SockType,
+        SockaddrIn, SocketTimestamp,
+    };
+    use std::io::{IoSlice, IoSliceMut};
+
+    let sock_addr = SockaddrIn::from_str("127.0.0.1:6803").unwrap();
+
+    let ssock = socket(
+        AddressFamily::Inet,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .expect("send socket failed");
+
+    let rsock = socket(
+        AddressFamily::Inet,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .unwrap();
+    nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap();
+
+    setsockopt(&rsock, ReceiveTimestamp, &true).unwrap();
+    setsockopt(&rsock, TsClock, &SocketTimestamp::SO_TS_MONOTONIC).unwrap();
+
+    let sbuf = [0u8; 2048];
+    let mut rbuf = [0u8; 2048];
+    let flags = MsgFlags::empty();
+    let iov1 = [IoSlice::new(&sbuf)];
+    let mut iov2 = [IoSliceMut::new(&mut rbuf)];
+
+    let mut cmsg = cmsg_space!(nix::sys::time::TimeVal);
+    sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
+    let recv =
+        recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags)
+            .unwrap();
+
+    let mut ts = None;
+    for c in recv.cmsgs() {
+        if let ControlMessageOwned::ScmMonotonic(timeval) = c {
+            ts = Some(timeval);
+        }
+    }
+    let ts = ts.expect("ScmMonotonic is present");
+    let sys_time =
+        ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_MONOTONIC)
+            .unwrap();
+    let diff = sys_time - ts; // Monotonic clock sys_time must be greater
+    assert!(std::time::Duration::from(diff).as_secs() < 60);
+}
+
 #[test]
 pub fn test_path_to_sock_addr() {
     let path = "/foo/bar";
     let actual = Path::new(path);
     let addr = UnixAddr::new(actual).unwrap();
 
-    let expect: &[c_char] = unsafe {
-        slice::from_raw_parts(path.as_ptr() as *const c_char, path.len())
-    };
+    let expect: &[c_char] =
+        unsafe { slice::from_raw_parts(path.as_ptr().cast(), path.len()) };
     assert_eq!(unsafe { &(*addr.as_ptr()).sun_path[..8] }, expect);
 
     assert_eq!(addr.path(), Some(actual));
@@ -105,7 +224,7 @@
     assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[test]
 pub fn test_abstract_sun_path_too_long() {
     let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough");
@@ -113,7 +232,7 @@
     addr.expect_err("assertion failed");
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[test]
 pub fn test_addr_equality_abstract() {
     let name = String::from("nix\0abstract\0test");
@@ -129,7 +248,7 @@
 }
 
 // Test getting/setting abstract addresses (without unix socket creation)
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[test]
 pub fn test_abstract_uds_addr() {
     let empty = String::new();
@@ -151,7 +270,7 @@
 }
 
 // Test getting an unnamed address (without unix socket creation)
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[test]
 pub fn test_unnamed_uds_addr() {
     use crate::nix::sys::socket::SockaddrLike;
@@ -200,7 +319,7 @@
         SockFlag::empty(),
     )
     .unwrap();
-    write(fd1.as_raw_fd(), b"hello").unwrap();
+    write(&fd1, b"hello").unwrap();
     let mut buf = [0; 5];
     read(fd2.as_raw_fd(), &mut buf).unwrap();
 
@@ -315,7 +434,7 @@
 
     #[test]
     pub fn udp() {
-        let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap();
+        let std_sa = SocketAddrV4::from_str("127.0.0.1:6795").unwrap();
         let sock_addr = SockaddrIn::from(std_sa);
         let rsock = socket(
             AddressFamily::Inet,
@@ -437,12 +556,7 @@
         }
     }
 
-    #[cfg(any(
-        target_os = "linux",
-        target_os = "android",
-        target_os = "freebsd",
-        target_os = "netbsd",
-    ))]
+    #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
     #[test]
     pub fn udp_sendmmsg() {
         use std::io::IoSlice;
@@ -504,12 +618,7 @@
         assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap());
     }
 
-    #[cfg(any(
-        target_os = "linux",
-        target_os = "android",
-        target_os = "freebsd",
-        target_os = "netbsd",
-    ))]
+    #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
     #[test]
     pub fn udp_recvmmsg() {
         use nix::sys::socket::{recvmmsg, MsgFlags};
@@ -565,7 +674,7 @@
         let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
             rsock.as_raw_fd(),
             &mut data,
-            msgs.iter(),
+            msgs.iter_mut(),
             MsgFlags::empty(),
             None,
         )
@@ -585,12 +694,7 @@
         send_thread.join().unwrap();
     }
 
-    #[cfg(any(
-        target_os = "linux",
-        target_os = "android",
-        target_os = "freebsd",
-        target_os = "netbsd",
-    ))]
+    #[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
     #[test]
     pub fn udp_recvmmsg_dontwait_short_read() {
         use nix::sys::socket::{recvmmsg, MsgFlags};
@@ -653,7 +757,7 @@
         let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
             rsock.as_raw_fd(),
             &mut data,
-            msgs.iter(),
+            msgs.iter_mut(),
             MsgFlags::MSG_DONTWAIT,
             None,
         )
@@ -674,10 +778,10 @@
     #[test]
     pub fn udp_inet6() {
         let addr = std::net::Ipv6Addr::from_str("::1").unwrap();
-        let rport = 6789;
+        let rport = 6796;
         let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0);
         let raddr = SockaddrIn6::from(rstd_sa);
-        let sport = 6790;
+        let sport = 6798;
         let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0);
         let saddr = SockaddrIn6::from(sstd_sa);
         let rsock = socket(
@@ -757,7 +861,7 @@
 
     {
         let iov = [IoSlice::new(b"hello")];
-        let fds = [r];
+        let fds = [r.as_raw_fd()];
         let cmsg = ControlMessage::ScmRights(&fds);
         assert_eq!(
             sendmsg::<()>(
@@ -770,7 +874,6 @@
             .unwrap(),
             5
         );
-        close(r).unwrap();
     }
 
     {
@@ -803,16 +906,15 @@
 
     let received_r = received_r.expect("Did not receive passed fd");
     // Ensure that the received file descriptor works
-    write(w.as_raw_fd(), b"world").unwrap();
+    write(&w, b"world").unwrap();
     let mut buf = [0u8; 5];
     read(received_r.as_raw_fd(), &mut buf).unwrap();
     assert_eq!(&buf[..], b"world");
     close(received_r).unwrap();
-    close(w).unwrap();
 }
 
 // Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[cfg_attr(qemu, ignore)]
 #[test]
 pub fn test_af_alg_cipher() {
@@ -905,7 +1007,7 @@
 
 // Disable the test on emulated platforms due to not enabled support of AF_ALG
 // in QEMU from rust cross
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[cfg_attr(qemu, ignore)]
 #[test]
 pub fn test_af_alg_aead() {
@@ -1039,7 +1141,7 @@
 // This would be a more interesting test if we could assume that the test host
 // has more than one IP address (since we could select a different address to
 // test from).
-#[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd"))]
+#[cfg(any(target_os = "linux", apple_targets, target_os = "netbsd"))]
 #[test]
 pub fn test_sendmsg_ipv4packetinfo() {
     use cfg_if::cfg_if;
@@ -1101,7 +1203,7 @@
 // test from).
 #[cfg(any(
     target_os = "linux",
-    target_os = "macos",
+    apple_targets,
     target_os = "netbsd",
     target_os = "freebsd"
 ))]
@@ -1158,12 +1260,7 @@
 //
 // Note that binding to 0.0.0.0 is *required* on FreeBSD; sendmsg
 // returns EINVAL otherwise. (See FreeBSD's ip(4) man page.)
-#[cfg(any(
-    target_os = "netbsd",
-    target_os = "freebsd",
-    target_os = "openbsd",
-    target_os = "dragonfly",
-))]
+#[cfg(any(freebsdlike, netbsdlike))]
 #[test]
 pub fn test_sendmsg_ipv4sendsrcaddr() {
     use nix::sys::socket::{
@@ -1302,7 +1399,7 @@
         )
         .unwrap();
 
-        for _ in msg.cmsgs() {
+        if msg.cmsgs().next().is_some() {
             panic!("unexpected cmsg");
         }
         assert!(!msg
@@ -1312,19 +1409,14 @@
     }
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "linux",
-    target_os = "freebsd",
-    target_os = "dragonfly",
-))]
+#[cfg(any(linux_android, freebsdlike))]
 #[test]
 fn test_scm_credentials() {
     use nix::sys::socket::{
         recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage,
         ControlMessageOwned, MsgFlags, SockFlag, SockType, UnixCredentials,
     };
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     use nix::sys::socket::{setsockopt, sockopt::PassCred};
     use nix::unistd::{getgid, getpid, getuid};
     use std::io::{IoSlice, IoSliceMut};
@@ -1336,16 +1428,16 @@
         SockFlag::empty(),
     )
     .unwrap();
-    #[cfg(any(target_os = "android", target_os = "linux"))]
+    #[cfg(linux_android)]
     setsockopt(&recv, PassCred, &true).unwrap();
 
     {
         let iov = [IoSlice::new(b"hello")];
-        #[cfg(any(target_os = "android", target_os = "linux"))]
+        #[cfg(linux_android)]
         let cred = UnixCredentials::new();
-        #[cfg(any(target_os = "android", target_os = "linux"))]
+        #[cfg(linux_android)]
         let cmsg = ControlMessage::ScmCredentials(&cred);
-        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+        #[cfg(freebsdlike)]
         let cmsg = ControlMessage::ScmCreds;
         assert_eq!(
             sendmsg::<()>(
@@ -1376,9 +1468,9 @@
 
         for cmsg in msg.cmsgs() {
             let cred = match cmsg {
-                #[cfg(any(target_os = "android", target_os = "linux"))]
+                #[cfg(linux_android)]
                 ControlMessageOwned::ScmCredentials(cred) => cred,
-                #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+                #[cfg(freebsdlike)]
                 ControlMessageOwned::ScmCreds(cred) => cred,
                 other => panic!("unexpected cmsg {other:?}"),
             };
@@ -1398,7 +1490,7 @@
 
 /// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single
 /// `sendmsg` call.
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 // qemu's handling of multiple cmsgs is bugged, ignore tests under emulation
 // see https://bugs.launchpad.net/qemu/+bug/1781280
 #[cfg_attr(qemu, ignore)]
@@ -1410,7 +1502,7 @@
 
 /// Ensure that passing a an oversized control message buffer to recvmsg
 /// still works.
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 // qemu's handling of multiple cmsgs is bugged, ignore tests under emulation
 // see https://bugs.launchpad.net/qemu/+bug/1781280
 #[cfg_attr(qemu, ignore)]
@@ -1420,7 +1512,7 @@
     test_impl_scm_credentials_and_rights(space);
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
     use libc::ucred;
     use nix::sys::socket::sockopt::PassCred;
@@ -1451,7 +1543,7 @@
             gid: getgid().as_raw(),
         }
         .into();
-        let fds = [r];
+        let fds = [r.as_raw_fd()];
         let cmsgs = [
             ControlMessage::ScmCredentials(&cred),
             ControlMessage::ScmRights(&fds),
@@ -1467,7 +1559,6 @@
             .unwrap(),
             5
         );
-        close(r).unwrap();
     }
 
     {
@@ -1510,18 +1601,19 @@
 
     let received_r = received_r.expect("Did not receive passed fd");
     // Ensure that the received file descriptor works
-    write(w.as_raw_fd(), b"world").unwrap();
+    write(&w, b"world").unwrap();
     let mut buf = [0u8; 5];
     read(received_r.as_raw_fd(), &mut buf).unwrap();
     assert_eq!(&buf[..], b"world");
     close(received_r).unwrap();
-    close(w).unwrap();
 }
 
 // Test creating and using named unix domain sockets
 #[test]
 pub fn test_named_unixdomain() {
-    use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr};
+    use nix::sys::socket::{
+        accept, bind, connect, listen, socket, Backlog, UnixAddr,
+    };
     use nix::sys::socket::{SockFlag, SockType};
     use nix::unistd::{read, write};
     use std::thread;
@@ -1537,7 +1629,7 @@
     .expect("socket failed");
     let sockaddr = UnixAddr::new(&sockname).unwrap();
     bind(s1.as_raw_fd(), &sockaddr).expect("bind failed");
-    listen(&s1, 10).expect("listen failed");
+    listen(&s1, Backlog::new(10).unwrap()).expect("listen failed");
 
     let thr = thread::spawn(move || {
         let s2 = socket(
@@ -1548,7 +1640,7 @@
         )
         .expect("socket failed");
         connect(s2.as_raw_fd(), &sockaddr).expect("connect failed");
-        write(s2.as_raw_fd(), b"hello").expect("write failed");
+        write(&s2, b"hello").expect("write failed");
     });
 
     let s3 = accept(s1.as_raw_fd()).expect("accept failed");
@@ -1560,8 +1652,16 @@
     assert_eq!(&buf[..], b"hello");
 }
 
+#[test]
+pub fn test_listen_wrongbacklog() {
+    use nix::sys::socket::Backlog;
+
+    assert!(Backlog::new(libc::SOMAXCONN + 1).is_err());
+    assert!(Backlog::new(-2).is_err());
+}
+
 // Test using unnamed unix domain addresses
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[test]
 pub fn test_unnamed_unixdomain() {
     use nix::sys::socket::{getsockname, socketpair};
@@ -1581,7 +1681,7 @@
 }
 
 // Test creating and using unnamed unix domain addresses for autobinding sockets
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[test]
 pub fn test_unnamed_unixdomain_autobind() {
     use nix::sys::socket::{bind, getsockname, socket};
@@ -1609,7 +1709,7 @@
 }
 
 // Test creating and using named system control sockets
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(apple_targets)]
 #[test]
 pub fn test_syscontrol() {
     use nix::errno::Errno;
@@ -1635,15 +1735,7 @@
     // connect(fd.as_raw_fd(), &sockaddr).expect("connect failed");
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "linux",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
+#[cfg(any(bsd, linux_android))]
 fn loopback_address(
     family: AddressFamily,
 ) -> Option<nix::ifaddrs::InterfaceAddress> {
@@ -1670,20 +1762,16 @@
     })
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "ios",
-    target_os = "linux",
-    target_os = "macos",
-    target_os = "netbsd",
-))]
+#[cfg(any(linux_android, apple_targets, target_os = "netbsd"))]
 // qemu doesn't seem to be emulating this correctly in these architectures
 #[cfg_attr(
     all(
         qemu,
         any(
             target_arch = "mips",
+            target_arch = "mips32r6",
             target_arch = "mips64",
+            target_arch = "mips64r6",
             target_arch = "powerpc64",
         )
     ),
@@ -1765,20 +1853,16 @@
     }
 }
 
-#[cfg(any(
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
+#[cfg(bsd)]
 // qemu doesn't seem to be emulating this correctly in these architectures
 #[cfg_attr(
     all(
         qemu,
         any(
             target_arch = "mips",
+            target_arch = "mips32r6",
             target_arch = "mips64",
+            target_arch = "mips64r6",
             target_arch = "powerpc64",
         )
     ),
@@ -1883,7 +1967,7 @@
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
 #[cfg_attr(qemu, ignore)]
 #[test]
 pub fn test_recvif_ipv4() {
@@ -1969,7 +2053,7 @@
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
 #[cfg_attr(qemu, ignore)]
 #[test]
 pub fn test_recvif_ipv6() {
@@ -2055,22 +2139,16 @@
     }
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "linux",
-    target_os = "macos",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
+#[cfg(any(linux_android, target_os = "freebsd", apple_targets, netbsdlike))]
 // qemu doesn't seem to be emulating this correctly in these architectures
 #[cfg_attr(
     all(
         qemu,
         any(
             target_arch = "mips",
+            target_arch = "mips32r6",
             target_arch = "mips64",
+            target_arch = "mips64r6",
             target_arch = "powerpc64",
         )
     ),
@@ -2152,7 +2230,7 @@
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[test]
 pub fn test_vsock() {
     use nix::sys::socket::SockaddrLike;
@@ -2192,7 +2270,7 @@
     assert_eq!(addr3.as_ref().svm_port, addr1.port());
 }
 
-#[cfg(target_os = "macos")]
+#[cfg(apple_targets)]
 #[test]
 pub fn test_vsock() {
     use nix::sys::socket::SockaddrLike;
@@ -2329,12 +2407,17 @@
     // Receive the message
     let mut buffer = vec![0u8; message.len()];
     let cmsgspace = nix::cmsg_space!(TimeSpec);
-    let iov = vec![[IoSliceMut::new(&mut buffer)]];
+    let mut iov = vec![[IoSliceMut::new(&mut buffer)]];
     let mut data = MultiHeaders::preallocate(1, Some(cmsgspace));
-    let r: Vec<RecvMsg<()>> =
-        recvmmsg(in_socket.as_raw_fd(), &mut data, iov.iter(), flags, None)
-            .unwrap()
-            .collect();
+    let r: Vec<RecvMsg<()>> = recvmmsg(
+        in_socket.as_raw_fd(),
+        &mut data,
+        iov.iter_mut(),
+        flags,
+        None,
+    )
+    .unwrap()
+    .collect();
     let rtime = match r[0].cmsgs().next() {
         Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime,
         Some(_) => panic!("Unexpected control message"),
@@ -2353,7 +2436,7 @@
 // Disable the test on emulated platforms because it fails in Cirrus-CI.  Lack
 // of QEMU support is suspected.
 #[cfg_attr(qemu, ignore)]
-#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "fuchsia"))]
 #[test]
 fn test_recvmsg_rxq_ovfl() {
     use nix::sys::socket::sockopt::{RcvBuf, RxqOvfl};
@@ -2447,7 +2530,7 @@
     assert_eq!(drop_counter, 1);
 }
 
-#[cfg(any(target_os = "linux", target_os = "android",))]
+#[cfg(linux_android)]
 mod linux_errqueue {
     use super::FromStr;
     use nix::sys::socket::*;
@@ -2685,3 +2768,160 @@
     recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, None, MsgFlags::empty())
         .unwrap();
 }
+
+// cfg needed for capability check.
+#[cfg(linux_android)]
+#[test]
+fn test_icmp_protocol() {
+    use nix::sys::socket::{
+        sendto, socket, AddressFamily, MsgFlags, SockFlag, SockProtocol,
+        SockType, SockaddrIn,
+    };
+
+    require_capability!("test_icmp_protocol", CAP_NET_RAW);
+
+    let owned_fd = socket(
+        AddressFamily::Inet,
+        SockType::Raw,
+        SockFlag::empty(),
+        SockProtocol::Icmp,
+    )
+    .unwrap();
+
+    // Send a minimal ICMP packet with no payload.
+    let packet = [
+        0x08, // Type
+        0x00, // Code
+        0x84, 0x85, // Checksum
+        0x73, 0x8a, // ID
+        0x00, 0x00, // Sequence Number
+    ];
+
+    let dest_addr = SockaddrIn::new(127, 0, 0, 1, 0);
+    sendto(owned_fd.as_raw_fd(), &packet, &dest_addr, MsgFlags::empty())
+        .unwrap();
+}
+
+// test contains both recvmmsg and timestaping which is linux only
+// there are existing tests for recvmmsg only in tests/
+#[cfg_attr(qemu, ignore)]
+#[cfg(target_os = "linux")]
+#[test]
+fn test_recvmm2() -> nix::Result<()> {
+    use nix::sys::{
+        socket::{
+            bind, recvmmsg, sendmsg, setsockopt, socket, sockopt::Timestamping,
+            AddressFamily, ControlMessageOwned, MsgFlags, MultiHeaders,
+            SockFlag, SockType, SockaddrIn, TimestampingFlag, Timestamps,
+        },
+        time::TimeSpec,
+    };
+    use std::io::{IoSlice, IoSliceMut};
+    use std::os::unix::io::AsRawFd;
+    use std::str::FromStr;
+
+    let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap();
+
+    let ssock = socket(
+        AddressFamily::Inet,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )?;
+
+    let rsock = socket(
+        AddressFamily::Inet,
+        SockType::Datagram,
+        SockFlag::SOCK_NONBLOCK,
+        None,
+    )?;
+
+    bind(rsock.as_raw_fd(), &sock_addr)?;
+
+    setsockopt(&rsock, Timestamping, &TimestampingFlag::all())?;
+
+    let sbuf = (0..400).map(|i| i as u8).collect::<Vec<_>>();
+
+    let mut recv_buf = vec![0; 1024];
+
+    let mut recv_iovs = Vec::new();
+    let mut pkt_iovs = Vec::new();
+
+    for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() {
+        pkt_iovs.push(IoSliceMut::new(chunk));
+        if ix % 2 == 1 {
+            recv_iovs.push(pkt_iovs);
+            pkt_iovs = Vec::new();
+        }
+    }
+    drop(pkt_iovs);
+
+    let flags = MsgFlags::empty();
+    let iov1 = [IoSlice::new(&sbuf)];
+
+    let cmsg = cmsg_space!(Timestamps);
+    sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
+
+    let mut data = MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg));
+
+    let t = TimeSpec::from_duration(std::time::Duration::from_secs(10));
+
+    let recv = recvmmsg(
+        rsock.as_raw_fd(),
+        &mut data,
+        recv_iovs.iter_mut(),
+        flags,
+        Some(t),
+    )?;
+
+    for rmsg in recv {
+        #[cfg(not(any(qemu, target_arch = "aarch64")))]
+        let mut saw_time = false;
+        let mut recvd = 0;
+        for cmsg in rmsg.cmsgs() {
+            if let ControlMessageOwned::ScmTimestampsns(timestamps) = cmsg {
+                let ts = timestamps.system;
+
+                let sys_time = nix::time::clock_gettime(
+                    nix::time::ClockId::CLOCK_REALTIME,
+                )?;
+                let diff = if ts > sys_time {
+                    ts - sys_time
+                } else {
+                    sys_time - ts
+                };
+                assert!(std::time::Duration::from(diff).as_secs() < 60);
+                #[cfg(not(any(qemu, target_arch = "aarch64")))]
+                {
+                    saw_time = true;
+                }
+            }
+        }
+
+        #[cfg(not(any(qemu, target_arch = "aarch64")))]
+        assert!(saw_time);
+
+        for iov in rmsg.iovs() {
+            recvd += iov.len();
+        }
+        assert_eq!(recvd, 400);
+    }
+
+    Ok(())
+}
+
+#[cfg(not(target_os = "redox"))]
+#[test]
+fn can_use_cmsg_space() {
+    let _ = cmsg_space!(u8);
+}
+
+#[cfg(not(any(linux_android, target_os = "redox", target_os = "haiku")))]
+#[test]
+fn can_open_routing_socket() {
+    use nix::sys::socket::{socket, AddressFamily, SockFlag, SockType};
+
+    let _ =
+        socket(AddressFamily::Route, SockType::Raw, SockFlag::empty(), None)
+            .expect("Failed to open routing socket");
+}
diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs
index 0e34917..a99d4e3 100644
--- a/test/sys/test_sockopt.rs
+++ b/test/sys/test_sockopt.rs
@@ -1,14 +1,14 @@
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 use crate::*;
 use nix::sys::socket::{
     getsockopt, setsockopt, socket, sockopt, AddressFamily, SockFlag,
     SockProtocol, SockType,
 };
 use rand::{thread_rng, Rng};
-use std::os::unix::io::AsRawFd;
+use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd};
 
 // NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not.
-#[cfg(any(target_os = "dragonfly", target_os = "freebsd",))]
+#[cfg(freebsdlike)]
 #[test]
 pub fn test_local_peercred_seqpacket() {
     use nix::{
@@ -29,12 +29,7 @@
     assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
 }
 
-#[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "macos",
-    target_os = "ios"
-))]
+#[cfg(any(freebsdlike, apple_targets))]
 #[test]
 pub fn test_local_peercred_stream() {
     use nix::{
@@ -55,7 +50,7 @@
     assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
 }
 
-#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[cfg(apple_targets)]
 #[test]
 pub fn test_local_peer_pid() {
     use nix::sys::socket::socketpair;
@@ -108,14 +103,14 @@
     assert!(actual >= bufsize);
 }
 
+#[cfg(target_os = "freebsd")]
 #[test]
-fn test_so_tcp_maxseg() {
-    use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn};
-    use nix::unistd::write;
+fn test_so_listen_q_limit() {
+    use nix::sys::socket::{bind, listen, Backlog, SockaddrIn};
     use std::net::SocketAddrV4;
     use std::str::FromStr;
 
-    let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap();
+    let std_sa = SocketAddrV4::from_str("127.0.0.1:4004").unwrap();
     let sock_addr = SockaddrIn::from(std_sa);
 
     let rsock = socket(
@@ -126,13 +121,41 @@
     )
     .unwrap();
     bind(rsock.as_raw_fd(), &sock_addr).unwrap();
-    listen(&rsock, 10).unwrap();
+    let pre_limit = getsockopt(&rsock, sockopt::ListenQLimit).unwrap();
+    assert_eq!(pre_limit, 0);
+    listen(&rsock, Backlog::new(42).unwrap()).unwrap();
+    let post_limit = getsockopt(&rsock, sockopt::ListenQLimit).unwrap();
+    assert_eq!(post_limit, 42);
+}
+
+#[test]
+fn test_so_tcp_maxseg() {
+    use nix::sys::socket::{
+        accept, bind, connect, getsockname, listen, Backlog, SockaddrIn,
+    };
+    use nix::unistd::write;
+    use std::net::SocketAddrV4;
+    use std::str::FromStr;
+
+    let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap();
+    let mut sock_addr = SockaddrIn::from(std_sa);
+
+    let rsock = socket(
+        AddressFamily::Inet,
+        SockType::Stream,
+        SockFlag::empty(),
+        SockProtocol::Tcp,
+    )
+    .unwrap();
+    bind(rsock.as_raw_fd(), &sock_addr).unwrap();
+    sock_addr = getsockname(rsock.as_raw_fd()).unwrap();
+    listen(&rsock, Backlog::new(10).unwrap()).unwrap();
     let initial = getsockopt(&rsock, sockopt::TcpMaxSeg).unwrap();
     // Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some
     // platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger
     // than 700
     cfg_if! {
-        if #[cfg(any(target_os = "android", target_os = "linux"))] {
+        if #[cfg(linux_android)] {
             let segsize: u32 = 873;
             assert!(initial < segsize);
             setsockopt(&rsock, sockopt::TcpMaxSeg, &segsize).unwrap();
@@ -151,12 +174,13 @@
     .unwrap();
     connect(ssock.as_raw_fd(), &sock_addr).unwrap();
     let rsess = accept(rsock.as_raw_fd()).unwrap();
-    write(rsess, b"hello").unwrap();
+    let rsess = unsafe { OwnedFd::from_raw_fd(rsess) };
+    write(&rsess, b"hello").unwrap();
     let actual = getsockopt(&ssock, sockopt::TcpMaxSeg).unwrap();
     // Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max
     // TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary.
     cfg_if! {
-        if #[cfg(any(target_os = "android", target_os = "linux"))] {
+        if #[cfg(linux_android)] {
             assert!((segsize - 100) <= actual);
             assert!(actual <= segsize);
         } else {
@@ -181,11 +205,10 @@
 
 /// getsockopt(_, sockopt::SockType) should gracefully handle unknown socket
 /// types.  Regression test for https://github.com/nix-rust/nix/issues/1819
-#[cfg(any(target_os = "android", target_os = "linux",))]
+#[cfg(linux_android)]
 #[test]
 fn test_so_type_unknown() {
     use nix::errno::Errno;
-    use std::os::unix::io::{FromRawFd, OwnedFd};
 
     require_capability!("test_so_type", CAP_NET_RAW);
     let raw_fd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) };
@@ -229,7 +252,7 @@
 }
 
 #[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn test_bindtodevice() {
     skip_if_not_root!("test_bindtodevice");
 
@@ -259,12 +282,7 @@
     setsockopt(&fd, sockopt::KeepAlive, &true).unwrap();
     assert!(getsockopt(&fd, sockopt::KeepAlive).unwrap());
 
-    #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "linux"
-    ))]
+    #[cfg(any(linux_android, freebsdlike))]
     {
         let x = getsockopt(&fd, sockopt::TcpKeepIdle).unwrap();
         setsockopt(&fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap();
@@ -281,14 +299,14 @@
 }
 
 #[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[cfg_attr(qemu, ignore)]
 fn test_get_mtu() {
     use nix::sys::socket::{bind, connect, SockaddrIn};
     use std::net::SocketAddrV4;
     use std::str::FromStr;
 
-    let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap();
+    let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap();
     let std_sb = SocketAddrV4::from_str("127.0.0.1:4002").unwrap();
 
     let usock = socket(
@@ -308,7 +326,7 @@
 }
 
 #[test]
-#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
 fn test_ttl_opts() {
     let fd4 = socket(
         AddressFamily::Inet,
@@ -331,7 +349,48 @@
 }
 
 #[test]
-#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[cfg(any(linux_android, target_os = "freebsd"))]
+fn test_multicast_ttl_opts_ipv4() {
+    let fd4 = socket(
+        AddressFamily::Inet,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .unwrap();
+    setsockopt(&fd4, sockopt::IpMulticastTtl, &2)
+        .expect("setting ipmulticastttl on an inet socket should succeed");
+}
+
+#[test]
+#[cfg(linux_android)]
+fn test_multicast_ttl_opts_ipv6() {
+    let fd6 = socket(
+        AddressFamily::Inet6,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .unwrap();
+    setsockopt(&fd6, sockopt::IpMulticastTtl, &2)
+        .expect("setting ipmulticastttl on an inet6 socket should succeed");
+}
+
+#[test]
+fn test_ipv6_multicast_hops() {
+    let fd6 = socket(
+        AddressFamily::Inet6,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .unwrap();
+    setsockopt(&fd6, sockopt::Ipv6MulticastHops, &7)
+        .expect("setting ipv6multicasthops on an inet6 socket should succeed");
+}
+
+#[test]
+#[cfg(apple_targets)]
 fn test_dontfrag_opts() {
     let fd4 = socket(
         AddressFamily::Inet,
@@ -361,12 +420,7 @@
 }
 
 #[test]
-#[cfg(any(
-    target_os = "android",
-    target_os = "ios",
-    target_os = "linux",
-    target_os = "macos",
-))]
+#[cfg(any(linux_android, apple_targets))]
 // Disable the test under emulation because it fails in Cirrus-CI.  Lack
 // of QEMU support is suspected.
 #[cfg_attr(qemu, ignore)]
@@ -446,3 +500,331 @@
     setsockopt(&fd, sockopt::Ipv6TClass, &class).unwrap();
     assert_eq!(getsockopt(&fd, sockopt::Ipv6TClass).unwrap(), class);
 }
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_receive_timestamp() {
+    let fd = socket(
+        AddressFamily::Inet6,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .unwrap();
+    setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+    assert!(getsockopt(&fd, sockopt::ReceiveTimestamp).unwrap());
+}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_ts_clock_realtime_micro() {
+    use nix::sys::socket::SocketTimestamp;
+
+    let fd = socket(
+        AddressFamily::Inet6,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .unwrap();
+
+    // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
+    setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+
+    setsockopt(
+        &fd,
+        sockopt::TsClock,
+        &SocketTimestamp::SO_TS_REALTIME_MICRO,
+    )
+    .unwrap();
+    assert_eq!(
+        getsockopt(&fd, sockopt::TsClock).unwrap(),
+        SocketTimestamp::SO_TS_REALTIME_MICRO
+    );
+}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_ts_clock_bintime() {
+    use nix::sys::socket::SocketTimestamp;
+
+    let fd = socket(
+        AddressFamily::Inet6,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .unwrap();
+
+    // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
+    setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+
+    setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_BINTIME).unwrap();
+    assert_eq!(
+        getsockopt(&fd, sockopt::TsClock).unwrap(),
+        SocketTimestamp::SO_TS_BINTIME
+    );
+}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_ts_clock_realtime() {
+    use nix::sys::socket::SocketTimestamp;
+
+    let fd = socket(
+        AddressFamily::Inet6,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .unwrap();
+
+    // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
+    setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+
+    setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_REALTIME)
+        .unwrap();
+    assert_eq!(
+        getsockopt(&fd, sockopt::TsClock).unwrap(),
+        SocketTimestamp::SO_TS_REALTIME
+    );
+}
+
+#[test]
+#[cfg(target_os = "freebsd")]
+fn test_ts_clock_monotonic() {
+    use nix::sys::socket::SocketTimestamp;
+
+    let fd = socket(
+        AddressFamily::Inet6,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .unwrap();
+
+    // FreeBSD setsockopt docs say to set SO_TS_CLOCK after setting SO_TIMESTAMP.
+    setsockopt(&fd, sockopt::ReceiveTimestamp, &true).unwrap();
+
+    setsockopt(&fd, sockopt::TsClock, &SocketTimestamp::SO_TS_MONOTONIC)
+        .unwrap();
+    assert_eq!(
+        getsockopt(&fd, sockopt::TsClock).unwrap(),
+        SocketTimestamp::SO_TS_MONOTONIC
+    );
+}
+
+#[test]
+#[cfg(linux_android)]
+// Disable the test under emulation because it fails with ENOPROTOOPT in CI
+// on cross target. Lack of QEMU support is suspected.
+#[cfg_attr(qemu, ignore)]
+fn test_ip_bind_address_no_port() {
+    let fd = socket(
+        AddressFamily::Inet,
+        SockType::Stream,
+        SockFlag::empty(),
+        SockProtocol::Tcp,
+    )
+    .unwrap();
+    setsockopt(&fd, sockopt::IpBindAddressNoPort, &true).expect(
+        "setting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
+    );
+    assert!(getsockopt(&fd, sockopt::IpBindAddressNoPort).expect(
+        "getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
+    ));
+    setsockopt(&fd, sockopt::IpBindAddressNoPort, &false).expect(
+        "unsetting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
+    );
+    assert!(!getsockopt(&fd, sockopt::IpBindAddressNoPort).expect(
+        "getting IP_BIND_ADDRESS_NO_PORT on an inet stream socket should succeed",
+    ));
+}
+
+#[test]
+#[cfg(linux_android)]
+fn test_tcp_fast_open_connect() {
+    let fd = socket(
+        AddressFamily::Inet,
+        SockType::Stream,
+        SockFlag::empty(),
+        SockProtocol::Tcp,
+    )
+    .unwrap();
+    setsockopt(&fd, sockopt::TcpFastOpenConnect, &true).expect(
+        "setting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
+    );
+    assert!(getsockopt(&fd, sockopt::TcpFastOpenConnect).expect(
+        "getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
+    ));
+    setsockopt(&fd, sockopt::TcpFastOpenConnect, &false).expect(
+        "unsetting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
+    );
+    assert!(!getsockopt(&fd, sockopt::TcpFastOpenConnect).expect(
+        "getting TCP_FASTOPEN_CONNECT on an inet stream socket should succeed",
+    ));
+}
+
+#[cfg(linux_android)]
+#[test]
+fn can_get_peercred_on_unix_socket() {
+    use nix::sys::socket::{socketpair, sockopt, SockFlag, SockType};
+
+    let (a, b) = socketpair(
+        AddressFamily::Unix,
+        SockType::Stream,
+        None,
+        SockFlag::empty(),
+    )
+    .unwrap();
+    let a_cred = getsockopt(&a, sockopt::PeerCredentials).unwrap();
+    let b_cred = getsockopt(&b, sockopt::PeerCredentials).unwrap();
+    assert_eq!(a_cred, b_cred);
+    assert_ne!(a_cred.pid(), 0);
+}
+
+#[test]
+fn is_socket_type_unix() {
+    use nix::sys::socket::{socketpair, sockopt, SockFlag, SockType};
+
+    let (a, _b) = socketpair(
+        AddressFamily::Unix,
+        SockType::Stream,
+        None,
+        SockFlag::empty(),
+    )
+    .unwrap();
+    let a_type = getsockopt(&a, sockopt::SockType).unwrap();
+    assert_eq!(a_type, SockType::Stream);
+}
+
+#[test]
+fn is_socket_type_dgram() {
+    use nix::sys::socket::{
+        getsockopt, sockopt, AddressFamily, SockFlag, SockType,
+    };
+
+    let s = socket(
+        AddressFamily::Inet,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None,
+    )
+    .unwrap();
+    let s_type = getsockopt(&s, sockopt::SockType).unwrap();
+    assert_eq!(s_type, SockType::Datagram);
+}
+
+#[cfg(any(target_os = "freebsd", target_os = "linux"))]
+#[test]
+fn can_get_listen_on_tcp_socket() {
+    use nix::sys::socket::{
+        getsockopt, listen, socket, sockopt, AddressFamily, Backlog, SockFlag,
+        SockType,
+    };
+
+    let s = socket(
+        AddressFamily::Inet,
+        SockType::Stream,
+        SockFlag::empty(),
+        None,
+    )
+    .unwrap();
+    let s_listening = getsockopt(&s, sockopt::AcceptConn).unwrap();
+    assert!(!s_listening);
+    listen(&s, Backlog::new(10).unwrap()).unwrap();
+    let s_listening2 = getsockopt(&s, sockopt::AcceptConn).unwrap();
+    assert!(s_listening2);
+}
+
+#[cfg(target_os = "linux")]
+// Some architectures running under cross don't support `setsockopt(SOL_TCP, TCP_ULP)`
+// because the cross image is based on Ubuntu 16.04 which predates TCP ULP support
+// (it was added in kernel v4.13 released in 2017). For these architectures,
+// the `setsockopt(SOL_TCP, TCP_ULP, "tls", sizeof("tls"))` call succeeds
+// but the subsequent `setsockopt(SOL_TLS, TLS_TX, ...)` call fails with `ENOPROTOOPT`.
+// It's as if the first `setsockopt` call enabled some other option, not `TCP_ULP`.
+// For example, `strace` says:
+//
+//     [pid   813] setsockopt(4, SOL_TCP, 0x1f /* TCP_??? */, [7564404], 4) = 0
+//
+// It's not clear why `setsockopt(SOL_TCP, TCP_ULP)` succeeds if the container image libc doesn't support it,
+// but in any case we can't run the test on such an architecture, so skip it.
+#[cfg_attr(qemu, ignore)]
+#[test]
+fn test_ktls() {
+    use nix::sys::socket::{
+        accept, bind, connect, getsockname, listen, Backlog, SockaddrIn,
+    };
+    use std::net::SocketAddrV4;
+    use std::str::FromStr;
+
+    let std_sa = SocketAddrV4::from_str("127.0.0.1:0").unwrap();
+    let mut sock_addr = SockaddrIn::from(std_sa);
+
+    let rsock = socket(
+        AddressFamily::Inet,
+        SockType::Stream,
+        SockFlag::empty(),
+        SockProtocol::Tcp,
+    )
+    .unwrap();
+    bind(rsock.as_raw_fd(), &sock_addr).unwrap();
+    sock_addr = getsockname(rsock.as_raw_fd()).unwrap();
+    listen(&rsock, Backlog::new(10).unwrap()).unwrap();
+
+    let ssock = socket(
+        AddressFamily::Inet,
+        SockType::Stream,
+        SockFlag::empty(),
+        SockProtocol::Tcp,
+    )
+    .unwrap();
+    connect(ssock.as_raw_fd(), &sock_addr).unwrap();
+
+    let _rsess = accept(rsock.as_raw_fd()).unwrap();
+
+    match setsockopt(&ssock, sockopt::TcpUlp::default(), b"tls") {
+        Ok(()) => (),
+
+        // TLS ULP is not enabled, so we can't test kTLS.
+        Err(nix::Error::ENOENT) => skip!("TLS ULP is not enabled"),
+
+        Err(err) => panic!("{err:?}"),
+    }
+
+    // In real life we would do a TLS handshake and extract the protocol version and secrets.
+    // For this test we just make some up.
+
+    let tx = sockopt::TlsCryptoInfo::Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128 {
+        info: libc::tls_crypto_info {
+            version: libc::TLS_1_2_VERSION,
+            cipher_type: libc::TLS_CIPHER_AES_GCM_128,
+        },
+        iv: *b"\x04\x05\x06\x07\x08\x09\x0a\x0b",
+        key: *b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+        salt: *b"\x00\x01\x02\x03",
+        rec_seq: *b"\x00\x00\x00\x00\x00\x00\x00\x00",
+    });
+    setsockopt(&ssock, sockopt::TcpTlsTx, &tx)
+        .expect("setting TLS_TX after enabling TLS ULP should succeed");
+
+    let rx = sockopt::TlsCryptoInfo::Aes128Gcm(libc::tls12_crypto_info_aes_gcm_128 {
+        info: libc::tls_crypto_info {
+            version: libc::TLS_1_2_VERSION,
+            cipher_type: libc::TLS_CIPHER_AES_GCM_128,
+        },
+        iv: *b"\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb",
+        key: *b"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
+        salt: *b"\xf0\xf1\xf2\xf3",
+        rec_seq: *b"\x00\x00\x00\x00\x00\x00\x00\x00",
+    });
+    match setsockopt(&ssock, sockopt::TcpTlsRx, &rx) {
+        Ok(()) => (),
+        Err(nix::Error::ENOPROTOOPT) => {
+            // TLS_TX was added in v4.13 and TLS_RX in v4.17, so we appear to be between that range.
+            // It's good enough that TLS_TX worked, so let the test succeed.
+        }
+        Err(err) => panic!("{err:?}"),
+    }
+}
diff --git a/test/sys/test_statfs.rs b/test/sys/test_statfs.rs
new file mode 100644
index 0000000..66b3f2c
--- /dev/null
+++ b/test/sys/test_statfs.rs
@@ -0,0 +1,99 @@
+use nix::sys::statfs::*;
+use nix::sys::statvfs::*;
+use std::fs::File;
+use std::path::Path;
+
+fn check_fstatfs(path: &str) {
+    if !Path::new(path).exists() {
+        return;
+    }
+    let vfs = statvfs(path.as_bytes()).unwrap();
+    let file = File::open(path).unwrap();
+    let fs = fstatfs(&file).unwrap();
+    assert_fs_equals(fs, vfs);
+}
+
+fn check_statfs(path: &str) {
+    if !Path::new(path).exists() {
+        return;
+    }
+    let vfs = statvfs(path.as_bytes()).unwrap();
+    let fs = statfs(path.as_bytes()).unwrap();
+    assert_fs_equals(fs, vfs);
+}
+
+fn check_fstatfs_strict(path: &str) {
+    if !Path::new(path).exists() {
+        return;
+    }
+    let vfs = statvfs(path.as_bytes());
+    let file = File::open(path).unwrap();
+    let fs = fstatfs(&file);
+    assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
+}
+
+fn check_statfs_strict(path: &str) {
+    if !Path::new(path).exists() {
+        return;
+    }
+    let vfs = statvfs(path.as_bytes());
+    let fs = statfs(path.as_bytes());
+    assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
+}
+
+// The cast is not unnecessary on all platforms.
+#[allow(clippy::unnecessary_cast)]
+fn assert_fs_equals(fs: Statfs, vfs: Statvfs) {
+    assert_eq!(fs.files() as u64, vfs.files() as u64);
+    assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
+    assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
+}
+
+#[test]
+fn statfs_call() {
+    check_statfs("/tmp");
+    check_statfs("/dev");
+    check_statfs("/run");
+    check_statfs("/");
+}
+
+#[test]
+fn fstatfs_call() {
+    check_fstatfs("/tmp");
+    check_fstatfs("/dev");
+    check_fstatfs("/run");
+    check_fstatfs("/");
+}
+
+// This test is ignored because files_free/blocks_free can change after statvfs call and before
+// statfs call.
+#[test]
+#[ignore]
+fn statfs_call_strict() {
+    check_statfs_strict("/tmp");
+    check_statfs_strict("/dev");
+    check_statfs_strict("/run");
+    check_statfs_strict("/");
+}
+
+// This test is ignored because files_free/blocks_free can change after statvfs call and before
+// fstatfs call.
+#[test]
+#[ignore]
+fn fstatfs_call_strict() {
+    check_fstatfs_strict("/tmp");
+    check_fstatfs_strict("/dev");
+    check_fstatfs_strict("/run");
+    check_fstatfs_strict("/");
+}
+
+// The cast is not unnecessary on all platforms.
+#[allow(clippy::unnecessary_cast)]
+fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) {
+    assert_eq!(fs.files_free() as u64, vfs.files_free() as u64);
+    assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64);
+    assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64);
+    assert_eq!(fs.files() as u64, vfs.files() as u64);
+    assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
+    assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
+}
diff --git a/test/sys/test_statvfs.rs b/test/sys/test_statvfs.rs
new file mode 100644
index 0000000..5c80965
--- /dev/null
+++ b/test/sys/test_statvfs.rs
@@ -0,0 +1,13 @@
+use nix::sys::statvfs::*;
+use std::fs::File;
+
+#[test]
+fn statvfs_call() {
+    statvfs(&b"/"[..]).unwrap();
+}
+
+#[test]
+fn fstatvfs_call() {
+    let root = File::open("/").unwrap();
+    fstatvfs(&root).unwrap();
+}
diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs
index 8391937..35cc7ab 100644
--- a/test/sys/test_termios.rs
+++ b/test/sys/test_termios.rs
@@ -4,17 +4,26 @@
 use nix::errno::Errno;
 use nix::fcntl;
 use nix::pty::openpty;
-use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags};
+use nix::sys::termios::{self, tcgetattr, BaudRate, LocalFlags, OutputFlags};
 use nix::unistd::{read, write};
 
 /// Helper function analogous to `std::io::Write::write_all`, but for `Fd`s
 fn write_all<Fd: AsFd>(f: Fd, buf: &[u8]) {
     let mut len = 0;
     while len < buf.len() {
-        len += write(f.as_fd().as_raw_fd(), &buf[len..]).unwrap();
+        len += write(f.as_fd(), &buf[len..]).unwrap();
     }
 }
 
+#[test]
+fn test_baudrate_try_from() {
+    assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0));
+    #[cfg(not(target_os = "haiku"))]
+    BaudRate::try_from(999999999).expect_err("assertion failed");
+    #[cfg(target_os = "haiku")]
+    BaudRate::try_from(99).expect_err("assertion failed");
+}
+
 // Test tcgetattr on a terminal
 #[test]
 fn test_tcgetattr_pty() {
diff --git a/test/sys/test_time.rs b/test/sys/test_time.rs
new file mode 100644
index 0000000..0510225
--- /dev/null
+++ b/test/sys/test_time.rs
@@ -0,0 +1,91 @@
+use nix::sys::time::{TimeSpec, TimeVal, TimeValLike};
+use std::time::Duration;
+
+#[test]
+pub fn test_timespec() {
+    assert_ne!(TimeSpec::seconds(1), TimeSpec::zero());
+    assert_eq!(
+        TimeSpec::seconds(1) + TimeSpec::seconds(2),
+        TimeSpec::seconds(3)
+    );
+    assert_eq!(
+        TimeSpec::minutes(3) + TimeSpec::seconds(2),
+        TimeSpec::seconds(182)
+    );
+}
+
+#[test]
+pub fn test_timespec_from() {
+    let duration = Duration::new(123, 123_456_789);
+    let timespec = TimeSpec::nanoseconds(123_123_456_789);
+
+    assert_eq!(TimeSpec::from(duration), timespec);
+    assert_eq!(Duration::from(timespec), duration);
+}
+
+#[test]
+pub fn test_timespec_neg() {
+    let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
+    let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123);
+
+    assert_eq!(a, -b);
+}
+
+#[test]
+pub fn test_timespec_ord() {
+    assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000));
+    assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001));
+    assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999));
+    assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999));
+    assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001));
+}
+
+#[test]
+pub fn test_timespec_fmt() {
+    assert_eq!(TimeSpec::zero().to_string(), "0 seconds");
+    assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds");
+    assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds");
+    assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds");
+    assert_eq!(TimeSpec::nanoseconds(42).to_string(), "0.000000042 seconds");
+    assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds");
+}
+
+#[test]
+pub fn test_timeval() {
+    assert_ne!(TimeVal::seconds(1), TimeVal::zero());
+    assert_eq!(
+        TimeVal::seconds(1) + TimeVal::seconds(2),
+        TimeVal::seconds(3)
+    );
+    assert_eq!(
+        TimeVal::minutes(3) + TimeVal::seconds(2),
+        TimeVal::seconds(182)
+    );
+}
+
+#[test]
+pub fn test_timeval_ord() {
+    assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000));
+    assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001));
+    assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999));
+    assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999));
+    assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001));
+}
+
+#[test]
+pub fn test_timeval_neg() {
+    let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
+    let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);
+
+    assert_eq!(a, -b);
+}
+
+#[test]
+pub fn test_timeval_fmt() {
+    assert_eq!(TimeVal::zero().to_string(), "0 seconds");
+    assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
+    assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
+    assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
+    assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds");
+    assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
+}
diff --git a/test/test_timer.rs b/test/sys/test_timer.rs
similarity index 100%
rename from test/test_timer.rs
rename to test/sys/test_timer.rs
diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs
index fc09465..d035a7b 100644
--- a/test/sys/test_uio.rs
+++ b/test/sys/test_uio.rs
@@ -4,7 +4,7 @@
 use rand::{thread_rng, Rng};
 use std::fs::OpenOptions;
 use std::io::IoSlice;
-use std::os::unix::io::{FromRawFd, OwnedFd};
+use std::os::unix::io::AsRawFd;
 use std::{cmp, iter};
 
 #[cfg(not(target_os = "redox"))]
@@ -44,22 +44,17 @@
     // FileDesc will close its filedesc (reader).
     let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect();
 
-    // Temporary workaround to cope with the existing RawFd pipe(2), should be
-    // removed when pipe(2) becomes I/O-safe.
-    let writer = unsafe { OwnedFd::from_raw_fd(writer) };
-
     // Blocking io, should write all data.
     let write_res = writev(&writer, &iovecs);
     let written = write_res.expect("couldn't write");
     // Check whether we written all data
     assert_eq!(to_write.len(), written);
-    let read_res = read(reader, &mut read_buf[..]);
+    let read_res = read(reader.as_raw_fd(), &mut read_buf[..]);
     let read = read_res.expect("couldn't read");
     // Check we have read as much as we written
     assert_eq!(read, written);
     // Check equality of written and read data
     assert_eq!(&to_write, &read_buf);
-    close(reader).expect("closed reader");
 }
 
 #[test]
@@ -92,10 +87,6 @@
     // Blocking io, should write all data.
     write(writer, &to_write).expect("write failed");
 
-    // Temporary workaround to cope with the existing RawFd pipe(2), should be
-    // removed when pipe(2) becomes I/O-safe.
-    let reader = unsafe { OwnedFd::from_raw_fd(reader) };
-
     let read = readv(&reader, &mut iovecs[..]).expect("read failed");
     // Check whether we've read all data
     assert_eq!(to_write.len(), read);
@@ -108,7 +99,6 @@
     assert_eq!(read_buf.len(), to_write.len());
     // Check equality of written and read data
     assert_eq!(&read_buf, &to_write);
-    close(writer).expect("couldn't close writer");
 }
 
 #[test]
@@ -150,7 +140,11 @@
 }
 
 #[test]
-#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
+#[cfg(not(any(
+    target_os = "redox",
+    target_os = "haiku",
+    target_os = "solaris"
+)))]
 fn test_pwritev() {
     use std::io::Read;
 
@@ -185,7 +179,11 @@
 }
 
 #[test]
-#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
+#[cfg(not(any(
+    target_os = "redox",
+    target_os = "haiku",
+    target_os = "solaris"
+)))]
 fn test_preadv() {
     use std::io::Write;
 
@@ -230,6 +228,7 @@
     use nix::sys::signal::*;
     use nix::sys::wait::*;
     use nix::unistd::ForkResult::*;
+    use std::os::unix::io::AsRawFd;
 
     require_capability!("test_process_vm_readv", CAP_SYS_PTRACE);
     let _m = crate::FORK_MTX.lock();
@@ -241,10 +240,10 @@
     let (r, w) = pipe().unwrap();
     match unsafe { fork() }.expect("Error: Fork Failed") {
         Parent { child } => {
-            close(w).unwrap();
+            drop(w);
             // wait for child
-            read(r, &mut [0u8]).unwrap();
-            close(r).unwrap();
+            read(r.as_raw_fd(), &mut [0u8]).unwrap();
+            drop(r);
 
             let ptr = vector.as_ptr() as usize;
             let remote_iov = RemoteIoVec { base: ptr, len: 5 };
@@ -263,12 +262,11 @@
             assert_eq!(20u8, buf.iter().sum());
         }
         Child => {
-            let _ = close(r);
+            drop(r);
             for i in &mut vector {
                 *i += 1;
             }
             let _ = write(w, b"\0");
-            let _ = close(w);
             loop {
                 pause();
             }
diff --git a/test/sys/test_utsname.rs b/test/sys/test_utsname.rs
new file mode 100644
index 0000000..8f84ac0
--- /dev/null
+++ b/test/sys/test_utsname.rs
@@ -0,0 +1,17 @@
+#[cfg(target_os = "linux")]
+#[test]
+pub fn test_uname_linux() {
+    assert_eq!(nix::sys::utsname::uname().unwrap().sysname(), "Linux");
+}
+
+#[cfg(apple_targets)]
+#[test]
+pub fn test_uname_darwin() {
+    assert_eq!(nix::sys::utsname::uname().unwrap().sysname(), "Darwin");
+}
+
+#[cfg(target_os = "freebsd")]
+#[test]
+pub fn test_uname_freebsd() {
+    assert_eq!(nix::sys::utsname::uname().unwrap().sysname(), "FreeBSD");
+}
diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs
index d472f1e..365b016 100644
--- a/test/sys/test_wait.rs
+++ b/test/sys/test_wait.rs
@@ -33,7 +33,12 @@
     //target_os = "haiku",
     all(target_os = "linux", not(target_env = "uclibc")),
 ))]
-#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
+#[cfg(not(any(
+    target_arch = "mips",
+    target_arch = "mips32r6",
+    target_arch = "mips64",
+    target_arch = "mips64r6"
+)))]
 fn test_waitid_signal() {
     let _m = crate::FORK_MTX.lock();
 
@@ -76,7 +81,12 @@
     target_os = "haiku",
     all(target_os = "linux", not(target_env = "uclibc")),
 ))]
-#[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
+#[cfg(not(any(
+    target_arch = "mips",
+    target_arch = "mips32r6",
+    target_arch = "mips64",
+    target_arch = "mips64r6"
+)))]
 fn test_waitid_exit() {
     let _m = crate::FORK_MTX.lock();
 
@@ -140,7 +150,7 @@
     }
 }
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 // FIXME: qemu-user doesn't implement ptrace on most arches
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
 mod ptrace {
diff --git a/test/test.rs b/test/test.rs
index 7e73bb3..c723142 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -7,12 +7,14 @@
 mod sys;
 #[cfg(not(target_os = "redox"))]
 mod test_dir;
+mod test_errno;
 mod test_fcntl;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 mod test_kmod;
+#[cfg(target_os = "linux")]
+mod test_mount;
 #[cfg(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
+    freebsdlike,
     target_os = "fushsia",
     target_os = "linux",
     target_os = "netbsd"
@@ -30,36 +32,16 @@
     target_os = "haiku"
 )))]
 mod test_pty;
-mod test_resource;
 #[cfg(any(
-    target_os = "android",
+    linux_android,
     target_os = "dragonfly",
     all(target_os = "freebsd", fbsd14),
-    target_os = "linux"
 ))]
 mod test_sched;
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "linux",
-    target_os = "macos"
-))]
+#[cfg(any(linux_android, freebsdlike, apple_targets, solarish))]
 mod test_sendfile;
 mod test_stat;
 mod test_time;
-#[cfg(all(
-    any(
-        target_os = "freebsd",
-        target_os = "illumos",
-        target_os = "linux",
-        target_os = "netbsd"
-    ),
-    feature = "time",
-    feature = "signal"
-))]
-mod test_timer;
 mod test_unistd;
 
 use nix::unistd::{chdir, getcwd, read};
diff --git a/test/test_dir.rs b/test/test_dir.rs
index 2af4aa5..24ecd69 100644
--- a/test/test_dir.rs
+++ b/test/test_dir.rs
@@ -6,10 +6,10 @@
 
 #[cfg(test)]
 fn flags() -> OFlag {
-    #[cfg(target_os = "illumos")]
+    #[cfg(solarish)]
     let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC;
 
-    #[cfg(not(target_os = "illumos"))]
+    #[cfg(not(solarish))]
     let f = OFlag::O_RDONLY | OFlag::O_CLOEXEC | OFlag::O_DIRECTORY;
 
     f
diff --git a/test/test_errno.rs b/test/test_errno.rs
new file mode 100644
index 0000000..750fc92
--- /dev/null
+++ b/test/test_errno.rs
@@ -0,0 +1,16 @@
+use nix::errno::Errno;
+
+#[test]
+fn errno_set_and_read() {
+    Errno::ENFILE.set();
+    assert_eq!(Errno::last(), Errno::ENFILE);
+}
+
+#[test]
+fn errno_set_and_clear() {
+    Errno::ENFILE.set();
+    assert_eq!(Errno::last(), Errno::ENFILE);
+
+    Errno::clear();
+    assert_eq!(Errno::last(), Errno::from_raw(0));
+}
diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs
index 5fef04b..6572e8a 100644
--- a/test/test_fcntl.rs
+++ b/test/test_fcntl.rs
@@ -42,7 +42,7 @@
         open(tmp.path().parent().unwrap(), OFlag::empty(), Mode::empty())
             .unwrap();
     let fd = openat(
-        dirfd,
+        Some(dirfd),
         tmp.path().file_name().unwrap(),
         OFlag::O_RDONLY,
         Mode::empty(),
@@ -222,7 +222,7 @@
 
     assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir);
     assert_eq!(
-        readlinkat(dirfd, "b").unwrap().to_str().unwrap(),
+        readlinkat(Some(dirfd), "b").unwrap().to_str().unwrap(),
         expected_dir
     );
 }
@@ -234,10 +234,9 @@
 /// The from_offset should be updated by the call to reflect
 /// the 3 bytes read (6).
 #[cfg(any(
-        target_os = "linux",
+        linux_android,
         // Not available until FreeBSD 13.0
         all(target_os = "freebsd", fbsd14),
-        target_os = "android"
 ))]
 #[test]
 // QEMU does not support copy_file_range. Skip under qemu
@@ -272,7 +271,7 @@
     assert_eq!(from_offset, 6);
 }
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 mod linux_android {
     use libc::loff_t;
     use std::io::prelude::*;
@@ -280,7 +279,7 @@
     use std::os::unix::prelude::*;
 
     use nix::fcntl::*;
-    use nix::unistd::{close, pipe, read, write};
+    use nix::unistd::{pipe, read, write};
 
     use tempfile::tempfile;
     #[cfg(target_os = "linux")]
@@ -299,7 +298,7 @@
         let res = splice(
             tmp.as_raw_fd(),
             Some(&mut offset),
-            wr,
+            wr.as_raw_fd(),
             None,
             2,
             SpliceFFlags::empty(),
@@ -309,12 +308,9 @@
         assert_eq!(2, res);
 
         let mut buf = [0u8; 1024];
-        assert_eq!(2, read(rd, &mut buf).unwrap());
+        assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap());
         assert_eq!(b"f1", &buf[0..2]);
         assert_eq!(7, offset);
-
-        close(rd).unwrap();
-        close(wr).unwrap();
     }
 
     #[test]
@@ -323,24 +319,21 @@
         let (rd2, wr2) = pipe().unwrap();
 
         write(wr1, b"abc").unwrap();
-        let res = tee(rd1, wr2, 2, SpliceFFlags::empty()).unwrap();
+        let res =
+            tee(rd1.as_raw_fd(), wr2.as_raw_fd(), 2, SpliceFFlags::empty())
+                .unwrap();
 
         assert_eq!(2, res);
 
         let mut buf = [0u8; 1024];
 
         // Check the tee'd bytes are at rd2.
-        assert_eq!(2, read(rd2, &mut buf).unwrap());
+        assert_eq!(2, read(rd2.as_raw_fd(), &mut buf).unwrap());
         assert_eq!(b"ab", &buf[0..2]);
 
         // Check all the bytes are still at rd1.
-        assert_eq!(3, read(rd1, &mut buf).unwrap());
+        assert_eq!(3, read(rd1.as_raw_fd(), &mut buf).unwrap());
         assert_eq!(b"abc", &buf[0..3]);
-
-        close(rd1).unwrap();
-        close(wr1).unwrap();
-        close(rd2).unwrap();
-        close(wr2).unwrap();
     }
 
     #[test]
@@ -351,17 +344,15 @@
         let buf2 = b"defghi";
         let iovecs = [IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])];
 
-        let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap();
+        let res = vmsplice(wr.as_raw_fd(), &iovecs[..], SpliceFFlags::empty())
+            .unwrap();
 
         assert_eq!(6, res);
 
         // Check the bytes can be read at rd.
         let mut buf = [0u8; 32];
-        assert_eq!(6, read(rd, &mut buf).unwrap());
+        assert_eq!(6, read(rd.as_raw_fd(), &mut buf).unwrap());
         assert_eq!(b"abcdef", &buf[0..6]);
-
-        close(rd).unwrap();
-        close(wr).unwrap();
     }
 
     #[cfg(target_os = "linux")]
@@ -481,8 +472,7 @@
 }
 
 #[cfg(any(
-    target_os = "linux",
-    target_os = "android",
+    linux_android,
     target_os = "emscripten",
     target_os = "fuchsia",
     target_os = "wasi",
@@ -494,7 +484,7 @@
     use nix::errno::Errno;
     use nix::fcntl::*;
     use nix::unistd::pipe;
-    use std::os::unix::io::{AsRawFd, RawFd};
+    use std::os::unix::io::AsRawFd;
     use tempfile::NamedTempFile;
 
     #[test]
@@ -509,7 +499,7 @@
     fn test_errno() {
         let (rd, _wr) = pipe().unwrap();
         let res = posix_fadvise(
-            rd as RawFd,
+            rd.as_raw_fd(),
             0,
             100,
             PosixFadviseAdvice::POSIX_FADV_WILLNEED,
@@ -519,23 +509,18 @@
 }
 
 #[cfg(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "dragonfly",
+    linux_android,
+    freebsdlike,
     target_os = "emscripten",
     target_os = "fuchsia",
     target_os = "wasi",
-    target_os = "freebsd"
 ))]
 mod test_posix_fallocate {
 
     use nix::errno::Errno;
     use nix::fcntl::*;
     use nix::unistd::pipe;
-    use std::{
-        io::Read,
-        os::unix::io::{AsRawFd, RawFd},
-    };
+    use std::{io::Read, os::unix::io::AsRawFd};
     use tempfile::NamedTempFile;
 
     #[test]
@@ -565,10 +550,133 @@
     #[test]
     fn errno() {
         let (rd, _wr) = pipe().unwrap();
-        let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err();
+        let err = posix_fallocate(rd.as_raw_fd(), 0, 100).unwrap_err();
         match err {
             Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (),
             errno => panic!("unexpected errno {errno}",),
         }
     }
 }
+
+#[cfg(any(target_os = "dragonfly", target_os = "netbsd", apple_targets))]
+#[test]
+fn test_f_get_path() {
+    use nix::fcntl::*;
+    use std::{os::unix::io::AsRawFd, path::PathBuf};
+
+    let tmp = NamedTempFile::new().unwrap();
+    let fd = tmp.as_raw_fd();
+    let mut path = PathBuf::new();
+    let res =
+        fcntl(fd, FcntlArg::F_GETPATH(&mut path)).expect("get path failed");
+    assert_ne!(res, -1);
+    assert_eq!(
+        path.as_path().canonicalize().unwrap(),
+        tmp.path().canonicalize().unwrap()
+    );
+}
+
+#[cfg(apple_targets)]
+#[test]
+fn test_f_get_path_nofirmlink() {
+    use nix::fcntl::*;
+    use std::{os::unix::io::AsRawFd, path::PathBuf};
+
+    let tmp = NamedTempFile::new().unwrap();
+    let fd = tmp.as_raw_fd();
+    let mut path = PathBuf::new();
+    let res = fcntl(fd, FcntlArg::F_GETPATH_NOFIRMLINK(&mut path))
+        .expect("get path failed");
+    let mut tmpstr = String::from("/System/Volumes/Data");
+    tmpstr.push_str(
+        &tmp.path()
+            .canonicalize()
+            .unwrap()
+            .into_os_string()
+            .into_string()
+            .unwrap(),
+    );
+    assert_ne!(res, -1);
+    assert_eq!(
+        path.as_path()
+            .canonicalize()
+            .unwrap()
+            .into_os_string()
+            .into_string()
+            .unwrap(),
+        tmpstr
+    );
+}
+
+#[cfg(all(target_os = "freebsd", target_arch = "x86_64"))]
+#[test]
+fn test_f_kinfo() {
+    use nix::fcntl::*;
+    use std::{os::unix::io::AsRawFd, path::PathBuf};
+
+    let tmp = NamedTempFile::new().unwrap();
+    // With TMPDIR set with UFS, the vnode name is not entered
+    // into the name cache thus path is always empty.
+    // Therefore, we reopen the tempfile a second time for the test
+    // to pass.
+    let tmp2 = File::open(tmp.path()).unwrap();
+    let fd = tmp2.as_raw_fd();
+    let mut path = PathBuf::new();
+    let res = fcntl(fd, FcntlArg::F_KINFO(&mut path)).expect("get path failed");
+    assert_ne!(res, -1);
+    assert_eq!(path, tmp.path());
+}
+
+/// Test `Flock` and associated functions.
+///
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
+mod test_flock {
+    use nix::fcntl::*;
+    use tempfile::NamedTempFile;
+
+    /// Verify that `Flock::lock()` correctly obtains a lock, and subsequently unlocks upon drop.
+    #[test]
+    fn verify_lock_and_drop() {
+        // Get 2 `File` handles to same underlying file.
+        let file1 = NamedTempFile::new().unwrap();
+        let file2 = file1.reopen().unwrap();
+        let file1 = file1.into_file();
+
+        // Lock first handle
+        let lock1 = Flock::lock(file1, FlockArg::LockExclusive).unwrap();
+
+        // Attempt to lock second handle
+        let file2 = match Flock::lock(file2, FlockArg::LockExclusiveNonblock) {
+            Ok(_) => panic!("Expected second exclusive lock to fail."),
+            Err((f, _)) => f,
+        };
+
+        // Drop first lock
+        std::mem::drop(lock1);
+
+        // Attempt to lock second handle again (but successfully)
+        if Flock::lock(file2, FlockArg::LockExclusiveNonblock).is_err() {
+            panic!("Expected locking to be successful.");
+        }
+    }
+
+    /// Verify that `Flock::unlock()` correctly obtains unlocks.
+    #[test]
+    fn verify_unlock() {
+        // Get 2 `File` handles to same underlying file.
+        let file1 = NamedTempFile::new().unwrap();
+        let file2 = file1.reopen().unwrap();
+        let file1 = file1.into_file();
+
+        // Lock first handle
+        let lock1 = Flock::lock(file1, FlockArg::LockExclusive).unwrap();
+
+        // Unlock and retain file so any erroneous flocks also remain present.
+        let _file1 = lock1.unlock().unwrap();
+
+        // Attempt to lock second handle.
+        if Flock::lock(file2, FlockArg::LockExclusiveNonblock).is_err() {
+            panic!("Expected locking to be successful.");
+        }
+    }
+}
diff --git a/test/test_mount.rs b/test/test_mount.rs
index 5cf0040..a4f0903 100644
--- a/test/test_mount.rs
+++ b/test/test_mount.rs
@@ -1,267 +1,183 @@
-mod common;
+use std::fs::{self, File};
+use std::io::{Read, Write};
+use std::os::unix::fs::OpenOptionsExt;
+use std::os::unix::fs::PermissionsExt;
+use std::process::Command;
 
-// Implementation note: to allow unprivileged users to run it, this test makes
-// use of user and mount namespaces. On systems that allow unprivileged user
-// namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run
-// without root.
+use libc::{EACCES, EROFS};
 
-#[cfg(target_os = "linux")]
-mod test_mount {
-    use std::fs::{self, File};
-    use std::io::{self, Read, Write};
-    use std::os::unix::fs::OpenOptionsExt;
-    use std::os::unix::fs::PermissionsExt;
-    use std::process::{self, Command};
+use nix::mount::{mount, umount, MsFlags};
+use nix::sys::stat::{self, Mode};
 
-    use libc::{EACCES, EROFS};
+use crate::*;
 
-    use nix::errno::Errno;
-    use nix::mount::{mount, umount, MsFlags};
-    use nix::sched::{unshare, CloneFlags};
-    use nix::sys::stat::{self, Mode};
-    use nix::unistd::getuid;
-
-    static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh
+static SCRIPT_CONTENTS: &[u8] = b"#!/bin/sh
 exit 23";
 
-    const EXPECTED_STATUS: i32 = 23;
+const EXPECTED_STATUS: i32 = 23;
 
-    const NONE: Option<&'static [u8]> = None;
-    #[allow(clippy::bind_instead_of_map)] // False positive
-    pub fn test_mount_tmpfs_without_flags_allows_rwx() {
-        let tempdir = tempfile::tempdir().unwrap();
+const NONE: Option<&'static [u8]> = None;
 
-        mount(
-            NONE,
-            tempdir.path(),
-            Some(b"tmpfs".as_ref()),
-            MsFlags::empty(),
-            NONE,
-        )
-        .unwrap_or_else(|e| panic!("mount failed: {e}"));
-
-        let test_path = tempdir.path().join("test");
-
-        // Verify write.
-        fs::OpenOptions::new()
-            .create(true)
-            .write(true)
-            .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
-            .open(&test_path)
-            .or_else(|e| {
-                if Errno::from_i32(e.raw_os_error().unwrap())
-                    == Errno::EOVERFLOW
-                {
-                    // Skip tests on certain Linux kernels which have a bug
-                    // regarding tmpfs in namespaces.
-                    // Ubuntu 14.04 and 16.04 are known to be affected; 16.10 is
-                    // not.  There is no legitimate reason for open(2) to return
-                    // EOVERFLOW here.
-                    // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1659087
-                    let stderr = io::stderr();
-                    let mut handle = stderr.lock();
-                    writeln!(
-                        handle,
-                        "Buggy Linux kernel detected.  Skipping test."
-                    )
-                    .unwrap();
-                    process::exit(0);
-                } else {
-                    panic!("open failed: {e}");
-                }
-            })
-            .and_then(|mut f| f.write(SCRIPT_CONTENTS))
-            .unwrap_or_else(|e| panic!("write failed: {e}"));
-
-        // Verify read.
-        let mut buf = Vec::new();
-        File::open(&test_path)
-            .and_then(|mut f| f.read_to_end(&mut buf))
-            .unwrap_or_else(|e| panic!("read failed: {e}"));
-        assert_eq!(buf, SCRIPT_CONTENTS);
-
-        // Verify execute.
-        assert_eq!(
-            EXPECTED_STATUS,
-            Command::new(&test_path)
-                .status()
-                .unwrap_or_else(|e| panic!("exec failed: {e}"))
-                .code()
-                .unwrap_or_else(|| panic!("child killed by signal"))
-        );
-
-        umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
-    }
-
-    pub fn test_mount_rdonly_disallows_write() {
-        let tempdir = tempfile::tempdir().unwrap();
-
-        mount(
-            NONE,
-            tempdir.path(),
-            Some(b"tmpfs".as_ref()),
-            MsFlags::MS_RDONLY,
-            NONE,
-        )
-        .unwrap_or_else(|e| panic!("mount failed: {e}"));
-
-        // EROFS: Read-only file system
-        assert_eq!(
-            EROFS,
-            File::create(tempdir.path().join("test"))
-                .unwrap_err()
-                .raw_os_error()
-                .unwrap()
-        );
-
-        umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
-    }
-
-    pub fn test_mount_noexec_disallows_exec() {
-        let tempdir = tempfile::tempdir().unwrap();
-
-        mount(
-            NONE,
-            tempdir.path(),
-            Some(b"tmpfs".as_ref()),
-            MsFlags::MS_NOEXEC,
-            NONE,
-        )
-        .unwrap_or_else(|e| panic!("mount failed: {e}"));
-
-        let test_path = tempdir.path().join("test");
-
-        fs::OpenOptions::new()
-            .create(true)
-            .write(true)
-            .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
-            .open(&test_path)
-            .and_then(|mut f| f.write(SCRIPT_CONTENTS))
-            .unwrap_or_else(|e| panic!("write failed: {e}"));
-
-        // Verify that we cannot execute despite a+x permissions being set.
-        let mode = stat::Mode::from_bits_truncate(
-            fs::metadata(&test_path)
-                .map(|md| md.permissions().mode())
-                .unwrap_or_else(|e| panic!("metadata failed: {e}")),
-        );
-
-        assert!(
-            mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH),
-            "{:?} did not have execute permissions",
-            &test_path
-        );
-
-        // EACCES: Permission denied
-        assert_eq!(
-            EACCES,
-            Command::new(&test_path)
-                .status()
-                .unwrap_err()
-                .raw_os_error()
-                .unwrap()
-        );
-
-        umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
-    }
-
-    pub fn test_mount_bind() {
-        let tempdir = tempfile::tempdir().unwrap();
-        let file_name = "test";
-
-        {
-            let mount_point = tempfile::tempdir().unwrap();
-
-            mount(
-                Some(tempdir.path()),
-                mount_point.path(),
-                NONE,
-                MsFlags::MS_BIND,
-                NONE,
-            )
-            .unwrap_or_else(|e| panic!("mount failed: {e}"));
-
-            fs::OpenOptions::new()
-                .create(true)
-                .write(true)
-                .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
-                .open(mount_point.path().join(file_name))
-                .and_then(|mut f| f.write(SCRIPT_CONTENTS))
-                .unwrap_or_else(|e| panic!("write failed: {e}"));
-
-            umount(mount_point.path())
-                .unwrap_or_else(|e| panic!("umount failed: {e}"));
-        }
-
-        // Verify the file written in the mount shows up in source directory, even
-        // after unmounting.
-
-        let mut buf = Vec::new();
-        File::open(tempdir.path().join(file_name))
-            .and_then(|mut f| f.read_to_end(&mut buf))
-            .unwrap_or_else(|e| panic!("read failed: {e}"));
-        assert_eq!(buf, SCRIPT_CONTENTS);
-    }
-
-    pub fn setup_namespaces() {
-        // Hold on to the uid in the parent namespace.
-        let uid = getuid();
-
-        unshare(CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_NEWUSER).unwrap_or_else(|e| {
-            let stderr = io::stderr();
-            let mut handle = stderr.lock();
-            writeln!(handle,
-                     "unshare failed: {e}. Are unprivileged user namespaces available?").unwrap();
-            writeln!(handle, "mount is not being tested").unwrap();
-            // Exit with success because not all systems support unprivileged user namespaces, and
-            // that's not what we're testing for.
-            process::exit(0);
-        });
-
-        // Map user as uid 1000.
-        fs::OpenOptions::new()
-            .write(true)
-            .open("/proc/self/uid_map")
-            .and_then(|mut f| f.write(format!("1000 {uid} 1\n").as_bytes()))
-            .unwrap_or_else(|e| panic!("could not write uid map: {e}"));
-    }
-}
-
-// Test runner
-
-/// Mimic normal test output (hackishly).
-#[cfg(target_os = "linux")]
-macro_rules! run_tests {
-    ( $($test_fn:ident),* ) => {{
-        println!();
-
-        $(
-            print!("test test_mount::{} ... ", stringify!($test_fn));
-            $test_fn();
-            println!("ok");
-        )*
-
-        println!();
-    }}
-}
-
-#[cfg(target_os = "linux")]
-fn main() {
-    use test_mount::{
-        setup_namespaces, test_mount_bind, test_mount_noexec_disallows_exec,
-        test_mount_rdonly_disallows_write,
-        test_mount_tmpfs_without_flags_allows_rwx,
-    };
-    skip_if_cirrus!("Fails for an unknown reason Cirrus CI.  Bug #1351");
-    setup_namespaces();
-
-    run_tests!(
-        test_mount_tmpfs_without_flags_allows_rwx,
-        test_mount_rdonly_disallows_write,
-        test_mount_noexec_disallows_exec,
-        test_mount_bind
+#[test]
+fn test_mount_tmpfs_without_flags_allows_rwx() {
+    require_capability!(
+        "test_mount_tmpfs_without_flags_allows_rwx",
+        CAP_SYS_ADMIN
     );
+    let tempdir = tempfile::tempdir().unwrap();
+
+    mount(
+        NONE,
+        tempdir.path(),
+        Some(b"tmpfs".as_ref()),
+        MsFlags::empty(),
+        NONE,
+    )
+    .unwrap_or_else(|e| panic!("mount failed: {e}"));
+
+    let test_path = tempdir.path().join("test");
+
+    // Verify write.
+    fs::OpenOptions::new()
+        .create(true)
+        .write(true)
+        .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
+        .open(&test_path)
+        .and_then(|mut f| f.write(SCRIPT_CONTENTS))
+        .unwrap_or_else(|e| panic!("write failed: {e}"));
+
+    // Verify read.
+    let mut buf = Vec::new();
+    File::open(&test_path)
+        .and_then(|mut f| f.read_to_end(&mut buf))
+        .unwrap_or_else(|e| panic!("read failed: {e}"));
+    assert_eq!(buf, SCRIPT_CONTENTS);
+
+    // Verify execute.
+    assert_eq!(
+        EXPECTED_STATUS,
+        Command::new(&test_path)
+            .status()
+            .unwrap_or_else(|e| panic!("exec failed: {e}"))
+            .code()
+            .unwrap_or_else(|| panic!("child killed by signal"))
+    );
+
+    umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
 }
 
-#[cfg(not(target_os = "linux"))]
-fn main() {}
+#[test]
+fn test_mount_rdonly_disallows_write() {
+    require_capability!("test_mount_rdonly_disallows_write", CAP_SYS_ADMIN);
+    let tempdir = tempfile::tempdir().unwrap();
+
+    mount(
+        NONE,
+        tempdir.path(),
+        Some(b"tmpfs".as_ref()),
+        MsFlags::MS_RDONLY,
+        NONE,
+    )
+    .unwrap_or_else(|e| panic!("mount failed: {e}"));
+
+    // EROFS: Read-only file system
+    assert_eq!(
+        EROFS,
+        File::create(tempdir.path().join("test"))
+            .unwrap_err()
+            .raw_os_error()
+            .unwrap()
+    );
+
+    umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
+}
+
+#[test]
+fn test_mount_noexec_disallows_exec() {
+    require_capability!("test_mount_noexec_disallows_exec", CAP_SYS_ADMIN);
+    let tempdir = tempfile::tempdir().unwrap();
+
+    mount(
+        NONE,
+        tempdir.path(),
+        Some(b"tmpfs".as_ref()),
+        MsFlags::MS_NOEXEC,
+        NONE,
+    )
+    .unwrap_or_else(|e| panic!("mount failed: {e}"));
+
+    let test_path = tempdir.path().join("test");
+
+    fs::OpenOptions::new()
+        .create(true)
+        .write(true)
+        .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
+        .open(&test_path)
+        .and_then(|mut f| f.write(SCRIPT_CONTENTS))
+        .unwrap_or_else(|e| panic!("write failed: {e}"));
+
+    // Verify that we cannot execute despite a+x permissions being set.
+    let mode = stat::Mode::from_bits_truncate(
+        fs::metadata(&test_path)
+            .map(|md| md.permissions().mode())
+            .unwrap_or_else(|e| panic!("metadata failed: {e}")),
+    );
+
+    assert!(
+        mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH),
+        "{:?} did not have execute permissions",
+        &test_path
+    );
+
+    // EACCES: Permission denied
+    assert_eq!(
+        EACCES,
+        Command::new(&test_path)
+            .status()
+            .unwrap_err()
+            .raw_os_error()
+            .unwrap()
+    );
+
+    umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
+}
+
+#[test]
+fn test_mount_bind() {
+    require_capability!("test_mount_bind", CAP_SYS_ADMIN);
+    let tempdir = tempfile::tempdir().unwrap();
+    let file_name = "test";
+
+    {
+        let mount_point = tempfile::tempdir().unwrap();
+
+        mount(
+            Some(tempdir.path()),
+            mount_point.path(),
+            NONE,
+            MsFlags::MS_BIND,
+            NONE,
+        )
+        .unwrap_or_else(|e| panic!("mount failed: {e}"));
+
+        fs::OpenOptions::new()
+            .create(true)
+            .write(true)
+            .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
+            .open(mount_point.path().join(file_name))
+            .and_then(|mut f| f.write(SCRIPT_CONTENTS))
+            .unwrap_or_else(|e| panic!("write failed: {e}"));
+
+        umount(mount_point.path())
+            .unwrap_or_else(|e| panic!("umount failed: {e}"));
+    }
+
+    // Verify the file written in the mount shows up in source directory, even
+    // after unmounting.
+
+    let mut buf = Vec::new();
+    File::open(tempdir.path().join(file_name))
+        .and_then(|mut f| f.read_to_end(&mut buf))
+        .unwrap_or_else(|e| panic!("read failed: {e}"));
+    assert_eq!(buf, SCRIPT_CONTENTS);
+}
diff --git a/test/test_mq.rs b/test/test_mq.rs
index 1fd8929..874a72b 100644
--- a/test/test_mq.rs
+++ b/test/test_mq.rs
@@ -112,7 +112,15 @@
 // FIXME: Fix failures for mips in QEMU
 #[test]
 #[cfg_attr(
-    all(qemu, any(target_arch = "mips", target_arch = "mips64")),
+    all(
+        qemu,
+        any(
+            target_arch = "mips",
+            target_arch = "mips32r6",
+            target_arch = "mips64",
+            target_arch = "mips64r6"
+        )
+    ),
     ignore
 )]
 fn test_mq_setattr() {
@@ -162,7 +170,15 @@
 // FIXME: Fix failures for mips in QEMU
 #[test]
 #[cfg_attr(
-    all(qemu, any(target_arch = "mips", target_arch = "mips64")),
+    all(
+        qemu,
+        any(
+            target_arch = "mips",
+            target_arch = "mips32r6",
+            target_arch = "mips64",
+            target_arch = "mips64r6"
+        )
+    ),
     ignore
 )]
 fn test_mq_set_nonblocking() {
diff --git a/test/test_net.rs b/test/test_net.rs
index c44655a..faba850 100644
--- a/test/test_net.rs
+++ b/test/test_net.rs
@@ -1,13 +1,9 @@
 use nix::net::if_::*;
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 const LOOPBACK: &[u8] = b"lo";
 
-#[cfg(not(any(
-    target_os = "android",
-    target_os = "linux",
-    target_os = "haiku"
-)))]
+#[cfg(not(any(linux_android, target_os = "haiku")))]
 const LOOPBACK: &[u8] = b"lo0";
 
 #[cfg(target_os = "haiku")]
diff --git a/test/test_poll.rs b/test/test_poll.rs
index 045ccd3..fcb3254 100644
--- a/test/test_poll.rs
+++ b/test/test_poll.rs
@@ -1,9 +1,9 @@
 use nix::{
     errno::Errno,
-    poll::{poll, PollFd, PollFlags},
-    unistd::{close, pipe, write},
+    poll::{poll, PollFd, PollFlags, PollTimeout},
+    unistd::{pipe, write},
 };
-use std::os::unix::io::{BorrowedFd, FromRawFd, OwnedFd};
+use std::os::unix::io::{AsFd, BorrowedFd};
 
 macro_rules! loop_while_eintr {
     ($poll_expr: expr) => {
@@ -20,32 +20,25 @@
 #[test]
 fn test_poll() {
     let (r, w) = pipe().unwrap();
-    let r = unsafe { OwnedFd::from_raw_fd(r) };
-    let mut fds = [PollFd::new(&r, PollFlags::POLLIN)];
+    let mut fds = [PollFd::new(r.as_fd(), PollFlags::POLLIN)];
 
     // Poll an idle pipe.  Should timeout
-    let nfds = loop_while_eintr!(poll(&mut fds, 100));
+    let nfds = loop_while_eintr!(poll(&mut fds, PollTimeout::from(100u8)));
     assert_eq!(nfds, 0);
     assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
 
-    write(w, b".").unwrap();
+    write(&w, b".").unwrap();
 
     // Poll a readable pipe.  Should return an event.
-    let nfds = poll(&mut fds, 100).unwrap();
+    let nfds = poll(&mut fds, PollTimeout::from(100u8)).unwrap();
     assert_eq!(nfds, 1);
     assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
-    close(w).unwrap();
 }
 
 // ppoll(2) is the same as poll except for how it handles timeouts and signals.
 // Repeating the test for poll(2) should be sufficient to check that our
 // bindings are correct.
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux"
-))]
+#[cfg(any(linux_android, freebsdlike))]
 #[test]
 fn test_ppoll() {
     use nix::poll::ppoll;
@@ -54,8 +47,7 @@
 
     let timeout = TimeSpec::milliseconds(1);
     let (r, w) = pipe().unwrap();
-    let r = unsafe { OwnedFd::from_raw_fd(r) };
-    let mut fds = [PollFd::new(&r, PollFlags::POLLIN)];
+    let mut fds = [PollFd::new(r.as_fd(), PollFlags::POLLIN)];
 
     // Poll an idle pipe.  Should timeout
     let sigset = SigSet::empty();
@@ -63,19 +55,18 @@
     assert_eq!(nfds, 0);
     assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
 
-    write(w, b".").unwrap();
+    write(&w, b".").unwrap();
 
     // Poll a readable pipe.  Should return an event.
     let nfds = ppoll(&mut fds, Some(timeout), None).unwrap();
     assert_eq!(nfds, 1);
     assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
-    close(w).unwrap();
 }
 
 #[test]
 fn test_pollfd_events() {
     let fd_zero = unsafe { BorrowedFd::borrow_raw(0) };
-    let mut pfd = PollFd::new(&fd_zero, PollFlags::POLLIN);
+    let mut pfd = PollFd::new(fd_zero.as_fd(), PollFlags::POLLIN);
     assert_eq!(pfd.events(), PollFlags::POLLIN);
     pfd.set_events(PollFlags::POLLOUT);
     assert_eq!(pfd.events(), PollFlags::POLLOUT);
diff --git a/test/test_pty.rs b/test/test_pty.rs
index 4cc6620..368ec12 100644
--- a/test/test_pty.rs
+++ b/test/test_pty.rs
@@ -1,9 +1,9 @@
 use std::fs::File;
-use std::io::{Read, Write};
+use std::io::{stdout, Read, Write};
 use std::os::unix::prelude::*;
 use std::path::Path;
 
-use libc::{_exit, STDOUT_FILENO};
+use libc::_exit;
 use nix::fcntl::{open, OFlag};
 use nix::pty::*;
 use nix::sys::stat;
@@ -12,7 +12,7 @@
 
 /// Test equivalence of `ptsname` and `ptsname_r`
 #[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn test_ptsname_equivalence() {
     let _m = crate::PTSNAME_MTX.lock();
 
@@ -29,7 +29,7 @@
 /// Test data copying of `ptsname`
 // TODO need to run in a subprocess, since ptsname is non-reentrant
 #[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn test_ptsname_copy() {
     let _m = crate::PTSNAME_MTX.lock();
 
@@ -47,7 +47,7 @@
 
 /// Test data copying of `ptsname_r`
 #[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn test_ptsname_r_copy() {
     // Open a new PTTY master
     let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
@@ -61,7 +61,7 @@
 
 /// Test that `ptsname` returns different names for different devices
 #[test]
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 fn test_ptsname_unique() {
     let _m = crate::PTSNAME_MTX.lock();
 
@@ -96,7 +96,7 @@
         open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty())
             .unwrap();
 
-    #[cfg(target_os = "illumos")]
+    #[cfg(solarish)]
     // TODO: rewrite using ioctl!
     #[allow(clippy::comparison_chain)]
     {
@@ -185,7 +185,7 @@
     // Writing to one should be readable on the other one
     let string = "foofoofoo\n";
     let mut buf = [0u8; 10];
-    write(pty.master.as_raw_fd(), string.as_bytes()).unwrap();
+    write(&pty.master, string.as_bytes()).unwrap();
     crate::read_exact(&pty.slave, &mut buf);
 
     assert_eq!(&buf, string.as_bytes());
@@ -199,7 +199,7 @@
     let string2 = "barbarbarbar\n";
     let echoed_string2 = "barbarbarbar\r\n";
     let mut buf = [0u8; 14];
-    write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap();
+    write(&pty.slave, string2.as_bytes()).unwrap();
     crate::read_exact(&pty.master, &mut buf);
 
     assert_eq!(&buf, echoed_string2.as_bytes());
@@ -224,7 +224,7 @@
     // Writing to one should be readable on the other one
     let string = "foofoofoo\n";
     let mut buf = [0u8; 10];
-    write(pty.master.as_raw_fd(), string.as_bytes()).unwrap();
+    write(&pty.master, string.as_bytes()).unwrap();
     crate::read_exact(&pty.slave, &mut buf);
 
     assert_eq!(&buf, string.as_bytes());
@@ -237,7 +237,7 @@
     let string2 = "barbarbarbar\n";
     let echoed_string2 = "barbarbarbar\n";
     let mut buf = [0u8; 13];
-    write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap();
+    write(&pty.slave, string2.as_bytes()).unwrap();
     crate::read_exact(&pty.master, &mut buf);
 
     assert_eq!(&buf, echoed_string2.as_bytes());
@@ -258,7 +258,7 @@
     let pty = unsafe { forkpty(None, None).unwrap() };
     match pty.fork_result {
         Child => {
-            write(STDOUT_FILENO, string.as_bytes()).unwrap();
+            write(stdout(), string.as_bytes()).unwrap();
             pause(); // we need the child to stay alive until the parent calls read
             unsafe {
                 _exit(0);
diff --git a/test/test_resource.rs b/test/test_resource.rs
deleted file mode 100644
index 2ab581b..0000000
--- a/test/test_resource.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-#[cfg(not(any(
-    target_os = "redox",
-    target_os = "fuchsia",
-    target_os = "illumos",
-    target_os = "haiku"
-)))]
-use nix::sys::resource::{getrlimit, setrlimit, Resource};
-
-/// Tests the RLIMIT_NOFILE functionality of getrlimit(), where the resource RLIMIT_NOFILE refers
-/// to the maximum file descriptor number that can be opened by the process (aka the maximum number
-/// of file descriptors that the process can open, since Linux 4.5).
-///
-/// We first fetch the existing file descriptor maximum values using getrlimit(), then edit the
-/// soft limit to make sure it has a new and distinct value to the hard limit. We then setrlimit()
-/// to put the new soft limit in effect, and then getrlimit() once more to ensure the limits have
-/// been updated.
-#[test]
-#[cfg(not(any(
-    target_os = "redox",
-    target_os = "fuchsia",
-    target_os = "illumos",
-    target_os = "haiku"
-)))]
-pub fn test_resource_limits_nofile() {
-    let (mut soft_limit, hard_limit) =
-        getrlimit(Resource::RLIMIT_NOFILE).unwrap();
-
-    soft_limit -= 1;
-    assert_ne!(soft_limit, hard_limit);
-    setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap();
-
-    let (new_soft_limit, _) = getrlimit(Resource::RLIMIT_NOFILE).unwrap();
-    assert_eq!(new_soft_limit, soft_limit);
-}
diff --git a/test/test_sendfile.rs b/test/test_sendfile.rs
index b85e030..6333bf8 100644
--- a/test/test_sendfile.rs
+++ b/test/test_sendfile.rs
@@ -1,21 +1,20 @@
 use std::io::prelude::*;
-#[cfg(any(target_os = "android", target_os = "linux"))]
-use std::os::unix::io::{FromRawFd, OwnedFd};
 
 use libc::off_t;
 use nix::sys::sendfile::*;
 use tempfile::tempfile;
 
 cfg_if! {
-    if #[cfg(any(target_os = "android", target_os = "linux"))] {
-        use nix::unistd::{close, pipe, read};
-    } else if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos"))] {
+    if #[cfg(linux_android)] {
+        use nix::unistd::{pipe, read};
+        use std::os::unix::io::AsRawFd;
+    } else if #[cfg(any(freebsdlike, apple_targets, solarish))] {
         use std::net::Shutdown;
         use std::os::unix::net::UnixStream;
     }
 }
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
 #[test]
 fn test_sendfile_linux() {
     const CONTENTS: &[u8] = b"abcdef123456";
@@ -24,21 +23,14 @@
 
     let (rd, wr) = pipe().unwrap();
     let mut offset: off_t = 5;
-    // The construct of this `OwnedFd` is a temporary workaround, when `pipe(2)`
-    // becomes I/O-safe:
-    // pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error>
-    // then it is no longer needed.
-    let wr = unsafe { OwnedFd::from_raw_fd(wr) };
     let res = sendfile(&wr, &tmp, Some(&mut offset), 2).unwrap();
 
     assert_eq!(2, res);
 
     let mut buf = [0u8; 1024];
-    assert_eq!(2, read(rd, &mut buf).unwrap());
+    assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap());
     assert_eq!(b"f1", &buf[0..2]);
     assert_eq!(7, offset);
-
-    close(rd).unwrap();
 }
 
 #[cfg(target_os = "linux")]
@@ -50,21 +42,14 @@
 
     let (rd, wr) = pipe().unwrap();
     let mut offset: libc::off64_t = 5;
-    // The construct of this `OwnedFd` is a temporary workaround, when `pipe(2)`
-    // becomes I/O-safe:
-    // pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error>
-    // then it is no longer needed.
-    let wr = unsafe { OwnedFd::from_raw_fd(wr) };
     let res = sendfile64(&wr, &tmp, Some(&mut offset), 2).unwrap();
 
     assert_eq!(2, res);
 
     let mut buf = [0u8; 1024];
-    assert_eq!(2, read(rd, &mut buf).unwrap());
+    assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap());
     assert_eq!(b"f1", &buf[0..2]);
     assert_eq!(7, offset);
-
-    close(rd).unwrap();
 }
 
 #[cfg(target_os = "freebsd")]
@@ -167,7 +152,7 @@
     assert_eq!(expected_string, read_string);
 }
 
-#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[cfg(apple_targets)]
 #[test]
 fn test_sendfile_darwin() {
     // Declare the content
@@ -215,3 +200,62 @@
     assert_eq!(bytes_written as usize, bytes_read);
     assert_eq!(expected_string, read_string);
 }
+
+#[cfg(solarish)]
+#[test]
+fn test_sendfilev() {
+    use std::os::fd::AsFd;
+    // Declare the content
+    let header_strings =
+        ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
+    let body = "Xabcdef123456";
+    let body_offset = 1usize;
+    let trailer_strings = ["\n", "Served by Make Believe\n"];
+
+    // Write data to files
+    let mut header_data = tempfile().unwrap();
+    header_data
+        .write_all(header_strings.concat().as_bytes())
+        .unwrap();
+    let mut body_data = tempfile().unwrap();
+    body_data.write_all(body.as_bytes()).unwrap();
+    let mut trailer_data = tempfile().unwrap();
+    trailer_data
+        .write_all(trailer_strings.concat().as_bytes())
+        .unwrap();
+    let (mut rd, wr) = UnixStream::pair().unwrap();
+    let vec: &[SendfileVec] = &[
+        SendfileVec::new(
+            header_data.as_fd(),
+            0,
+            header_strings.iter().map(|s| s.len()).sum(),
+        ),
+        SendfileVec::new(
+            body_data.as_fd(),
+            body_offset as off_t,
+            body.len() - body_offset,
+        ),
+        SendfileVec::new(
+            trailer_data.as_fd(),
+            0,
+            trailer_strings.iter().map(|s| s.len()).sum(),
+        ),
+    ];
+
+    let (res, bytes_written) = sendfilev(&wr, vec);
+    assert!(res.is_ok());
+    wr.shutdown(Shutdown::Both).unwrap();
+
+    // Prepare the expected result
+    let expected_string = header_strings.concat()
+        + &body[body_offset..]
+        + &trailer_strings.concat();
+
+    // Verify the message that was sent
+    assert_eq!(bytes_written, expected_string.as_bytes().len());
+
+    let mut read_string = String::new();
+    let bytes_read = rd.read_to_string(&mut read_string).unwrap();
+    assert_eq!(bytes_written, bytes_read);
+    assert_eq!(expected_string, read_string);
+}
diff --git a/test/test_stat.rs b/test/test_stat.rs
index 55f15c0..386f108 100644
--- a/test/test_stat.rs
+++ b/test/test_stat.rs
@@ -21,8 +21,7 @@
 use nix::fcntl;
 #[cfg(any(
     target_os = "linux",
-    target_os = "ios",
-    target_os = "macos",
+    apple_targets,
     target_os = "freebsd",
     target_os = "netbsd"
 ))]
@@ -117,7 +116,7 @@
         fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty());
 
     let result =
-        stat::fstatat(dirfd.unwrap(), &filename, fcntl::AtFlags::empty());
+        stat::fstatat(Some(dirfd.unwrap()), &filename, fcntl::AtFlags::empty());
     assert_stat_results(result);
 }
 
@@ -235,8 +234,7 @@
 #[test]
 #[cfg(any(
     target_os = "linux",
-    target_os = "ios",
-    target_os = "macos",
+    apple_targets,
     target_os = "freebsd",
     target_os = "netbsd"
 ))]
@@ -323,7 +321,7 @@
     let dirfd =
         fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
             .unwrap();
-    mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed");
+    mkdirat(Some(dirfd), filename, Mode::S_IRWXU).expect("mkdirat failed");
     assert!(Path::exists(&tempdir.path().join(filename)));
 }
 
@@ -337,7 +335,7 @@
     let dirfd =
         fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
             .unwrap();
-    mkdirat(dirfd, filename, Mode::S_IRWXU).expect("mkdirat failed");
+    mkdirat(Some(dirfd), filename, Mode::S_IRWXU).expect("mkdirat failed");
     let permissions = fs::metadata(tempdir.path().join(filename))
         .unwrap()
         .permissions();
@@ -357,16 +355,14 @@
         stat::Mode::empty(),
     )
     .unwrap();
-    let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err();
+    let result = mkdirat(Some(dirfd), filename, Mode::S_IRWXU).unwrap_err();
     assert_eq!(result, Errno::ENOTDIR);
 }
 
 #[test]
 #[cfg(not(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
+    freebsdlike,
+    apple_targets,
     target_os = "haiku",
     target_os = "redox"
 )))]
@@ -384,11 +380,9 @@
 
 #[test]
 #[cfg(not(any(
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "illumos",
-    target_os = "ios",
-    target_os = "macos",
+    solarish,
+    freebsdlike,
+    apple_targets,
     target_os = "haiku",
     target_os = "redox"
 )))]
@@ -402,7 +396,7 @@
     let target_dir =
         Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap();
     mknodat(
-        target_dir.as_raw_fd(),
+        Some(target_dir.as_raw_fd()),
         file_name,
         SFlag::S_IFREG,
         Mode::S_IRWXU,
@@ -410,7 +404,7 @@
     )
     .unwrap();
     let mode = fstatat(
-        target_dir.as_raw_fd(),
+        Some(target_dir.as_raw_fd()),
         file_name,
         AtFlags::AT_SYMLINK_NOFOLLOW,
     )
@@ -419,3 +413,75 @@
     assert_eq!(mode & libc::S_IFREG, libc::S_IFREG);
     assert_eq!(mode & libc::S_IRWXU, libc::S_IRWXU);
 }
+
+#[test]
+#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
+fn test_futimens_unchanged() {
+    let tempdir = tempfile::tempdir().unwrap();
+    let fullpath = tempdir.path().join("file");
+    drop(File::create(&fullpath).unwrap());
+    let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty())
+        .unwrap();
+
+    let old_atime = fs::metadata(fullpath.as_path())
+        .unwrap()
+        .accessed()
+        .unwrap();
+    let old_mtime = fs::metadata(fullpath.as_path())
+        .unwrap()
+        .modified()
+        .unwrap();
+
+    futimens(fd, &TimeSpec::UTIME_OMIT, &TimeSpec::UTIME_OMIT).unwrap();
+
+    let new_atime = fs::metadata(fullpath.as_path())
+        .unwrap()
+        .accessed()
+        .unwrap();
+    let new_mtime = fs::metadata(fullpath.as_path())
+        .unwrap()
+        .modified()
+        .unwrap();
+    assert_eq!(old_atime, new_atime);
+    assert_eq!(old_mtime, new_mtime);
+}
+
+#[test]
+#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
+fn test_utimensat_unchanged() {
+    let _dr = crate::DirRestore::new();
+    let tempdir = tempfile::tempdir().unwrap();
+    let filename = "foo.txt";
+    let fullpath = tempdir.path().join(filename);
+    drop(File::create(&fullpath).unwrap());
+    let dirfd =
+        fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
+            .unwrap();
+
+    let old_atime = fs::metadata(fullpath.as_path())
+        .unwrap()
+        .accessed()
+        .unwrap();
+    let old_mtime = fs::metadata(fullpath.as_path())
+        .unwrap()
+        .modified()
+        .unwrap();
+    utimensat(
+        Some(dirfd),
+        filename,
+        &TimeSpec::UTIME_OMIT,
+        &TimeSpec::UTIME_OMIT,
+        UtimensatFlags::NoFollowSymlink,
+    )
+    .unwrap();
+    let new_atime = fs::metadata(fullpath.as_path())
+        .unwrap()
+        .accessed()
+        .unwrap();
+    let new_mtime = fs::metadata(fullpath.as_path())
+        .unwrap()
+        .modified()
+        .unwrap();
+    assert_eq!(old_atime, new_atime);
+    assert_eq!(old_mtime, new_mtime);
+}
diff --git a/test/test_time.rs b/test/test_time.rs
index 5f76e61..64c8161 100644
--- a/test/test_time.rs
+++ b/test/test_time.rs
@@ -1,10 +1,4 @@
-#[cfg(any(
-    target_os = "freebsd",
-    target_os = "dragonfly",
-    target_os = "linux",
-    target_os = "android",
-    target_os = "emscripten",
-))]
+#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
 use nix::time::clock_getcpuclockid;
 use nix::time::{clock_gettime, ClockId};
 
@@ -19,13 +13,7 @@
     clock_gettime(ClockId::CLOCK_REALTIME).expect("assertion failed");
 }
 
-#[cfg(any(
-    target_os = "freebsd",
-    target_os = "dragonfly",
-    target_os = "linux",
-    target_os = "android",
-    target_os = "emscripten",
-))]
+#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
 #[test]
 pub fn test_clock_getcpuclockid() {
     let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap();
@@ -43,13 +31,7 @@
     ClockId::CLOCK_REALTIME.now().unwrap();
 }
 
-#[cfg(any(
-    target_os = "freebsd",
-    target_os = "dragonfly",
-    target_os = "linux",
-    target_os = "android",
-    target_os = "emscripten",
-))]
+#[cfg(any(freebsdlike, linux_android, target_os = "emscripten"))]
 #[test]
 pub fn test_clock_id_pid_cpu_clock_id() {
     ClockId::pid_cpu_clock_id(nix::unistd::Pid::this())
@@ -57,3 +39,28 @@
         .unwrap()
         .unwrap();
 }
+
+#[cfg(any(
+    linux_android,
+    solarish,
+    freebsdlike,
+    target_os = "netbsd",
+    target_os = "hurd",
+    target_os = "aix"
+))]
+#[test]
+pub fn test_clock_nanosleep() {
+    use nix::{
+        sys::time::{TimeSpec, TimeValLike},
+        time::{clock_nanosleep, ClockNanosleepFlags},
+    };
+
+    let sleep_time = TimeSpec::microseconds(1);
+    let res = clock_nanosleep(
+        ClockId::CLOCK_MONOTONIC,
+        ClockNanosleepFlags::empty(),
+        &sleep_time,
+    );
+    let expected = TimeSpec::microseconds(0);
+    assert_eq!(res, Ok(expected));
+}
diff --git a/test/test_unistd.rs b/test/test_unistd.rs
index 10284e4..aa2e5e5 100644
--- a/test/test_unistd.rs
+++ b/test/test_unistd.rs
@@ -67,6 +67,37 @@
 }
 
 #[test]
+#[cfg(target_os = "freebsd")]
+fn test_rfork_and_waitpid() {
+    let _m = crate::FORK_MTX.lock();
+
+    // Safe: Child only calls `_exit`, which is signal-safe
+    match unsafe { rfork(RforkFlags::RFPROC | RforkFlags::RFTHREAD) }
+        .expect("Error: Rfork Failed")
+    {
+        Child => unsafe { _exit(0) },
+        Parent { child } => {
+            // assert that child was created and pid > 0
+            let child_raw: ::libc::pid_t = child.into();
+            assert!(child_raw > 0);
+            let wait_status = waitpid(child, None);
+            match wait_status {
+                // assert that waitpid returned correct status and the pid is the one of the child
+                Ok(WaitStatus::Exited(pid_t, _)) => assert_eq!(pid_t, child),
+
+                // panic, must never happen
+                s @ Ok(_) => {
+                    panic!("Child exited {s:?}, should never happen")
+                }
+
+                // panic, waitpid should never fail
+                Err(s) => panic!("Error: waitpid returned Err({s:?}"),
+            }
+        }
+    }
+}
+
+#[test]
 fn test_wait() {
     // Grab FORK_MTX so wait doesn't reap a different test's child process
     let _m = crate::FORK_MTX.lock();
@@ -126,8 +157,7 @@
 
 #[test]
 #[cfg(not(any(
-    target_os = "macos",
-    target_os = "ios",
+    apple_targets,
     target_os = "android",
     target_os = "redox",
     target_os = "haiku"
@@ -147,8 +177,7 @@
 
 #[test]
 #[cfg(not(any(
-    target_os = "macos",
-    target_os = "ios",
+    apple_targets,
     target_os = "android",
     target_os = "redox",
     target_os = "haiku"
@@ -163,15 +192,15 @@
     mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap();
 
     let stats =
-        stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap();
+        stat::fstatat(Some(dirfd), mkfifoat_name, fcntl::AtFlags::empty())
+            .unwrap();
     let typ = stat::SFlag::from_bits_truncate(stats.st_mode);
     assert_eq!(typ, SFlag::S_IFIFO);
 }
 
 #[test]
 #[cfg(not(any(
-    target_os = "macos",
-    target_os = "ios",
+    apple_targets,
     target_os = "android",
     target_os = "redox",
     target_os = "haiku"
@@ -186,8 +215,7 @@
 
 #[test]
 #[cfg(not(any(
-    target_os = "macos",
-    target_os = "ios",
+    apple_targets,
     target_os = "android",
     target_os = "redox",
     target_os = "haiku"
@@ -197,7 +225,7 @@
     let tempdir = tempdir().unwrap();
     let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
     let mkfifoat_dir = "mkfifoat_dir";
-    stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap();
+    stat::mkdirat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR).unwrap();
 
     mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR)
         .expect_err("assertion failed");
@@ -220,7 +248,7 @@
     assert_eq!(none_sid, pid_sid);
 }
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 mod linux_android {
     use nix::unistd::gettid;
 
@@ -234,8 +262,7 @@
 #[test]
 // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
 #[cfg(not(any(
-    target_os = "ios",
-    target_os = "macos",
+    apple_targets,
     target_os = "redox",
     target_os = "fuchsia",
     target_os = "haiku"
@@ -263,12 +290,11 @@
 #[test]
 // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
 #[cfg(not(any(
-    target_os = "ios",
-    target_os = "macos",
+    apple_targets,
     target_os = "redox",
     target_os = "fuchsia",
     target_os = "haiku",
-    target_os = "illumos"
+    solarish
 )))]
 fn test_initgroups() {
     // Skip this test when not run as root as `initgroups()` and `setgroups()`
@@ -356,7 +382,7 @@
         match unsafe{fork()}.unwrap() {
             Child => {
                 // Make `writer` be the stdout of the new process.
-                dup2(writer, 1).unwrap();
+                dup2(writer.as_raw_fd(), 1).unwrap();
                 let r = syscall();
                 let _ = std::io::stderr()
                     .write_all(format!("{:?}", r).as_bytes());
@@ -370,7 +396,7 @@
                 assert_eq!(ws, Ok(WaitStatus::Exited(child, 0)));
                 // Read 1024 bytes.
                 let mut buf = [0u8; 1024];
-                read(reader, &mut buf).unwrap();
+                read(reader.as_raw_fd(), &mut buf).unwrap();
                 // It should contain the things we printed using `/bin/sh`.
                 let string = String::from_utf8_lossy(&buf);
                 assert!(string.contains("nix!!!"));
@@ -404,46 +430,44 @@
     if #[cfg(target_os = "android")] {
         execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap().as_c_str());
         execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd());
-    } else if #[cfg(any(target_os = "dragonfly",
-                        target_os = "freebsd",
-                        target_os = "linux"))] {
+    } else if #[cfg(any(freebsdlike, target_os = "linux", target_os = "hurd"))] {
         // These tests frequently fail on musl, probably due to
         // https://github.com/nix-rust/nix/issues/555
         execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str());
         execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd());
-    } else if #[cfg(any(target_os = "illumos",
-                        target_os = "ios",
-                        target_os = "macos",
-                        target_os = "netbsd",
-                        target_os = "openbsd",
-                        target_os = "solaris"))] {
+    } else if #[cfg(any(solarish, apple_targets, netbsdlike))] {
         execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str());
         // No fexecve() on ios, macos, NetBSD, OpenBSD.
     }
 }
 
-#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))]
+#[cfg(any(
+    target_os = "haiku",
+    target_os = "hurd",
+    target_os = "linux",
+    target_os = "openbsd"
+))]
 execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap());
 
 cfg_if! {
     if #[cfg(target_os = "android")] {
         use nix::fcntl::AtFlags;
         execve_test_factory!(test_execveat_empty, execveat,
-                             File::open("/system/bin/sh").unwrap().into_raw_fd(),
+                             Some(File::open("/system/bin/sh").unwrap().into_raw_fd()),
                              "", AtFlags::AT_EMPTY_PATH);
         execve_test_factory!(test_execveat_relative, execveat,
-                             File::open("/system/bin/").unwrap().into_raw_fd(),
+                             Some(File::open("/system/bin/").unwrap().into_raw_fd()),
                              "./sh", AtFlags::empty());
         execve_test_factory!(test_execveat_absolute, execveat,
-                             File::open("/").unwrap().into_raw_fd(),
+                             Some(File::open("/").unwrap().into_raw_fd()),
                              "/system/bin/sh", AtFlags::empty());
     } else if #[cfg(all(target_os = "linux", any(target_arch ="x86_64", target_arch ="x86")))] {
         use nix::fcntl::AtFlags;
-        execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(),
+        execve_test_factory!(test_execveat_empty, execveat, Some(File::open("/bin/sh").unwrap().into_raw_fd()),
                              "", AtFlags::AT_EMPTY_PATH);
-        execve_test_factory!(test_execveat_relative, execveat, File::open("/bin/").unwrap().into_raw_fd(),
+        execve_test_factory!(test_execveat_relative, execveat, Some(File::open("/bin/").unwrap().into_raw_fd()),
                              "./sh", AtFlags::empty());
-        execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(),
+        execve_test_factory!(test_execveat_absolute, execveat, Some(File::open("/").unwrap().into_raw_fd()),
                              "/bin/sh", AtFlags::empty());
     }
 }
@@ -527,6 +551,8 @@
 #[test]
 #[cfg(not(target_os = "redox"))]
 fn test_fchownat() {
+    use nix::fcntl::AtFlags;
+
     let _dr = crate::DirRestore::new();
     // Testing for anything other than our own UID/GID is hard.
     let uid = Some(getuid());
@@ -540,14 +566,13 @@
 
     let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
 
-    fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink)
-        .unwrap();
+    fchownat(Some(dirfd), "file", uid, gid, AtFlags::empty()).unwrap();
 
     chdir(tempdir.path()).unwrap();
-    fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap();
+    fchownat(None, "file", uid, gid, AtFlags::empty()).unwrap();
 
     fs::remove_file(&path).unwrap();
-    fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err();
+    fchownat(None, "file", uid, gid, AtFlags::empty()).unwrap_err();
 }
 
 #[test]
@@ -564,7 +589,7 @@
     assert_eq!(b"f123456", &buf);
 }
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[test]
 fn test_lseek64() {
     const CONTENTS: &[u8] = b"abcdef123456";
@@ -579,7 +604,7 @@
 }
 
 cfg_if! {
-    if #[cfg(any(target_os = "android", target_os = "linux"))] {
+    if #[cfg(linux_android)] {
         macro_rules! require_acct{
             () => {
                 require_capability!("test_acct", CAP_SYS_PACCT);
@@ -631,11 +656,12 @@
     acct::disable().unwrap();
 }
 
+#[cfg_attr(target_os = "hurd", ignore)]
 #[test]
 fn test_fpathconf_limited() {
     let f = tempfile().unwrap();
-    // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test
-    let path_max = fpathconf(f.as_raw_fd(), PathconfVar::PATH_MAX);
+    // PATH_MAX is limited on most platforms, so it makes a good test
+    let path_max = fpathconf(f, PathconfVar::PATH_MAX);
     assert!(
         path_max
             .expect("fpathconf failed")
@@ -644,9 +670,10 @@
     );
 }
 
+#[cfg_attr(target_os = "hurd", ignore)]
 #[test]
 fn test_pathconf_limited() {
-    // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test
+    // PATH_MAX is limited on most platforms, so it makes a good test
     let path_max = pathconf("/", PathconfVar::PATH_MAX);
     assert!(
         path_max
@@ -656,9 +683,10 @@
     );
 }
 
+#[cfg_attr(target_os = "hurd", ignore)]
 #[test]
 fn test_sysconf_limited() {
-    // AFAIK, OPEN_MAX is limited on all platforms, so it makes a good test
+    // OPEN_MAX is limited on most platforms, so it makes a good test
     let open_max = sysconf(SysconfVar::OPEN_MAX);
     assert!(
         open_max
@@ -678,13 +706,7 @@
     assert!(open_max.expect("sysconf failed").is_none())
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "openbsd"
-))]
+#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))]
 #[test]
 fn test_getresuid() {
     let resuids = getresuid().unwrap();
@@ -693,13 +715,7 @@
     assert_ne!(resuids.saved.as_raw(), libc::uid_t::MAX);
 }
 
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "openbsd"
-))]
+#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))]
 #[test]
 fn test_getresgid() {
     let resgids = getresgid().unwrap();
@@ -714,12 +730,12 @@
 fn test_pipe() {
     let (fd0, fd1) = pipe().unwrap();
     let m0 = stat::SFlag::from_bits_truncate(
-        stat::fstat(fd0).unwrap().st_mode as mode_t,
+        stat::fstat(fd0.as_raw_fd()).unwrap().st_mode as mode_t,
     );
     // S_IFIFO means it's a pipe
     assert_eq!(m0, SFlag::S_IFIFO);
     let m1 = stat::SFlag::from_bits_truncate(
-        stat::fstat(fd1).unwrap().st_mode as mode_t,
+        stat::fstat(fd1.as_raw_fd()).unwrap().st_mode as mode_t,
     );
     assert_eq!(m1, SFlag::S_IFIFO);
 }
@@ -727,25 +743,25 @@
 // pipe2(2) is the same as pipe(2), except it allows setting some flags.  Check
 // that we can set a flag.
 #[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
+    linux_android,
+    freebsdlike,
+    solarish,
+    netbsdlike,
     target_os = "emscripten",
-    target_os = "freebsd",
-    target_os = "illumos",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd",
     target_os = "redox",
-    target_os = "solaris"
 ))]
 #[test]
 fn test_pipe2() {
     use nix::fcntl::{fcntl, FcntlArg, FdFlag};
 
     let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap();
-    let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap());
+    let f0 = FdFlag::from_bits_truncate(
+        fcntl(fd0.as_raw_fd(), FcntlArg::F_GETFD).unwrap(),
+    );
     assert!(f0.contains(FdFlag::FD_CLOEXEC));
-    let f1 = FdFlag::from_bits_truncate(fcntl(fd1, FcntlArg::F_GETFD).unwrap());
+    let f1 = FdFlag::from_bits_truncate(
+        fcntl(fd1.as_raw_fd(), FcntlArg::F_GETFD).unwrap(),
+    );
     assert!(f1.contains(FdFlag::FD_CLOEXEC));
 }
 
@@ -881,6 +897,8 @@
 #[test]
 #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
 fn test_linkat_file() {
+    use nix::fcntl::AtFlags;
+
     let tempdir = tempdir().unwrap();
     let oldfilename = "foo.txt";
     let oldfilepath = tempdir.path().join(oldfilename);
@@ -902,7 +920,7 @@
         oldfilename,
         Some(dirfd),
         newfilename,
-        LinkatFlags::SymlinkFollow,
+        AtFlags::AT_SYMLINK_FOLLOW,
     )
     .unwrap();
     assert!(newfilepath.exists());
@@ -911,6 +929,8 @@
 #[test]
 #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
 fn test_linkat_olddirfd_none() {
+    use nix::fcntl::AtFlags;
+
     let _dr = crate::DirRestore::new();
 
     let tempdir_oldfile = tempdir().unwrap();
@@ -939,7 +959,7 @@
         oldfilename,
         Some(dirfd),
         newfilename,
-        LinkatFlags::SymlinkFollow,
+        AtFlags::AT_SYMLINK_FOLLOW,
     )
     .unwrap();
     assert!(newfilepath.exists());
@@ -948,6 +968,8 @@
 #[test]
 #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
 fn test_linkat_newdirfd_none() {
+    use nix::fcntl::AtFlags;
+
     let _dr = crate::DirRestore::new();
 
     let tempdir_oldfile = tempdir().unwrap();
@@ -976,20 +998,17 @@
         oldfilename,
         None,
         newfilename,
-        LinkatFlags::SymlinkFollow,
+        AtFlags::AT_SYMLINK_FOLLOW,
     )
     .unwrap();
     assert!(newfilepath.exists());
 }
 
 #[test]
-#[cfg(not(any(
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "redox",
-    target_os = "haiku"
-)))]
+#[cfg(not(any(apple_targets, target_os = "redox", target_os = "haiku")))]
 fn test_linkat_no_follow_symlink() {
+    use nix::fcntl::AtFlags;
+
     let _m = crate::CWD_LOCK.read();
 
     let tempdir = tempdir().unwrap();
@@ -1019,7 +1038,7 @@
         symoldfilename,
         Some(dirfd),
         newfilename,
-        LinkatFlags::NoSymlinkFollow,
+        AtFlags::empty(),
     )
     .unwrap();
 
@@ -1033,6 +1052,8 @@
 #[test]
 #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
 fn test_linkat_follow_symlink() {
+    use nix::fcntl::AtFlags;
+
     let _m = crate::CWD_LOCK.read();
 
     let tempdir = tempdir().unwrap();
@@ -1062,7 +1083,7 @@
         symoldfilename,
         Some(dirfd),
         newfilename,
-        LinkatFlags::SymlinkFollow,
+        AtFlags::AT_SYMLINK_FOLLOW,
     )
     .unwrap();
 
@@ -1070,8 +1091,8 @@
 
     // Check the file type of the new link
     assert_eq!(
-        (stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t)
-            & SFlag::S_IFMT),
+        stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t)
+            & SFlag::S_IFMT,
         SFlag::S_IFREG
     );
 
@@ -1159,8 +1180,6 @@
         .expect("assertion failed");
 }
 
-//Clippy false positive https://github.com/rust-lang/rust-clippy/issues/9111
-#[allow(clippy::needless_borrow)]
 #[cfg(not(target_os = "redox"))]
 #[test]
 fn test_user_into_passwd() {
@@ -1177,7 +1196,7 @@
 }
 
 /// Tests setting the filesystem UID with `setfsuid`.
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
 #[test]
 fn test_setfsuid() {
     use std::os::unix::fs::PermissionsExt;
@@ -1230,9 +1249,11 @@
     grantpt(&fd).expect("grantpt failed");
     unlockpt(&fd).expect("unlockpt failed");
     let sname = unsafe { ptsname(&fd) }.expect("ptsname failed");
-    let fds = open(Path::new(&sname), OFlag::O_RDWR, stat::Mode::empty())
+    let fds = fs::OpenOptions::new()
+        .read(true)
+        .write(true)
+        .open(Path::new(&sname))
         .expect("open failed");
-    assert!(fds > 0);
 
     let name = ttyname(fds).expect("ttyname failed");
     assert!(name.starts_with("/dev"));
@@ -1242,35 +1263,17 @@
 #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 fn test_ttyname_not_pty() {
     let fd = File::open("/dev/zero").unwrap();
-    assert!(fd.as_raw_fd() > 0);
-    assert_eq!(ttyname(fd.as_raw_fd()), Err(Errno::ENOTTY));
+    assert_eq!(ttyname(fd), Err(Errno::ENOTTY));
 }
 
 #[test]
-#[cfg(not(any(
-    target_os = "redox",
-    target_os = "fuchsia",
-    target_os = "haiku"
-)))]
-fn test_ttyname_invalid_fd() {
-    assert_eq!(ttyname(-1), Err(Errno::EBADF));
-}
-
-#[test]
-#[cfg(any(
-    target_os = "macos",
-    target_os = "ios",
-    target_os = "freebsd",
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "dragonfly",
-))]
+#[cfg(bsd)]
 fn test_getpeereid() {
     use std::os::unix::net::UnixStream;
     let (sock_a, sock_b) = UnixStream::pair().unwrap();
 
-    let (uid_a, gid_a) = getpeereid(sock_a.as_raw_fd()).unwrap();
-    let (uid_b, gid_b) = getpeereid(sock_b.as_raw_fd()).unwrap();
+    let (uid_a, gid_a) = getpeereid(sock_a).unwrap();
+    let (uid_b, gid_b) = getpeereid(sock_b).unwrap();
 
     let uid = geteuid();
     let gid = getegid();
@@ -1282,20 +1285,6 @@
 }
 
 #[test]
-#[cfg(any(
-    target_os = "macos",
-    target_os = "ios",
-    target_os = "freebsd",
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "dragonfly",
-))]
-fn test_getpeereid_invalid_fd() {
-    // getpeereid is not POSIX, so error codes are inconsistent between different Unices.
-    getpeereid(-1).expect_err("assertion failed");
-}
-
-#[test]
 #[cfg(not(target_os = "redox"))]
 fn test_faccessat_none_not_existing() {
     use nix::fcntl::AtFlags;
@@ -1364,11 +1353,7 @@
 }
 
 #[test]
-#[cfg(any(
-    all(target_os = "linux", not(target_env = "uclibc")),
-    target_os = "freebsd",
-    target_os = "dragonfly"
-))]
+#[cfg(any(all(target_os = "linux", not(target_env = "uclibc")), freebsdlike))]
 fn test_eaccess_not_existing() {
     let tempdir = tempdir().unwrap();
     let dir = tempdir.path().join("does_not_exist.txt");
@@ -1379,11 +1364,7 @@
 }
 
 #[test]
-#[cfg(any(
-    all(target_os = "linux", not(target_env = "uclibc")),
-    target_os = "freebsd",
-    target_os = "dragonfly"
-))]
+#[cfg(any(all(target_os = "linux", not(target_env = "uclibc")), freebsdlike))]
 fn test_eaccess_file_exists() {
     let tempdir = tempdir().unwrap();
     let path = tempdir.path().join("does_exist.txt");
@@ -1391,3 +1372,14 @@
     eaccess(&path, AccessFlags::R_OK | AccessFlags::W_OK)
         .expect("assertion failed");
 }
+
+#[test]
+#[cfg(bsd)]
+fn test_group_from() {
+    let group = Group::from_name("wheel").unwrap().unwrap();
+    assert!(group.name == "wheel");
+    let group_id = group.gid;
+    let group = Group::from_gid(group_id).unwrap().unwrap();
+    assert_eq!(group.gid, group_id);
+    assert_eq!(group.name, "wheel");
+}