aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-04-30 21:49:16 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-04-30 21:49:16 +0000
commit9d9cae777b071256ff8a1a6eb0fe48306e33ed26 (patch)
tree799406047564fccc4e80ee22513f1485f441cd8e
parent2712e434670084387f31dd659041f8e300a41ff3 (diff)
parent33265a2e3abe8f6edbbdf72728f6e6fb12dd6358 (diff)
downloadnix-build-tools-release.tar.gz
Snap for 11784721 from 33265a2e3abe8f6edbbdf72728f6e6fb12dd6358 to build-tools-releasebuild-tools-release
Change-Id: Ib9ccf7c1212b4b54e503c6e48b95a159a19ca1c2
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp21
-rw-r--r--CHANGELOG.md205
-rw-r--r--Cargo.toml16
-rw-r--r--Cargo.toml.orig17
-rw-r--r--METADATA23
-rw-r--r--README.md4
-rw-r--r--build.rs25
-rw-r--r--cargo_embargo.json7
-rw-r--r--module_block.bp.fragment15
-rw-r--r--src/dir.rs27
-rw-r--r--src/env.rs7
-rw-r--r--src/errno.rs1114
-rw-r--r--src/fcntl.rs561
-rw-r--r--src/features.rs12
-rw-r--r--src/ifaddrs.rs38
-rw-r--r--src/kmod.rs4
-rw-r--r--src/lib.rs34
-rw-r--r--src/macros.rs8
-rw-r--r--src/mount/bsd.rs51
-rw-r--r--src/mount/linux.rs2
-rw-r--r--src/mount/mod.rs22
-rw-r--r--src/mqueue.rs15
-rw-r--r--src/net/if_.rs329
-rw-r--r--src/poll.rs61
-rw-r--r--src/poll_timeout.rs224
-rw-r--r--src/pty.rs15
-rw-r--r--src/sched.rs43
-rw-r--r--src/sys/aio.rs80
-rw-r--r--src/sys/epoll.rs25
-rw-r--r--src/sys/event.rs171
-rw-r--r--src/sys/eventfd.rs77
-rw-r--r--src/sys/fanotify.rs416
-rw-r--r--src/sys/inotify.rs16
-rw-r--r--src/sys/ioctl/bsd.rs4
-rw-r--r--src/sys/ioctl/linux.rs2
-rw-r--r--src/sys/ioctl/mod.rs112
-rw-r--r--src/sys/memfd.rs43
-rw-r--r--src/sys/mman.rs320
-rw-r--r--src/sys/mod.rs82
-rw-r--r--src/sys/personality.rs2
-rw-r--r--src/sys/prctl.rs23
-rw-r--r--src/sys/ptrace/bsd.rs42
-rw-r--r--src/sys/ptrace/linux.rs58
-rw-r--r--src/sys/ptrace/mod.rs20
-rw-r--r--src/sys/quota.rs6
-rw-r--r--src/sys/reboot.rs175
-rw-r--r--src/sys/resource.rs109
-rw-r--r--src/sys/select.rs267
-rw-r--r--src/sys/sendfile.rs116
-rw-r--r--src/sys/signal.rs461
-rw-r--r--src/sys/signalfd.rs66
-rw-r--r--src/sys/socket/addr.rs873
-rw-r--r--src/sys/socket/mod.rs943
-rw-r--r--src/sys/socket/sockopt.rs454
-rw-r--r--src/sys/stat.rs73
-rw-r--r--src/sys/statfs.rs363
-rw-r--r--src/sys/statvfs.rs48
-rw-r--r--src/sys/termios.rs584
-rw-r--r--src/sys/time.rs121
-rw-r--r--src/sys/timerfd.rs2
-rw-r--r--src/sys/uio.rs49
-rw-r--r--src/sys/utsname.rs23
-rw-r--r--src/sys/wait.rs58
-rw-r--r--src/time.rs236
-rw-r--r--src/unistd.rs1313
-rw-r--r--test/common/mod.rs10
-rw-r--r--test/sys/mod.rs54
-rw-r--r--test/sys/test_aio.rs66
-rw-r--r--test/sys/test_aio_drop.rs3
-rw-r--r--test/sys/test_event.rs41
-rw-r--r--test/sys/test_fanotify.rs149
-rw-r--r--test/sys/test_ioctl.rs33
-rw-r--r--test/sys/test_mman.rs55
-rw-r--r--test/sys/test_ptrace.rs12
-rw-r--r--test/sys/test_resource.rs (renamed from test/test_resource.rs)33
-rw-r--r--test/sys/test_select.rs247
-rw-r--r--test/sys/test_signal.rs320
-rw-r--r--test/sys/test_signalfd.rs63
-rw-r--r--test/sys/test_socket.rs474
-rw-r--r--test/sys/test_sockopt.rs454
-rw-r--r--test/sys/test_statfs.rs99
-rw-r--r--test/sys/test_statvfs.rs13
-rw-r--r--test/sys/test_termios.rs13
-rw-r--r--test/sys/test_time.rs91
-rw-r--r--test/sys/test_timer.rs (renamed from test/test_timer.rs)0
-rw-r--r--test/sys/test_uio.rs36
-rw-r--r--test/sys/test_utsname.rs17
-rw-r--r--test/sys/test_wait.rs16
-rw-r--r--test/test.rs32
-rw-r--r--test/test_dir.rs4
-rw-r--r--test/test_errno.rs16
-rw-r--r--test/test_fcntl.rs182
-rw-r--r--test/test_mount.rs390
-rw-r--r--test/test_mq.rs20
-rw-r--r--test/test_net.rs8
-rw-r--r--test/test_poll.rs31
-rw-r--r--test/test_pty.rs24
-rw-r--r--test/test_sendfile.rs90
-rw-r--r--test/test_stat.rs104
-rw-r--r--test/test_time.rs49
-rw-r--r--test/test_unistd.rs260
102 files changed, 7726 insertions, 6518 deletions
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 @@ rust_library {
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 @@ rust_library {
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 @@ This project adheres to [Semantic Versioning](https://semver.org/).
## [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 @@ This project adheres to [Semantic Versioning](https://semver.org/).
([#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 @@ name = "test-clearenv"
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 = "2.3.1"
version = "1.0"
[dependencies.libc]
-version = "0.2.147"
+version = "0.2.153"
features = ["extra_traits"]
[dependencies.memoffset]
@@ -102,6 +98,9 @@ version = "1.0.7"
[dev-dependencies.tempfile]
version = "3.7.1"
+[build-dependencies.cfg_aliases]
+version = "0.1.1"
+
[features]
acct = []
aio = ["pin-utils"]
@@ -109,6 +108,7 @@ default = []
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 @@ targets = [
]
[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 @@ aio = ["pin-utils"]
dir = ["fs"]
env = []
event = []
+fanotify = []
feature = []
fs = []
hostname = []
@@ -83,6 +84,9 @@ caps = "0.5.3"
[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 @@ name = "test-clearenv"
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 @@ The following targets are supported by `nix`:
<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 @@ impl Dir {
/// 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 @@ impl Entry {
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 @@ impl Entry {
/// notably, some Linux filesystems don't implement this. The caller should use `stat` or
/// `fstat` if this returns `None`.
pub fn file_type(&self) -> Option<Type> {
- #[cfg(not(any(
- target_os = "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 @@ impl Entry {
}
// illumos, Solaris, and Haiku systems do not have the d_type member at all:
- #[cfg(any(
- target_os = "aix",
- target_os = "illumos",
- target_os = "solaris",
- target_os = "haiku"
- ))]
+ #[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 @@ impl std::error::Error for ClearEnvError {}
/// 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())
}
- pub fn desc(self) -> &'static str {
- desc(self)
+ /// 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)
+ }
+
+ /// 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 @@ impl TryFrom<io::Error> for Errno {
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 @@ fn desc(errno: Errno) -> &'static str {
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 @@ fn desc(errno: Errno) -> &'static str {
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 @@ fn desc(errno: Errno) -> &'static str {
))]
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 @@ fn desc(errno: Errno) -> &'static str {
#[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 @@ fn desc(errno: Errno) -> &'static str {
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 @@ fn desc(errno: Errno) -> &'static str {
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 @@ fn desc(errno: Errno) -> &'static str {
#[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 @@ mod consts {
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 @@ mod consts {
}
}
-#[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 @@ mod consts {
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 @@ mod consts {
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 @@ mod consts {
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 @@ mod consts {
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 @@ mod consts {
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 @@ mod consts {
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 @@ mod consts {
}
}
-#[cfg(any(target_os = "illumos", target_os = "solaris"))]
+#[cfg(solarish)]
mod consts {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(i32)]
@@ -2861,6 +2573,10 @@ mod consts {
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 @@ mod consts {
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 @@ mod consts {
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 @@ mod consts {
}
}
}
+
+#[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 @@ use crate::{sys::stat::Mode, NixPath, Result};
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 @@ libc_bitflags!(
/// 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 @@ libc_bitflags!(
O_NONBLOCK;
/// Don't deliver `SIGPIPE`.
#[cfg(target_os = "netbsd")]
- #[cfg_attr(docsrs, doc(cfg(all())))]
O_NOSIGPIPE;
/// Obtain a file descriptor for low-level access.
///
/// The file itself is not opened and other file operations will fail.
- #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
+ #[cfg(any(linux_android, target_os = "redox"))]
O_PATH;
/// Only allow reading.
///
@@ -161,36 +162,24 @@ libc_bitflags!(
/// 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 @@ libc_bitflags!(
}
);
+/// 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 @@ pub fn open<P: ?Sized + NixPath>(
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 @@ pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
#[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 @@ fn readlink_maybe_at<P: ?Sized + NixPath>(
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 @@ fn inner_readlink<P: ?Sized + NixPath>(
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 @@ fn inner_readlink<P: ?Sized + NixPath>(
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 @@ fn inner_readlink<P: ?Sized + NixPath>(
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 @@ fn inner_readlink<P: ?Sized + NixPath>(
} 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 @@ fn inner_readlink<P: ?Sized + NixPath>(
}
}
+/// 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 @@ libc_bitflags!(
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 @@ libc_bitflags!(
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 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
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 @@ pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> {
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(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(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
#[cfg(feature = "zerocopy")]
libc_bitflags! {
/// Additional flags to `splice` and friends.
@@ -636,7 +889,7 @@ feature! {
// 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 @@ pub fn copy_file_range<Fd1: AsFd, Fd2: AsFd>(
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 @@ pub fn copy_file_range<Fd1: AsFd, Fd2: AsFd>(
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 @@ pub fn splice(
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 @@ pub fn tee(
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 @@ pub fn vmsplice(
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 @@ pub struct SpacectlRange(pub libc::off_t, pub libc::off_t);
#[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 @@ impl SpacectlRange {
/// 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 @@ pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result<SpacectlRange> {
/// 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 @@ pub fn fspacectl_all(
}
#[cfg(any(
- target_os = "linux",
- target_os = "android",
+ linux_android,
target_os = "emscripten",
target_os = "fuchsia",
target_os = "wasi",
@@ -937,21 +1209,34 @@ mod posix_fadvise {
#[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 @@ mod posix_fadvise {
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 @@ pub fn posix_fallocate(
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 @@ mod os {
}
#[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 @@ mod os {
#[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 @@ pub struct InterfaceAddress {
}
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 @@ cfg_if! {
/// 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 @@ unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option<SockaddrStorage> {
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 @@ impl InterfaceAddress {
fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress {
let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) };
let address = unsafe { SockaddrStorage::from_raw(info.ifa_addr, None) };
- #[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 @@ libc_bitflags!(
/// 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 @@ feature! {
#[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 @@ feature! {
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 @@ feature! {
#[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 @@ impl NixPath for [u8] {
}
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 @@ macro_rules! feature {
/// /// 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 @@ macro_rules! libc_bitflags {
/// 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 @@ libc_bitflags!(
pub struct MntFlags: c_int {
/// ACL support enabled.
#[cfg(any(target_os = "netbsd", target_os = "freebsd"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
MNT_ACLS;
/// All I/O to the file system should be done asynchronously.
MNT_ASYNC;
/// dir should instead be a file system ID encoded as “FSID:val0:val1”.
#[cfg(target_os = "freebsd")]
- #[cfg_attr(docsrs, doc(cfg(all())))]
MNT_BYFSID;
/// Force a read-write mount even if the file system appears to be
/// unclean.
MNT_FORCE;
/// GEOM journal support enabled.
#[cfg(target_os = "freebsd")]
- #[cfg_attr(docsrs, doc(cfg(all())))]
MNT_GJOURNAL;
/// MAC support for objects.
- #[cfg(any(target_os = "macos", target_os = "freebsd"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
+ #[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 @@ libc_bitflags!(
/// 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 @@ libc_bitflags!(
/// 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 @@ pub type NmountResult = std::result::Result<(), NmountError>;
/// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount)
/// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs)
#[cfg(target_os = "freebsd")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
#[derive(Debug, Default)]
pub struct Nmount<'a> {
// n.b. notgull: In reality, this is a list that contains
@@ -210,12 +191,11 @@ pub struct Nmount<'a> {
}
#[cfg(target_os = "freebsd")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
impl<'a> Nmount<'a> {
/// Helper function to push a slice onto the `iov` array.
fn push_slice(&mut self, val: &'a [u8], is_owned: bool) {
self.iov.push(libc::iovec {
- iov_base: val.as_ptr() as *mut _,
+ iov_base: val.as_ptr().cast_mut().cast(),
iov_len: val.len(),
});
self.is_owned.push(is_owned);
@@ -386,7 +366,7 @@ impl<'a> Nmount<'a> {
// 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 @@ impl<'a> Nmount<'a> {
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 @@ libc_bitflags!(
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::NixPath;
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 @@ pub struct MqdT(mqd_t);
// 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 @@ pub fn mq_receive(
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 @@ feature! {
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 @@ feature! {
/// 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 @@ pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> {
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 @@ mod if_nameindex {
}
/// 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 @@ mod if_nameindex {
/// 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 @@ mod if_nameindex {
}
}
#[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 @@ pub struct PollFd<'fd> {
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 @@ libc_bitflags! {
POLLOUT;
/// Equivalent to [`POLLIN`](constant.POLLIN.html)
#[cfg(not(target_os = "redox"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
POLLRDNORM;
#[cfg(not(target_os = "redox"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
/// Equivalent to [`POLLOUT`](constant.POLLOUT.html)
POLLWRNORM;
/// Priority band data can be read (generally unused on Linux).
#[cfg(not(target_os = "redox"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
POLLRDBAND;
/// Priority data may be written.
#[cfg(not(target_os = "redox"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
POLLWRBAND;
/// Error condition (only returned in
/// [`PollFd::revents`](struct.PollFd.html#method.revents);
@@ -184,16 +192,19 @@ libc_bitflags! {
///
/// 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 @@ feature! {
/// 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 @@ pub fn ppoll(
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::Read for PtyMaster {
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::Read for &PtyMaster {
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 @@ pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> {
/// 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 @@ pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> {
///
/// 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 @@ pub unsafe fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b T
.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 @@ pub unsafe fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b T
})?;
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 @@ mod sched_linux_like {
}
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 @@ mod sched_linux_like {
}
}
-#[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 @@ use std::{
ptr, thread,
};
-use libc::{c_void, off_t};
+use libc::off_t;
use pin_utils::unsafe_pinned;
use crate::{
@@ -53,12 +53,9 @@ libc_enum! {
/// 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 @@ impl AioCb {
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 @@ impl<'a> AioRead<'a> {
) -> 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 @@ impl<'a> AioReadv<'a> {
// 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 @@ impl<'a> AioWrite<'a> {
// 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 @@ impl<'a> AioWritev<'a> {
// 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 @@ pub fn aio_suspend(
// 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 @@ pub fn aio_suspend(
/// // notification, we know that all operations are complete.
/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len());
/// ```
-#[deprecated(since = "0.27.0", note = "https://github.com/nix-rust/nix/issues/2017")]
+#[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 @@ pub fn lio_listio(
})
.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 @@ impl EpollEvent {
/// A safe wrapper around [`epoll`](https://man7.org/linux/man-pages/man7/epoll.7.html).
/// ```
-/// # use nix::sys::{epoll::{Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{eventfd, EfdFlags}};
+/// # use nix::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 @@ impl Epoll {
/// (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 @@ pub fn epoll_wait(
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_int, c_long, intptr_t, time_t, timespec, uintptr_t};
use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t};
use std::convert::TryInto;
use std::mem;
+use std::os::fd::{AsFd, BorrowedFd};
use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd};
use std::ptr;
@@ -29,6 +30,18 @@ pub struct KEvent {
#[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 @@ impl Kqueue {
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 @@ impl Kqueue {
}
}
-#[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 @@ libc_enum! {
/// 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 @@ libc_enum! {
/// # 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 @@ libc_enum! {
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 @@ libc_enum! {
impl TryFrom<type_of_event_filter>
}
-#[cfg(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "openbsd"
-))]
+#[cfg(any(freebsdlike, apple_targets, target_os = "openbsd"))]
#[doc(hidden)]
pub type type_of_event_flag = u16;
#[cfg(target_os = "netbsd")]
@@ -187,9 +182,7 @@ libc_bitflags! {
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 @@ libc_bitflags! {
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 @@ libc_bitflags! {
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 @@ libc_bitflags!(
// 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 @@ libc_bitflags!(
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 @@ libc_bitflags!(
#[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 @@ libc_bitflags!(
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 @@ pub fn kevent(
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 @@ pub fn ev_set(
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 @@ impl Inotify {
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 @@ impl Inotify {
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 @@ impl Inotify {
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 Inotify {
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 @@ pub const TYPEBITS: ioctl_num_type = 8;
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 @@ macro_rules! ioctl_none {
$(#[$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 @@ macro_rules! ioctl_none_bad {
$(#[$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 @@ macro_rules! ioctl_read {
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_rules! ioctl_read {
///
/// ```
/// # #[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 @@ macro_rules! ioctl_read_bad {
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 @@ macro_rules! ioctl_write_ptr {
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_rules! ioctl_write_ptr {
///
/// ```
/// # #[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 @@ macro_rules! ioctl_write_ptr_bad {
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 @@ cfg_if! {
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 @@ cfg_if! {
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 @@ cfg_if! {
///
/// ```
/// # #[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 @@ macro_rules! ioctl_write_int_bad {
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 @@ macro_rules! ioctl_readwrite {
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 @@ macro_rules! ioctl_readwrite_bad {
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 @@ macro_rules! ioctl_read_buf {
pub unsafe fn $name(fd: $crate::libc::c_int,
data: &mut [$ty])
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::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 @@ macro_rules! ioctl_write_buf {
pub unsafe fn $name(fd: $crate::libc::c_int,
data: &[$ty])
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::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 @@ macro_rules! ioctl_readwrite_buf {
pub unsafe fn $name(fd: $crate::libc::c_int,
data: &mut [$ty])
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::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 @@ libc_bitflags!(
///
/// [`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 @@ use crate::Result;
#[cfg(feature = "fs")]
use crate::{fcntl::OFlag, sys::stat::Mode};
use libc::{self, c_int, c_void, off_t, size_t};
-use std::{num::NonZeroUsize, os::unix::io::{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 @@ libc_bitflags! {
/// 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 @@ libc_bitflags! {
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 @@ libc_bitflags! {
pub struct MRemapFlags: c_int {
/// Permit the kernel to relocate the mapping to a new virtual address, if necessary.
#[cfg(target_os = "linux")]
- #[cfg_attr(docsrs, doc(cfg(all())))]
MREMAP_MAYMOVE;
/// Place the mapping at exactly the address specified in `new_address`.
#[cfg(target_os = "linux")]
- #[cfg_attr(docsrs, doc(cfg(all())))]
MREMAP_FIXED;
/// 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 @@ libc_enum! {
/// 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 @@ libc_enum! {
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 @@ libc_bitflags! {
/// 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 @@ libc_bitflags! {
/// `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 @@ pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
/// 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 @@ pub fn munlockall() -> Result<()> {
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 @@ pub unsafe fn mmap<F: AsFd>(
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 {
+ // 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 {
- 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) })
}
}
@@ -449,33 +457,43 @@ pub unsafe fn mmap<F: AsFd>(
/// 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 @@ pub unsafe fn mremap(
/// 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 @@ pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
/// [`MmapAdvise::MADV_FREE`].
///
/// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html
+#[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 @@ pub unsafe fn madvise(
///
/// ```
/// # 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 @@ pub unsafe fn mprotect(
///
/// [`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 @@ pub fn shm_open<P>(
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! {
#![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 @@ feature! {
pub mod pthread;
}
-#[cfg(any(
- target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "linux",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd"
-))]
+#[cfg(any(linux_android, bsd))]
feature! {
#![feature = "ptrace"]
#[allow(missing_docs)]
@@ -99,7 +79,7 @@ feature! {
pub mod quota;
}
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "linux", netbsdlike))]
feature! {
#![feature = "reboot"]
pub mod reboot;
@@ -108,7 +88,7 @@ feature! {
#[cfg(not(any(
target_os = "redox",
target_os = "fuchsia",
- target_os = "illumos",
+ solarish,
target_os = "haiku"
)))]
feature! {
@@ -121,14 +101,7 @@ feature! {
pub mod select;
}
-#[cfg(any(
- target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos"
-))]
+#[cfg(any(linux_android, freebsdlike, apple_targets, solarish))]
feature! {
#![feature = "zerocopy"]
pub mod sendfile;
@@ -136,7 +109,7 @@ feature! {
pub mod signal;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(linux_android)]
feature! {
#![feature = "signal"]
#[allow(missing_docs)]
@@ -155,15 +128,7 @@ feature! {
pub mod stat;
}
-#[cfg(any(
- target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
- target_os = "openbsd"
-))]
+#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "openbsd"))]
feature! {
#![feature = "fs"]
pub mod statfs;
@@ -174,8 +139,7 @@ feature! {
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 @@ feature! {
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 @@ feature! {
#[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 @@ libc_bitflags! {
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 @@ libc_bitflags! {
///
/// [`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 @@ pub fn get_child_subreaper() -> Result<bool> {
// 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 @@ pub fn get_keepcaps() -> Result<bool> {
/// 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 @@ pub fn get_name() -> Result<CString> {
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 @@ pub fn get_timerslack() -> Result<i32> {
/// 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 @@ use std::ptr;
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 @@ libc_enum! {
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 @@ unsafe fn ptrace_other(
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 @@ pub fn kill(pid: Pid) -> Result<()> {
/// }
/// ```
#[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 @@ libc_enum! {
#[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 @@ libc_enum! {
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 @@ libc_enum! {
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 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
/// 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 @@ unsafe fn ptrace_other(
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 @@ pub fn attach(pid: Pid) -> Result<()> {
///
/// Attaches to the process specified in pid, making it a tracee of the calling process.
#[cfg(target_os = "linux")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn seize(pid: Pid, options: Options) -> Result<()> {
unsafe {
ptrace_other(
@@ -428,7 +447,6 @@ pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
///
/// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)`
#[cfg(target_os = "linux")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn interrupt(pid: Pid) -> Result<()> {
unsafe {
ptrace_other(
@@ -535,7 +553,7 @@ pub unsafe fn write(
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 @@ pub unsafe fn write_user(
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 @@ pub fn quotactl_on<P: ?Sized + NixPath>(
) -> 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 @@ pub fn quotactl_get<P: ?Sized + NixPath>(
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,
- }
-}
-/// Reboots or shuts down the system.
-pub fn reboot(how: RebootMode) -> Result<Infallible> {
- unsafe { libc::reboot(how as libc::c_int) };
- Err(Errno::last())
-}
+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)
+ /// 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())
+ }
+ }
}
+
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 @@ pub use libc::RLIM_INFINITY;
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 @@ libc_enum! {
//
// https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html
// https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs
- #[cfg_attr(all(target_os = "linux", 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 @@ libc_enum! {
RLIMIT_STACK,
#[cfg(target_os = "freebsd")]
- #[cfg_attr(docsrs, doc(cfg(all())))]
/// The maximum number of kqueues this user id is allowed to create.
RLIMIT_KQUEUES,
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
+ #[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 @@ pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> {
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 @@ pub fn setrlimit(
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 @@ libc_enum! {
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 @@ pub fn getrusage(who: UsageWho) -> Result<Usage> {
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::convert::TryFrom;
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 @@ impl<'fd> FdSet<'fd> {
}
/// 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 @@ impl<'fd> FdSet<'fd> {
/// 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 @@ impl<'fd> FdSet<'fd> {
/// 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 @@ impl<'a, 'fd> Iterator for Fds<'a, 'fd> {
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 @@ impl<'a, 'fd> DoubleEndedIterator for Fds<'a, 'fd> {
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 @@ where
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 @@ use crate::Result;
///
/// `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 @@ pub fn sendfile<F1: AsFd, F2: AsFd>(
///
/// 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 @@ pub fn sendfile64<F1: AsFd, F2: AsFd>(
}
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 @@ cfg_if! {
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 @@ cfg_if! {
) -> (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 @@ cfg_if! {
};
(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 @@ cfg_if! {
) -> (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 @@ cfg_if! {
};
(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::errno::Errno;
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 @@ libc_enum! {
/// 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 @@ libc_enum! {
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 @@ impl FromStr for Signal {
"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 @@ impl FromStr for Signal {
#[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 @@ impl Signal {
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 @@ impl Signal {
#[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 @@ const SIGNALS: [Signal; 28] = [
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 @@ const SIGNALS: [Signal; 31] = [
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 @@ const SIGNALS: [Signal; 30] = [
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 @@ libc_bitflags! {
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 @@ use std::iter::IntoIterator;
// 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 @@ impl SigSet {
/// Suspends execution of the calling thread until one of the signals in the
/// signal mask becomes pending, and returns the accepted signal.
#[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait
- #[cfg_attr(docsrs, doc(cfg(all())))]
pub fn wait(&self) -> Result<Signal> {
use std::convert::TryFrom;
@@ -589,6 +582,35 @@ impl SigSet {
})
}
+ /// 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 SigSet {
}
}
+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 FromIterator<Signal> for SigSet {
}
}
+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 @@ pub enum SigHandler {
/// Use the given signal-catching function, which takes in the signal, information about how
/// the signal was generated, and a pointer to the threads `ucontext_t`.
#[cfg(not(target_os = "redox"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
}
@@ -689,23 +767,27 @@ impl SigAction {
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 @@ impl SigAction {
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 sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigActi
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 @@ pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler>
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 @@ feature! {
#[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 @@ pub enum SigevNotify {
},
// 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 @@ pub enum SigevNotify {
},
/// 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 @@ pub enum SigevNotify {
target_env = "gnu",
target_env = "uclibc",
))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
SigevThreadId {
/// Signal to send
signal: Signal,
@@ -1082,10 +1159,10 @@ pub enum SigevNotify {
#[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 @@ mod sigevent {
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 @@ mod sigevent {
}
}
}
-
-#[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 @@ use crate::Result;
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 @@ pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::<siginfo>();
///
/// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html)
#[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 @@ impl SignalFd {
}
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 @@ impl SignalFd {
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 @@ impl SignalFd {
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 @@ impl Iterator for SignalFd {
}
}
}
-
-#[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 memoffset::offset_of;
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 @@ use std::{fmt, mem, net, ptr, slice};
#[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 @@ pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr {
#[cfg(feature = "net")]
pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr {
libc::in6_addr {
- s6_addr: addr.octets()
+ s6_addr: addr.octets(),
}
}
@@ -71,346 +63,188 @@ pub enum AddressFamily {
/// 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 @@ impl AddressFamily {
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 @@ pub struct UnixAddr {
/// The length of the valid part of `sun`, including the sun_family field
/// but excluding any trailing nul.
// On the BSDs, this field is built into sun
- #[cfg(any(
- target_os = "android",
- target_os = "fuchsia",
- target_os = "illumos",
- target_os = "linux",
- target_os = "redox",
- ))]
+ #[cfg(not(any(bsd, target_os = "haiku", target_os = "hurd")))]
sun_len: u8,
}
@@ -483,12 +299,12 @@ pub struct UnixAddr {
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 @@ impl<'a> UnixAddrKind<'a> {
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<'a> UnixAddrKind<'a> {
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 @@ impl UnixAddr {
.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 @@ impl UnixAddr {
/// 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 @@ impl UnixAddr {
// 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 @@ impl UnixAddr {
}
/// Create a new `sockaddr_un` representing an "unnamed" unix socket address.
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
+ #[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 @@ impl UnixAddr {
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 @@ impl UnixAddr {
///
/// 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 @@ impl UnixAddr {
}
/// Check if this address is an "unnamed" unix socket address.
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
+ #[cfg(linux_android)]
#[inline]
pub fn is_unnamed(&self) -> bool {
matches!(self.kind(), UnixAddrKind::Unnamed)
@@ -699,10 +506,9 @@ impl UnixAddr {
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 UnixAddr {
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 @@ impl SockaddrLike for UnixAddr {
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 @@ impl SockaddrLike for UnixAddr {
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 @@ impl AsRef<libc::sockaddr_un> for UnixAddr {
}
}
-#[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 @@ impl fmt::Display for UnixAddr {
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 @@ pub trait SockaddrLike: private::SockaddrLikePriv {
}
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 @@ pub trait SockaddrLike: private::SockaddrLikePriv {
/// `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 @@ pub struct SockaddrIn(libc::sockaddr_in);
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 @@ impl SockaddrLike for SockaddrIn {
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 @@ impl From<net::SocketAddrV4> for SockaddrIn {
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 @@ impl SockaddrIn6 {
}
/// 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 @@ impl SockaddrLike for SockaddrIn6 {
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 @@ impl From<net::SocketAddrV6> for SockaddrIn6 {
#[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 @@ impl std::str::FromStr for SockaddrIn6 {
#[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 @@ pub union SockaddrStorage {
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 @@ impl SockaddrLike for SockaddrStorage {
{
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 @@ impl SockaddrLike for SockaddrStorage {
// 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 @@ impl SockaddrLike for SockaddrStorage {
}
}
- 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 @@ impl SockaddrStorage {
/// 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 @@ impl SockaddrStorage {
/// 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 @@ impl SockaddrStorage {
}
}
- #[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 @@ impl SockaddrStorage {
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 @@ impl fmt::Display for SockaddrStorage {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe {
match self.ss.ss_family as i32 {
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[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 @@ impl Hash for SockaddrStorage {
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 @@ impl PartialEq for SockaddrStorage {
fn eq(&self, other: &Self) -> bool {
unsafe {
match (self.ss.ss_family as i32, other.ss.ss_family as i32) {
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[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 @@ pub(super) mod private {
}
}
-#[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 @@ pub mod netlink {
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 @@ pub mod netlink {
}
}
-#[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 @@ pub mod alg {
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 @@ pub mod alg {
/// Return the socket's cipher type, for example `hash` or `aead`.
pub fn alg_type(&self) -> &CStr {
- unsafe {
- CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char)
- }
+ 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 @@ pub mod alg {
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 @@ pub mod sys_control {
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 @@ pub mod sys_control {
}
}
-#[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 @@ mod datalink {
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 @@ mod datalink {
}
}
-#[cfg(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "illumos",
- target_os = "netbsd",
- target_os = "haiku",
- target_os = "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 @@ mod datalink {
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 @@ mod datalink {
}
}
-#[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 @@ pub mod vsock {
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 @@ pub mod vsock {
}
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 @@ pub mod vsock {
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 @@ mod tests {
}
}
- #[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 @@ mod tests {
}
#[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 @@ mod tests {
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 @@ mod tests {
}
}
- #[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 @@ mod tests {
}
}
- #[cfg(any(target_os = "ios", target_os = "macos"))]
+ #[cfg(apple_targets)]
#[test]
fn macos_tap() {
let bytes = [
@@ -2525,9 +2240,9 @@ mod tests {
}
}
- #[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 @@ mod tests {
#[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 @@ mod tests {
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 @@ mod tests {
}
#[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 @@ mod tests {
#[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 tests {
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::TimeSpec;
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 mod sockopt;
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 @@ pub enum SockProtocol {
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,
+ /// 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")]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- CanRaw = libc::CAN_RAW,
-}
+ #[allow(non_upper_case_globals)]
+ pub const CanRaw: SockProtocol = SockProtocol::Icmp; // Matches libc::CAN_RAW
-impl SockProtocol {
/// The Controller Area Network broadcast manager protocol
/// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan))
#[cfg(target_os = "linux")]
- #[cfg_attr(docsrs, doc(cfg(all())))]
#[allow(non_upper_case_globals)]
pub const CanBcm: SockProtocol = SockProtocol::NetlinkUserSock; // Matches libc::CAN_BCM
+
+ /// 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 @@ libc_bitflags! {
/// 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 @@ libc_bitflags! {
/// 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 @@ libc_bitflags! {
/// 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 @@ libc_bitflags! {
/// [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 @@ cfg_if! {
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 @@ cfg_if! {
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! {
}
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 @@ feature! {
/// 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 @@ macro_rules! cmsg_space {
#[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 @@ impl<'a> Iterator for CmsgIterator<'a> {
}
/// 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 @@ pub enum ControlMessageOwned {
/// 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 @@ pub enum ControlMessageOwned {
/// 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 @@ pub enum ControlMessageOwned {
///
/// `RxqOvfl` socket option should be enabled on a socket
/// to allow receiving the drop counter.
- #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
+ #[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 struct Timestamps {
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 @@ impl ControlMessageOwned {
#[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 @@ impl ControlMessageOwned {
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 @@ pub enum ControlMessage<'a> {
///
/// For further information, please refer to the
/// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page.
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
+ #[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 @@ pub enum ControlMessage<'a> {
///
/// For further information, please refer to the
/// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page.
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
+ #[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 @@ pub enum ControlMessage<'a> {
#[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 @@ impl<'a> ControlMessage<'a> {
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 @@ impl<'a> ControlMessage<'a> {
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 @@ impl<'a> ControlMessage<'a> {
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 @@ impl<'a> ControlMessage<'a> {
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 @@ impl<'a> ControlMessage<'a> {
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 @@ impl<'a> ControlMessage<'a> {
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 @@ impl<'a> ControlMessage<'a> {
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 @@ impl<'a> ControlMessage<'a> {
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 @@ impl<'a> ControlMessage<'a> {
// 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 @@ impl<'a> ControlMessage<'a> {
/// 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 @@ impl<'a> ControlMessage<'a> {
/// 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 @@ pub fn sendmsg<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage],
///
/// # 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 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>(
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 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>(
for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() {
let 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 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>(
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 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>(
}
-#[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 @@ pub struct MultiHeaders<S> {
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 @@ impl<S> MultiHeaders<S> {
.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 @@ impl<S> MultiHeaders<S> {
// 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 @@ pub fn recvmmsg<'a, XS, S, I>(
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 @@ where
.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 @@ where
})
}
-#[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 @@ pub struct MultiResults<'a, S> {
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 @@ impl<'a> Iterator for IoSliceIterator<'a> {
}
}
-// 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 @@ unsafe fn read_mhdr<'a, 'i, S>(
// 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 @@ unsafe fn pack_mhdr_to_receive<S>(
// 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 @@ fn pack_mhdr_to_send<'a, I, C, S>(
// The message header must be initialized before the individual cmsgs.
let cmsg_ptr = if capacity > 0 {
- cmsg_buffer.as_mut_ptr() as *mut c_void
+ cmsg_buffer.as_mut_ptr().cast()
} else {
ptr::null_mut()
};
@@ -2035,11 +1873,11 @@ fn pack_mhdr_to_send<'a, I, C, S>(
// 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 @@ pub fn socketpair<T: Into<Option<SockProtocol>>>(
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 @@ pub fn accept(sockfd: RawFd) -> Result<RawFd> {
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 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
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 @@ pub fn recvfrom<T: SockaddrLike>(
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 @@ pub fn sendto(
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 @@ pub fn sendto(
/// [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 @@ pub fn getpeername<T: SockaddrLike>(fd: RawFd) -> Result<T> {
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 @@ pub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> {
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 @@ pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
}
}
-#[cfg(test)]
-mod tests {
- #[cfg(not(target_os = "redox"))]
- #[test]
- fn can_use_cmsg_space() {
- let _ = cmsg_space!(u8);
- }
-
- #[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 cfg_if::cfg_if;
use libc::{self, c_int, c_void, socklen_t};
use std::ffi::{OsStr, OsString};
use std::mem::{self, MaybeUninit};
-#[cfg(target_family = "unix")]
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::{AsFd, AsRawFd};
@@ -128,7 +127,7 @@ macro_rules! getsockopt_impl {
/// 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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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_if! {
#[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 @@ sockopt_impl!(
#[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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ cfg_if! {
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
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 @@ sockopt_impl!(
#[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 @@ impl SetSockOpt for AlgSetAeadAuthSize {
#[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,54 @@ where
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)
+ }
+ }
+}
+
+/// 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)
@@ -1111,6 +1173,113 @@ where
}
}
+/// 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 @@ impl<T> Get<T> for GetStruct<T> {
}
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 @@ impl<T> Get<T> for GetStruct<T> {
mem::size_of::<T>(),
"invalid getsockopt implementation"
);
- self.val.assume_init()
+ unsafe { self.val.assume_init() }
}
}
@@ -1209,7 +1378,7 @@ impl Get<bool> for GetBool {
}
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 @@ impl Get<bool> for GetBool {
mem::size_of::<c_int>(),
"invalid getsockopt implementation"
);
- self.val.assume_init() != 0
+ unsafe { self.val.assume_init() != 0 }
}
}
@@ -1243,7 +1412,7 @@ impl<'a> Set<'a, bool> for SetBool {
}
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 @@ impl Get<u8> for GetU8 {
}
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 @@ impl Get<u8> for GetU8 {
mem::size_of::<u8>(),
"invalid getsockopt implementation"
);
- self.val.assume_init()
+ unsafe { self.val.assume_init() }
}
}
@@ -1294,7 +1463,7 @@ impl<'a> Set<'a, u8> for SetU8 {
}
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 @@ impl Get<usize> for GetUsize {
}
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 @@ impl Get<usize> for GetUsize {
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 @@ impl<'a> Set<'a, usize> for SetUsize {
}
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 @@ impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
}
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 @@ impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
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 @@ impl<'a> Set<'a, OsString> for SetOsString<'a> {
}
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 @@ impl<'a> Set<'a, OsString> for SetOsString<'a> {
}
}
-#[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 @@ libc_bitflags! {
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 @@ libc_bitflags! {
}
}
-#[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 @@ libc_bitflags! {
#[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 @@ libc_bitflags! {
#[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 @@ libc_bitflags! {
#[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 @@ libc_bitflags! {
#[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 @@ pub fn mknod<P: ?Sized + NixPath>(
}
/// 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 @@ pub fn mknodat<P: ?Sized + NixPath>(
}
#[cfg(target_os = "linux")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
pub const fn major(dev: dev_t) -> u64 {
((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff)
}
#[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 @@ pub fn fstat(fd: RawFd) -> Result<FileStat> {
}
#[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 @@ pub enum FchmodatFlags {
///
/// [fchmodat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html).
#[cfg(not(target_os = "redox"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn fchmodat<P: ?Sized + NixPath>(
dirfd: Option<RawFd>,
path: &P,
@@ -383,12 +357,10 @@ pub fn utimes<P: ?Sized + NixPath>(
#[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 @@ pub fn lutimes<P: ?Sized + NixPath>(
/// 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 @@ pub enum UtimensatFlags {
/// `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 @@ pub fn utimensat<P: ?Sized + NixPath>(
}
#[cfg(not(target_os = "redox"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn mkdirat<P: ?Sized + NixPath>(
- fd: RawFd,
+ 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 std::os::unix::io::{AsFd, AsRawFd};
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 @@ use crate::{errno::Errno, NixPath, Result};
/// 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 @@ pub struct Statfs(type_of_statfs);
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 @@ type fs_type_t = libc::c_int;
not(any(
target_arch = "s390x",
target_env = "musl",
+ target_env = "ohos",
target_env = "uclibc"
))
))]
@@ -84,6 +76,7 @@ type fs_type_t = libc::__fsword_t;
target_os = "android",
all(target_os = "linux", target_arch = "s390x"),
all(target_os = "linux", target_env = "musl"),
+ all(target_os = "linux", target_env = "ohos"),
all(
target_os = "linux",
not(any(target_arch = "s390x", target_env = "musl"))
@@ -94,206 +87,203 @@ pub struct FsType(pub fs_type_t);
// These constants are defined without documentation in the Linux headers, so we
// can't very well document them here.
-#[cfg(any(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 @@ impl Statfs {
#[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 @@ impl Statfs {
/// 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 @@ impl Statfs {
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 @@ impl Statfs {
/// Size of a block
// f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
#[cfg(all(target_os = "linux", target_env = "musl"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
+ pub fn block_size(&self) -> libc::c_ulong {
+ self.0.f_bsize
+ }
+
+ /// 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 @@ impl Statfs {
/// Size of a block
// f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
#[cfg(all(target_os = "linux", target_env = "uclibc"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
pub fn block_size(&self) -> libc::c_int {
self.0.f_bsize
}
@@ -422,47 +406,34 @@ impl Statfs {
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 @@ impl Statfs {
// 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 @@ impl Statfs {
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 @@ impl Debug for Statfs {
ds.field("files", &self.files());
ds.field("files_free", &self.files_free());
ds.field("filesystem_id", &self.filesystem_id());
- #[cfg(all(
- feature = "mount",
- any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "openbsd"
- )
- ))]
+ #[cfg(all(feature = "mount", bsd))]
ds.field("flags", &self.flags());
ds.finish()
}
@@ -747,107 +672,3 @@ pub fn fstatfs<Fd: AsFd>(fd: Fd) -> Result<Statfs> {
.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 @@ libc_bitflags!(
#[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 @@ impl Statvfs {
}
/// 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 @@ pub fn fstatvfs<Fd: AsFd>(fd: Fd) -> Result<Statvfs> {
.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 @@ pub struct Termios {
/// Control characters (see `termios.c_cc` documentation)
pub control_chars: [libc::cc_t; NCCS],
/// Line discipline (see `termios.c_line` documentation)
- #[cfg(any(target_os = "linux", target_os = "android",))]
+ #[cfg(linux_android)]
pub line_discipline: libc::cc_t,
/// Line discipline (see `termios.c_line` documentation)
#[cfg(target_os = "haiku")]
@@ -266,11 +186,7 @@ impl Termios {
termios.c_cflag = self.control_flags.bits();
termios.c_lflag = self.local_flags.bits();
termios.c_cc = self.control_chars;
- #[cfg(any(
- target_os = "linux",
- target_os = "android",
- target_os = "haiku",
- ))]
+ #[cfg(any(linux_android, target_os = "haiku"))]
{
termios.c_line = self.line_discipline;
}
@@ -292,11 +208,7 @@ impl Termios {
termios.c_cflag = self.control_flags.bits();
termios.c_lflag = self.local_flags.bits();
termios.c_cc = self.control_chars;
- #[cfg(any(
- target_os = "linux",
- target_os = "android",
- target_os = "haiku",
- ))]
+ #[cfg(any(linux_android, target_os = "haiku"))]
{
termios.c_line = self.line_discipline;
}
@@ -307,16 +219,12 @@ impl Termios {
/// 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 @@ impl From<libc::termios> for Termios {
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 @@ libc_enum! {
///
/// 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 @@ libc_enum! {
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 @@ libc_enum! {
}
// TODO: Make this usable directly as a slice index.
-#[cfg(not(target_os = "haiku"))]
libc_enum! {
/// Indices into the `termios.c_cc` array for special characters.
#[repr(usize)]
#[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 @@ impl SpecialCharacterIndices {
}
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 @@ libc_bitflags! {
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 @@ libc_bitflags! {
/// 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! {
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 @@ libc_bitflags! {
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 @@ libc_bitflags! {
/// Flags for setting any local modes
pub struct LocalFlags: tcflag_t {
#[cfg(not(target_os = "redox"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
ECHOKE;
ECHOE;
ECHOK;
ECHO;
ECHONL;
#[cfg(not(target_os = "redox"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
ECHOPRT;
#[cfg(not(target_os = "redox"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
ECHOCTL;
ISIG;
ICANON;
- #[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 @@ pub fn cfmakeraw(termios: &mut Termios) {
///
/// Note that this is a non-standard function, available on FreeBSD.
#[cfg(target_os = "freebsd")]
-#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn cfmakesane(termios: &mut Termios) {
let inner_termios = unsafe { termios.get_libc_termios_mut() };
unsafe {
@@ -1242,18 +923,3 @@ pub fn tcgetsid<Fd: AsFd>(fd: Fd) -> Result<Pid> {
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 @@ const fn zero_init_timespec() -> timespec {
all(
any(
target_os = "freebsd",
- target_os = "illumos",
+ solarish,
target_os = "linux",
target_os = "netbsd"
),
@@ -88,7 +87,7 @@ pub(crate) mod timer {
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 @@ pub(crate) mod timer {
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 TimeValLike for TimeSpec {
}
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 mod_floor_64(this: i64, other: i64) -> i64 {
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 AsFd for TimerFd {
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 @@ pub fn writev<Fd: AsFd>(fd: Fd, iov: &[IoSlice<'_>]) -> Result<usize> {
//
// 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 writev<Fd: AsFd>(fd: Fd, iov: &[IoSlice<'_>]) -> Result<usize> {
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 @@ pub fn readv<Fd: AsFd>(fd: Fd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> {
/// 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 @@ pub fn pwritev<Fd: AsFd>(fd: Fd, iov: &[IoSlice<'_>], offset: off_t) -> Result<u
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 @@ pub fn pwritev<Fd: AsFd>(fd: Fd, iov: &[IoSlice<'_>], offset: off_t) -> Result<u
/// 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 @@ pub fn preadv<Fd: AsFd>(
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 @@ pub fn pwrite<Fd: AsFd>(fd: Fd, buf: &[u8], offset: off_t) -> Result<usize> {
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 @@ pub fn pread<Fd: AsFd>(fd: Fd, buf: &mut [u8], offset: off_t) -> Result<usize> {
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 @@ pub fn pread<Fd: AsFd>(fd: Fd, buf: &mut [u8], offset: off_t) -> Result<usize> {
/// 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 @@ feature! {
/// [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 @@ pub fn process_vm_writev(
{
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 @@ pub fn process_vm_writev(
/// [`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 @@ pub fn process_vm_readv(
{
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 @@ impl UtsName {
}
/// 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 @@ fn cast_and_trim(slice: &[c_char]) -> &OsStr {
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 @@ libc_bitflags!(
/// [`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 @@ pub enum WaitStatus {
///
/// [`nix::sys::ptrace`]: ../ptrace/index.html
/// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html
- #[cfg(any(target_os = "linux", target_os = "android"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
+ #[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 @@ impl WaitStatus {
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 @@ fn stop_signal(status: i32) -> Result<Signal> {
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 @@ fn syscall_stop(status: i32) -> bool {
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 @@ impl WaitStatus {
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 @@ impl WaitStatus {
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 @@ impl WaitStatus {
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 @@ impl WaitStatus {
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 @@ pub enum Id<'fd> {
/// 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 @@ pub fn waitid(id: Id, flags: WaitPidFlag) -> Result<WaitStatus> {
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 @@ use std::mem::MaybeUninit;
/// 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 @@ impl ClockId {
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 @@ impl ClockId {
/// 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 @@ impl ClockId {
/// 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 @@ impl ClockId {
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 @@ impl std::fmt::Display for ClockId {
/// Get the resolution of the specified clock, (see
/// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)).
#[cfg(not(target_os = "redox"))]
-#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> {
let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
let ret =
@@ -247,12 +200,12 @@ pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> {
/// 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 @@ pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> {
/// 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 @@ pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
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 @@ use crate::{Error, NixPath, Result};
#[cfg(not(target_os = "redox"))]
use cfg_if::cfg_if;
use libc::{
- self, c_char, c_int, c_long, c_uint, c_void, gid_t, mode_t, off_t, pid_t,
- size_t, uid_t, PATH_MAX,
+ 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 @@ impl fmt::Display for Pid {
/// 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 @@ impl ForkResult {
/// }
/// 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 @@ impl ForkResult {
#[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 @@ pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> {
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 @@ feature! {
/// 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 @@ pub fn tcgetpgrp(fd: c_int) -> Result<Pid> {
/// 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 @@ pub fn getpgrp() -> Pid {
///
/// 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 @@ pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> {
}
/// 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)
-}
-
-#[inline]
-fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
- if oldfd == newfd {
- return Err(Errno::EINVAL);
- }
+ let res = unsafe { libc::dup3(oldfd, newfd, flags.bits()) };
- 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 @@ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
// 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 @@ feature! {
/// ```
#[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 @@ pub fn getcwd() -> 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
+
// 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 @@ pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
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 @@ pub enum FchownatFlags {
/// 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 @@ pub fn fchownat<P: ?Sized + NixPath>(
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 @@ pub fn fchownat<P: ?Sized + NixPath>(
cstr.as_ptr(),
uid,
gid,
- atflag.bits() as libc::c_int,
+ flag.bits()
)
})?;
@@ -883,7 +882,7 @@ pub fn execvp<S: AsRef<CStr>>(
/// 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 @@ pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(
///
/// 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 @@ pub fn fexecve<SA: AsRef<CStr>, SE: AsRef<CStr>>(
///
/// 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 @@ pub fn execveat<SA: AsRef<CStr>, SE: AsRef<CStr>>(
/// * `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 @@ feature! {
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 sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
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 @@ pub fn close(fd: RawFd) -> Result<()> {
///
/// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html)
pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<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 @@ pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> {
/// 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 @@ pub enum Whence {
/// 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 @@ pub enum Whence {
/// 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 @@ pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> {
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 @@ pub fn lseek64(
/// 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 @@ feature! {
///
/// 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 @@ pub fn ftruncate<Fd: AsFd>(fd: Fd, len: off_t) -> Result<()> {
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 @@ pub fn isatty(fd: RawFd) -> Result<bool> {
}
}
-/// 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 @@ pub enum LinkatFlags {
/// 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 @@ pub fn linkat<P: ?Sized + NixPath>(
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 @@ pub fn linkat<P: ?Sized + NixPath>(
oldcstr.as_ptr(),
at_rawfd(newdirfd),
newcstr.as_ptr(),
- atflag.bits() as libc::c_int,
+ flag.bits(),
)
})
})??;
@@ -1335,7 +1328,9 @@ pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> {
/// 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 @@ pub fn unlinkat<P: ?Sized + NixPath>(
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 @@ pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
/// 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 @@ pub fn sync() {
/// 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 @@ pub fn fsync(fd: RawFd) -> Result<()> {
/// See also
/// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html)
#[cfg(any(
- target_os = "linux",
- target_os = "android",
- target_os = "emscripten",
+ 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 @@ feature! {
/// 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 @@ pub fn setfsuid(uid: Uid) -> Uid {
/// 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 @@ feature! {
/// **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 @@ pub fn getgroups() -> Result<Vec<Gid>> {
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 @@ pub fn getgroups() -> Result<Vec<Gid>> {
/// # 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 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> {
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 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> {
/// 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 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
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 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
/// # 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 @@ pub fn sleep(seconds: c_uint) -> c_uint {
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 @@ feature! {
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 @@ pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
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 @@ feature! {
#[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 @@ pub enum PathconfVar {
/// 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 @@ pub enum PathconfVar {
/// 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 @@ pub enum PathconfVar {
/// - `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 @@ pub fn pathconf<P: ?Sized + NixPath>(
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 @@ pub enum SysconfVar {
/// 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 @@ pub enum SysconfVar {
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 @@ pub enum SysconfVar {
NGROUPS_MAX = libc::_SC_NGROUPS_MAX,
/// Initial size of `getgrgid_r` and `getgrnam_r` data buffers
#[cfg(not(target_os = "redox"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX,
/// Initial size of `getpwuid_r` and `getpwnam_r` data buffers
#[cfg(not(target_os = "redox"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX,
/// The maximum number of open message queue descriptors a process may hold.
#[cfg(not(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 @@ pub enum SysconfVar {
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 @@ pub enum SysconfVar {
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 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> {
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 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> {
}
}
-#[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 @@ mod pivot_root {
}
}
-#[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 @@ mod setres {
}
}
-#[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 @@ mod getres {
/// 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 @@ mod getres {
///
#[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 @@ mod getres {
///
#[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 @@ mod getres {
}
}
+#[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 @@ pub fn faccessat<P: ?Sized + NixPath>(
/// * [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 struct User {
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 @@ impl From<&libc::passwd> for User {
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 @@ impl From<User> for libc::passwd {
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 @@ impl User {
} 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 @@ impl Group {
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 @@ impl Group {
} 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 @@ feature! {
/// 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 @@ feature! {
/// 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 @@ feature! {
/// 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 @@ use cfg_if::cfg_if;
#[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 @@ macro_rules! require_mount {
};
}
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
#[macro_export]
macro_rules! skip_if_cirrus {
($reason:expr) => {
@@ -87,7 +87,7 @@ macro_rules! skip_if_not_root {
}
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 @@ mod test_signal;
// 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 @@ mod test_socket;
#[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_termios;
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 @@ mod aio_fsync {
// 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 @@ mod aio_read {
// 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 @@ mod aio_write {
// 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 @@ mod aio_writev {
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 @@ fn test_aio_cancel_all() {
}
#[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 @@ fn test_aio_suspend() {
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 @@ ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32);
// 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 @@ mod linux {
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 @@ mod linux {
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 @@ mod linux {
#[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 @@ mod linux {
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 @@ mod linux {
#[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 @@ mod linux {
}
}
-#[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 @@ mod bsd {
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 @@ mod bsd {
}
}
-#[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 @@ fn test_mremap_grow() {
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 @@ fn test_mremap_grow() {
.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 @@ fn test_mremap_grow() {
// Segfaults for unknown reasons under QEMU for 32-bit targets
#[cfg_attr(all(target_pointer_width = "32", qemu), ignore)]
fn test_mremap_shrink() {
- use nix::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 @@ fn test_mremap_shrink() {
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 @@ fn test_mremap_shrink() {
.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 @@ fn test_ptrace() {
// 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 @@ fn test_ptrace_setoptions() {
// 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 @@ fn test_ptrace_getevent() {
// 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 @@ fn test_ptrace_getsiginfo() {
// 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/test_resource.rs b/test/sys/test_resource.rs
index 2ab581b..8b12a94 100644
--- a/test/test_resource.rs
+++ b/test/sys/test_resource.rs
@@ -1,10 +1,5 @@
-#[cfg(not(any(
- target_os = "redox",
- target_os = "fuchsia",
- target_os = "illumos",
- target_os = "haiku"
-)))]
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
@@ -15,12 +10,6 @@ use nix::sys::resource::{getrlimit, setrlimit, Resource};
/// to put the new soft limit in effect, and then getrlimit() once more to ensure the limits have
/// been updated.
#[test]
-#[cfg(not(any(
- target_os = "redox",
- target_os = "fuchsia",
- target_os = "illumos",
- target_os = "haiku"
-)))]
pub fn test_resource_limits_nofile() {
let (mut soft_limit, hard_limit) =
getrlimit(Resource::RLIMIT_NOFILE).unwrap();
@@ -32,3 +21,23 @@ pub fn test_resource_limits_nofile() {
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 @@ pub fn test_pselect() {
1,
pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap()
);
- assert!(fd_set.contains(&r1));
- assert!(!fd_set.contains(&r2));
+ assert!(fd_set.contains(r1.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 @@ pub fn test_pselect_nfds2() {
)
.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 @@ macro_rules! generate_fdset_bad_fd_tests {
#[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 @@ macro_rules! generate_fdset_bad_fd_tests {
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 @@ mod test_fdset_too_large_fd {
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 @@ fn test_signal() {
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 @@ fn test_signal() {
// 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 @@ fn test_signal() {
// 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 @@ fn test_signalfd() {
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 @@ pub fn test_timestamping() {
};
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 @@ pub fn test_timestamping() {
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 @@ pub fn test_addr_equality_path() {
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 @@ pub fn test_abstract_sun_path_too_long() {
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 @@ pub fn test_addr_equality_abstract() {
}
// 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 @@ pub fn test_abstract_uds_addr() {
}
// 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 @@ pub fn test_socketpair() {
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 @@ mod recvfrom {
#[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 @@ mod recvfrom {
}
}
- #[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 @@ mod recvfrom {
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 @@ mod recvfrom {
let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
rsock.as_raw_fd(),
&mut data,
- msgs.iter(),
+ msgs.iter_mut(),
MsgFlags::empty(),
None,
)
@@ -585,12 +694,7 @@ mod recvfrom {
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 @@ mod recvfrom {
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 @@ mod recvfrom {
#[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 @@ pub fn test_scm_rights() {
{
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 @@ pub fn test_scm_rights() {
.unwrap(),
5
);
- close(r).unwrap();
}
{
@@ -803,16 +906,15 @@ pub fn test_scm_rights() {
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 @@ pub fn test_af_alg_cipher() {
// Disable the test on emulated platforms due to not enabled support of AF_ALG
// in QEMU from rust cross
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(linux_android)]
#[cfg_attr(qemu, ignore)]
#[test]
pub fn test_af_alg_aead() {
@@ -1039,7 +1141,7 @@ pub fn test_af_alg_aead() {
// This would be a more interesting test if we could assume that the test host
// has more than one IP address (since we could select a different address to
// test from).
-#[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd"))]
+#[cfg(any(target_os = "linux", apple_targets, target_os = "netbsd"))]
#[test]
pub fn test_sendmsg_ipv4packetinfo() {
use cfg_if::cfg_if;
@@ -1101,7 +1203,7 @@ pub fn test_sendmsg_ipv4packetinfo() {
// test from).
#[cfg(any(
target_os = "linux",
- target_os = "macos",
+ apple_targets,
target_os = "netbsd",
target_os = "freebsd"
))]
@@ -1158,12 +1260,7 @@ pub fn test_sendmsg_ipv6packetinfo() {
//
// 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 @@ pub fn test_sendmsg_empty_cmsgs() {
)
.unwrap();
- for _ in msg.cmsgs() {
+ if msg.cmsgs().next().is_some() {
panic!("unexpected cmsg");
}
assert!(!msg
@@ -1312,19 +1409,14 @@ pub fn test_sendmsg_empty_cmsgs() {
}
}
-#[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 @@ fn test_scm_credentials() {
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 @@ fn test_scm_credentials() {
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 @@ fn test_scm_credentials() {
/// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single
/// `sendmsg` call.
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[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 @@ fn test_scm_credentials_and_rights() {
/// Ensure that passing a an oversized control message buffer to recvmsg
/// still works.
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[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 @@ fn test_too_large_cmsgspace() {
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 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
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 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
.unwrap(),
5
);
- close(r).unwrap();
}
{
@@ -1510,18 +1601,19 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
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 @@ pub fn test_named_unixdomain() {
.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 @@ pub fn test_named_unixdomain() {
)
.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 @@ pub fn test_named_unixdomain() {
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 @@ pub fn test_unnamed_unixdomain() {
}
// 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 @@ pub fn test_unnamed_unixdomain_autobind() {
}
// 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 @@ pub fn test_syscontrol() {
// 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 @@ fn loopback_address(
})
}
-#[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 @@ pub fn test_recv_ipv4pktinfo() {
}
}
-#[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 @@ pub fn test_recvif() {
}
}
-#[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 @@ pub fn test_recvif_ipv4() {
}
}
-#[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 @@ pub fn test_recvif_ipv6() {
}
}
-#[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 @@ pub fn test_recv_ipv6pktinfo() {
}
}
-#[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 @@ pub fn test_vsock() {
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 @@ fn test_recvmmsg_timestampns() {
// 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 @@ fn test_recvmmsg_timestampns() {
// 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 @@ fn test_recvmsg_rxq_ovfl() {
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 @@ pub fn test_txtime() {
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 @@ pub fn test_local_peercred_seqpacket() {
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 @@ pub fn test_local_peercred_stream() {
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,15 +103,42 @@ fn test_so_buf() {
assert!(actual >= bufsize);
}
+#[cfg(target_os = "freebsd")]
+#[test]
+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:4004").unwrap();
+ let 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();
+ 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, listen, SockaddrIn};
+ 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:4001").unwrap();
- let sock_addr = SockaddrIn::from(std_sa);
+ 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,
@@ -126,13 +148,14 @@ fn test_so_tcp_maxseg() {
)
.unwrap();
bind(rsock.as_raw_fd(), &sock_addr).unwrap();
- listen(&rsock, 10).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 @@ fn test_so_tcp_maxseg() {
.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 @@ fn test_so_type() {
/// 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 @@ fn test_tcp_congestion() {
}
#[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 @@ fn test_so_tcp_keepalive() {
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 @@ fn test_so_tcp_keepalive() {
}
#[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 @@ fn test_get_mtu() {
}
#[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 @@ fn test_ttl_opts() {
}
#[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 @@ fn test_dontfrag_opts() {
}
#[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 @@ fn test_ipv6_tclass() {
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 tempfile::tempfile;
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
index ffd1468..ffd1468 100644
--- a/test/test_timer.rs
+++ b/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::distributions::Alphanumeric;
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 @@ fn test_writev() {
// 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 @@ fn test_readv() {
// 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 @@ fn test_readv() {
assert_eq!(read_buf.len(), to_write.len());
// Check equality of written and read data
assert_eq!(&read_buf, &to_write);
- close(writer).expect("couldn't close writer");
}
#[test]
@@ -150,7 +140,11 @@ fn test_pread() {
}
#[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 @@ fn test_pwritev() {
}
#[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 @@ fn test_process_vm_readv() {
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 @@ fn test_process_vm_readv() {
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 @@ fn test_process_vm_readv() {
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 @@ fn test_wait_signal() {
//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 @@ fn test_wait_exit() {
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 @@ fn test_waitid_pid() {
}
}
-#[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 common;
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 @@ mod test_poll;
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 @@ use tempfile::tempdir;
#[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 @@ fn test_openat() {
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 @@ fn test_readlink() {
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 @@ fn test_readlink() {
/// 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 @@ fn test_copy_file_range() {
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 @@ mod linux_android {
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 @@ mod linux_android {
let res = splice(
tmp.as_raw_fd(),
Some(&mut offset),
- wr,
+ wr.as_raw_fd(),
None,
2,
SpliceFFlags::empty(),
@@ -309,12 +308,9 @@ mod linux_android {
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 @@ mod linux_android {
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 @@ mod linux_android {
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 @@ mod linux_android {
}
#[cfg(any(
- target_os = "linux",
- target_os = "android",
+ linux_android,
target_os = "emscripten",
target_os = "fuchsia",
target_os = "wasi",
@@ -494,7 +484,7 @@ mod test_posix_fadvise {
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 @@ mod test_posix_fadvise {
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 @@ mod test_posix_fadvise {
}
#[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 @@ mod test_posix_fallocate {
#[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;
-
-// 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.
-
-#[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 libc::{EACCES, EROFS};
-
- 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
+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;
+
+use libc::{EACCES, EROFS};
+
+use nix::mount::{mount, umount, MsFlags};
+use nix::sys::stat::{self, Mode};
+
+use crate::*;
+
+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}"));
+#[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"))
+ );
- let test_path = tempdir.path().join("test");
+ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
+}
- // 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}"));
+#[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()
+ );
- // 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}"));
- }
+ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
+}
- pub fn test_mount_rdonly_disallows_write() {
- let tempdir = tempfile::tempdir().unwrap();
+#[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}")),
+ );
- mount(
- NONE,
- tempdir.path(),
- Some(b"tmpfs".as_ref()),
- MsFlags::MS_RDONLY,
- NONE,
- )
- .unwrap_or_else(|e| panic!("mount 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()
+ );
- // 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}"));
+}
- 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";
- pub fn test_mount_noexec_disallows_exec() {
- let tempdir = tempfile::tempdir().unwrap();
+ {
+ let mount_point = tempfile::tempdir().unwrap();
mount(
+ Some(tempdir.path()),
+ mount_point.path(),
NONE,
- tempdir.path(),
- Some(b"tmpfs".as_ref()),
- MsFlags::MS_NOEXEC,
+ MsFlags::MS_BIND,
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)
+ .open(mount_point.path().join(file_name))
.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}"));
+ umount(mount_point.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);
- }
+ // Verify the file written in the mount shows up in source directory, even
+ // after unmounting.
- 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}"));
- }
+ 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);
}
-
-// 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
- );
-}
-
-#[cfg(not(target_os = "linux"))]
-fn main() {}
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 @@ fn test_mq_getattr() {
// 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 @@ fn test_mq_setattr() {
// 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 @@ macro_rules! loop_while_eintr {
#[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 @@ fn test_ppoll() {
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 @@ fn test_ppoll() {
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 @@ use nix::unistd::{pause, write};
/// 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 @@ fn test_ptsname_equivalence() {
/// 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 @@ fn test_ptsname_copy() {
/// 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 @@ fn test_ptsname_r_copy() {
/// 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 @@ fn open_ptty_pair() -> (PtyMaster, File) {
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 @@ fn test_openpty() {
// 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 @@ fn test_openpty() {
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 @@ fn test_openpty_with_termios() {
// 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 @@ fn test_openpty_with_termios() {
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 @@ fn test_forkpty() {
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_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 @@ fn test_sendfile_linux() {
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 @@ fn test_sendfile64_linux() {
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 @@ fn test_sendfile_dragonfly() {
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 @@ fn test_sendfile_darwin() {
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::errno::Errno;
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 @@ fn test_fstatat() {
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 @@ fn test_utimes() {
#[test]
#[cfg(any(
target_os = "linux",
- target_os = "ios",
- target_os = "macos",
+ apple_targets,
target_os = "freebsd",
target_os = "netbsd"
))]
@@ -323,7 +321,7 @@ fn test_mkdirat_success_path() {
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 @@ fn test_mkdirat_success_mode() {
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 @@ fn test_mkdirat_fail() {
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 @@ fn test_mknod() {
#[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 @@ fn test_mknodat() {
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 @@ fn test_mknodat() {
)
.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 @@ fn test_mknodat() {
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 @@ pub fn test_clock_gettime() {
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 @@ pub fn test_clock_id_now() {
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 @@ pub fn test_clock_id_pid_cpu_clock_id() {
.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 @@ fn test_fork_and_waitpid() {
}
#[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 @@ fn test_mkfifo_directory() {
#[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 @@ fn test_mkfifoat_none() {
#[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 @@ fn test_mkfifoat() {
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 @@ fn test_mkfifoat_directory_none() {
#[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 @@ fn test_mkfifoat_directory() {
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 @@ fn test_getsid() {
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 @@ mod linux_android {
#[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 @@ fn test_setgroups() {
#[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 @@ macro_rules! execve_test_factory (
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 @@ macro_rules! execve_test_factory (
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 @@ cfg_if! {
if #[cfg(target_os = "android")] {
execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap().as_c_str());
execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd());
- } else if #[cfg(any(target_os = "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 @@ fn test_fchown() {
#[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 @@ fn test_fchownat() {
let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
- fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink)
- .unwrap();
+ fchownat(Some(dirfd), "file", uid, gid, 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 @@ fn test_lseek() {
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 @@ fn test_lseek64() {
}
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 @@ fn test_acct() {
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 @@ fn test_fpathconf_limited() {
);
}
+#[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 @@ fn test_pathconf_limited() {
);
}
+#[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 @@ fn test_sysconf_unsupported() {
assert!(open_max.expect("sysconf failed").is_none())
}
-#[cfg(any(
- target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "linux",
- target_os = "openbsd"
-))]
+#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))]
#[test]
fn test_getresuid() {
let resuids = getresuid().unwrap();
@@ -693,13 +715,7 @@ fn test_getresuid() {
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_getresgid() {
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 @@ fn test_pipe() {
// pipe2(2) is the same as pipe(2), except it allows setting some flags. Check
// that we can set a flag.
#[cfg(any(
- target_os = "android",
- target_os = "dragonfly",
+ 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 @@ fn test_symlinkat() {
#[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 @@ fn test_linkat_file() {
oldfilename,
Some(dirfd),
newfilename,
- LinkatFlags::SymlinkFollow,
+ AtFlags::AT_SYMLINK_FOLLOW,
)
.unwrap();
assert!(newfilepath.exists());
@@ -911,6 +929,8 @@ fn test_linkat_file() {
#[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 @@ fn test_linkat_olddirfd_none() {
oldfilename,
Some(dirfd),
newfilename,
- LinkatFlags::SymlinkFollow,
+ AtFlags::AT_SYMLINK_FOLLOW,
)
.unwrap();
assert!(newfilepath.exists());
@@ -948,6 +968,8 @@ fn test_linkat_olddirfd_none() {
#[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 @@ fn test_linkat_newdirfd_none() {
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 @@ fn test_linkat_no_follow_symlink() {
symoldfilename,
Some(dirfd),
newfilename,
- LinkatFlags::NoSymlinkFollow,
+ AtFlags::empty(),
)
.unwrap();
@@ -1033,6 +1052,8 @@ fn test_linkat_no_follow_symlink() {
#[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 @@ fn test_linkat_follow_symlink() {
symoldfilename,
Some(dirfd),
newfilename,
- LinkatFlags::SymlinkFollow,
+ AtFlags::AT_SYMLINK_FOLLOW,
)
.unwrap();
@@ -1070,8 +1091,8 @@ fn test_linkat_follow_symlink() {
// 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 @@ fn test_access_file_exists() {
.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 @@ fn test_user_into_passwd() {
}
/// 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 @@ fn test_ttyname() {
grantpt(&fd).expect("grantpt failed");
unlockpt(&fd).expect("unlockpt failed");
let sname = unsafe { ptsname(&fd) }.expect("ptsname failed");
- let fds = open(Path::new(&sname), OFlag::O_RDWR, stat::Mode::empty())
+ 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 @@ fn test_ttyname() {
#[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 @@ fn test_getpeereid() {
}
#[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 @@ fn test_faccessat_file_exists() {
}
#[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 @@ fn test_eaccess_not_existing() {
}
#[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 @@ fn test_eaccess_file_exists() {
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");
+}