aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-02 23:54:01 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-02 23:54:01 +0000
commit211d89cd314357a8d6c0fa8d3cfdabe53b32ba56 (patch)
tree433bf4bf96250b2f15312c2150f82d3ea71052dd
parent78446f707b956665a891668df4e3f9be6f99a828 (diff)
parent02994e4018b5e81efd3911350f1db83d79d49588 (diff)
downloadnix-simpleperf-release.tar.gz
Snap for 11400057 from 02994e4018b5e81efd3911350f1db83d79d49588 to simpleperf-releasesimpleperf-release
Change-Id: Ia1b7b427f78e946b01095024814d443dfa7603ec
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp28
-rw-r--r--CHANGELOG.md115
-rw-r--r--Cargo.toml66
-rw-r--r--Cargo.toml.orig31
-rw-r--r--METADATA10
-rw-r--r--README.md103
-rw-r--r--cargo2android.json10
-rw-r--r--cargo_embargo.json21
-rw-r--r--patches/unistd.diff22
-rw-r--r--src/dir.rs10
-rw-r--r--src/errno.rs247
-rw-r--r--src/fcntl.rs331
-rw-r--r--src/features.rs16
-rw-r--r--src/kmod.rs8
-rw-r--r--src/lib.rs47
-rw-r--r--src/macros.rs5
-rw-r--r--src/mount/bsd.rs6
-rw-r--r--src/mount/linux.rs54
-rw-r--r--src/mqueue.rs110
-rw-r--r--src/net/if_.rs2
-rw-r--r--src/poll.rs52
-rw-r--r--src/pty.rs70
-rw-r--r--src/sched.rs44
-rw-r--r--src/sys/aio.rs18
-rw-r--r--src/sys/epoll.rs128
-rw-r--r--src/sys/event.rs213
-rw-r--r--src/sys/eventfd.rs6
-rw-r--r--src/sys/inotify.rs32
-rw-r--r--src/sys/ioctl/linux.rs78
-rw-r--r--src/sys/ioctl/mod.rs6
-rw-r--r--src/sys/memfd.rs7
-rw-r--r--src/sys/mman.rs36
-rw-r--r--src/sys/mod.rs9
-rw-r--r--src/sys/personality.rs5
-rw-r--r--src/sys/prctl.rs208
-rw-r--r--src/sys/ptrace/linux.rs18
-rw-r--r--src/sys/ptrace/mod.rs2
-rw-r--r--src/sys/quota.rs3
-rw-r--r--src/sys/resource.rs4
-rw-r--r--src/sys/select.rs313
-rw-r--r--src/sys/sendfile.rs62
-rw-r--r--src/sys/signal.rs333
-rw-r--r--src/sys/signalfd.rs38
-rw-r--r--src/sys/socket/addr.rs874
-rw-r--r--src/sys/socket/mod.rs364
-rw-r--r--src/sys/socket/sockopt.rs120
-rw-r--r--src/sys/stat.rs4
-rw-r--r--src/sys/statfs.rs6
-rw-r--r--src/sys/statvfs.rs7
-rw-r--r--src/sys/termios.rs92
-rw-r--r--src/sys/time.rs35
-rw-r--r--src/sys/timerfd.rs54
-rw-r--r--src/sys/uio.rs106
-rw-r--r--src/sys/wait.rs15
-rw-r--r--src/unistd.rs1578
-rw-r--r--test/sys/test_aio.rs10
-rw-r--r--test/sys/test_epoll.rs2
-rw-r--r--test/sys/test_mman.rs14
-rw-r--r--test/sys/test_prctl.rs125
-rw-r--r--test/sys/test_select.rs31
-rw-r--r--test/sys/test_signal.rs12
-rw-r--r--test/sys/test_socket.rs713
-rw-r--r--test/sys/test_sockopt.rs135
-rw-r--r--test/sys/test_termios.rs59
-rw-r--r--test/sys/test_uio.rs29
-rw-r--r--test/test.rs44
-rw-r--r--test/test_fcntl.rs95
-rw-r--r--test/test_mount.rs42
-rw-r--r--test/test_mq.rs51
-rw-r--r--test/test_poll.rs22
-rw-r--r--test/test_pty.rs77
-rw-r--r--test/test_ptymaster_drop.rs20
-rw-r--r--test/test_sendfile.rs39
-rw-r--r--test/test_unistd.rs40
75 files changed, 4685 insertions, 3059 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index b9cb2ab..02451fb 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "1e3f062fd842b7ce130ea6c792a8eab7f78f82e3"
+ "sha1": "996db47d542ae20f09eb344b9fcb88c40ae38e3d"
},
"path_in_vcs": ""
} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 0e94841..ddbca61 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,4 @@
-// This file is generated by cargo2android.py --config cargo2android.json.
+// This file is generated by cargo_embargo.
// Do not modify this file as changes will be overridden on upgrade.
package {
@@ -26,53 +26,33 @@ rust_library {
host_supported: true,
crate_name: "nix",
cargo_env_compat: true,
- cargo_pkg_version: "0.26.2",
+ cargo_pkg_version: "0.27.1",
srcs: ["src/lib.rs"],
- edition: "2018",
+ edition: "2021",
features: [
- "acct",
- "aio",
- "default",
- "dir",
- "env",
"event",
"feature",
"fs",
- "hostname",
- "inotify",
"ioctl",
- "kmod",
"memoffset",
"mman",
"mount",
- "mqueue",
"net",
- "personality",
- "pin-utils",
"poll",
"process",
- "pthread",
- "ptrace",
- "quota",
- "reboot",
- "resource",
"sched",
"signal",
"socket",
"term",
"time",
- "ucontext",
"uio",
"user",
- "zerocopy",
],
rustlibs: [
- "libbitflags-1.3.2",
+ "libbitflags",
"libcfg_if",
"liblibc",
"libmemoffset",
- "libpin_utils",
- "libstatic_assertions",
],
apex_available: [
"//apex_available:platform",
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 283cb86..3a171af 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,9 +3,120 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/).
+## [0.27.1] - 2023-08-28
+
+### Fixed
+
+- Fixed generating the documentation on docs.rs.
+ ([#2111](https://github.com/nix-rust/nix/pull/2111))
+
+## [0.27.0] - 2023-08-28
+### Added
+- Added `AT_EACCESS` to `AtFlags` on all platforms but android
+ ([#1995](https://github.com/nix-rust/nix/pull/1995))
+- Add `PF_ROUTE` to `SockType` on macOS, iOS, all of the BSDs, Fuchsia, Haiku, Illumos.
+ ([#1867](https://github.com/nix-rust/nix/pull/1867))
+- Added `nix::ucontext` module on `aarch64-unknown-linux-gnu`.
+ (#[1662](https://github.com/nix-rust/nix/pull/1662))
+- Added `CanRaw` to `SockProtocol` and `CanBcm` as a separate `SocProtocol` constant.
+ ([#1912](https://github.com/nix-rust/nix/pull/1912))
+- Added `Generic` and `NFLOG` to `SockProtocol`.
+ ([#2092](https://github.com/nix-rust/nix/pull/2092))
+- Added `mq_timedreceive` to `::nix::mqueue`.
+ ([#1966])(https://github.com/nix-rust/nix/pull/1966)
+- Added `LocalPeerPid` to `nix::sys::socket::sockopt` for macOS. ([#1967](https://github.com/nix-rust/nix/pull/1967))
+- Added `TFD_TIMER_CANCEL_ON_SET` to `::nix::sys::time::TimerSetTimeFlags` on Linux and Android.
+ ([#2040](https://github.com/nix-rust/nix/pull/2040))
+- Added `SOF_TIMESTAMPING_OPT_ID` and `SOF_TIMESTAMPING_OPT_TSONLY` to `nix::sys::socket::TimestampingFlag`.
+ ([#2048](https://github.com/nix-rust/nix/pull/2048))
+- Enabled socket timestamping options on Android. ([#2077](https://github.com/nix-rust/nix/pull/2077))
+- Added vsock support for macOS ([#2056](https://github.com/nix-rust/nix/pull/2056))
+- Added `SO_SETFIB` and `SO_USER_COOKIE` to `nix::sys::socket::sockopt` for FreeBSD.
+ ([#2085](https://github.com/nix-rust/nix/pull/2085))
+- Added `SO_RTABLE` for OpenBSD and `SO_ACCEPTFILTER` for FreeBSD/NetBSD to `nix::sys::socket::sockopt`.
+ ([#2085](https://github.com/nix-rust/nix/pull/2085))
+- Added `MSG_WAITFORONE` to `MsgFlags` on Android, Fuchsia, Linux, NetBSD,
+ FreeBSD, OpenBSD, and Solaris.
+ ([#2014](https://github.com/nix-rust/nix/pull/2014))
+- Added `SO_TS_CLOCK` for FreeBSD to `nix::sys::socket::sockopt`.
+ ([#2093](https://github.com/nix-rust/nix/pull/2093))
+- Added support for prctl in Linux.
+ (#[1550](https://github.com/nix-rust/nix/pull/1550))
+- `nix::socket` and `nix::select` are now available on Redox.
+ ([#2012](https://github.com/nix-rust/nix/pull/2012))
+- Implemented AsFd, AsRawFd, FromRawFd, and IntoRawFd for `mqueue::MqdT`.
+ ([#2097](https://github.com/nix-rust/nix/pull/2097))
+- Add the ability to set `kevent_flags` on `SigEvent`.
+ ([#1731](https://github.com/nix-rust/nix/pull/1731))
+
+### Changed
+
+- All Cargo features have been removed from the default set. Users will need to
+ specify which features they depend on in their Cargo.toml.
+ ([#2091](https://github.com/nix-rust/nix/pull/2091))
+- Implemented I/O safety for many, but not all, of Nix's APIs. Many public
+ functions argument and return types have changed:
+ | Original Type | New Type |
+ | ------------- | --------------------- |
+ | AsRawFd | AsFd |
+ | RawFd | BorrowedFd or OwnedFd |
+
+ (#[1906](https://github.com/nix-rust/nix/pull/1906))
+- Use I/O safety with `copy_file_range`, and expose it on FreeBSD.
+ (#[1906](https://github.com/nix-rust/nix/pull/1906))
+- The MSRV is now 1.65
+ ([#1862](https://github.com/nix-rust/nix/pull/1862))
+ ([#2104](https://github.com/nix-rust/nix/pull/2104))
+- The epoll interface now uses a type.
+ ([#1882](https://github.com/nix-rust/nix/pull/1882))
+- With I/O-safe type applied in `pty::OpenptyResult` and `pty::ForkptyResult`,
+ users no longer need to manually close the file descriptors in these types.
+ ([#1921](https://github.com/nix-rust/nix/pull/1921))
+- Refactored `name` parameter of `mq_open` and `mq_unlink` to be generic over
+ `NixPath`.
+ ([#2102](https://github.com/nix-rust/nix/pull/2102)).
+- Made `clone` unsafe, like `fork`.
+ ([#1993](https://github.com/nix-rust/nix/pull/1993))
+
+### Removed
+
+- `sys::event::{kevent, kevent_ts}` are deprecated in favor of
+ `sys::kevent::Kqueue::kevent`, and `sys::event::kqueue` is deprecated in
+ favor of `sys::kevent::Kqueue::new`.
+ ([#1943](https://github.com/nix-rust/nix/pull/1943))
+- Removed deprecated IoVec API.
+ ([#1855](https://github.com/nix-rust/nix/pull/1855))
+- Removed deprecated net APIs.
+ ([#1861](https://github.com/nix-rust/nix/pull/1861))
+- `nix::sys::signalfd::signalfd` is deprecated. Use
+ `nix::sys::signalfd::SignalFd` instead.
+ ([#1938](https://github.com/nix-rust/nix/pull/1938))
+- Removed `SigEvent` support on Fuchsia, where it was unsound.
+ ([#2079](https://github.com/nix-rust/nix/pull/2079))
+- Removed `flock` from `::nix::fcntl` on Solaris.
+ ([#2082](https://github.com/nix-rust/nix/pull/2082))
+
+## [0.26.3] - 2023-08-27
+
+### Fixed
+- 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))
+- Fix potentially invalid conversions in
+ `SockaddrIn::from<std::net::SocketAddrV4>`,
+ `SockaddrIn6::from<std::net::SockaddrV6>`, `IpMembershipRequest::new`, and
+ `Ipv6MembershipRequest::new` with future Rust versions.
+ ([#2061](https://github.com/nix-rust/nix/pull/2061))
+- Fixed an incorrect lifetime returned from `recvmsg`.
+ ([#2095](https://github.com/nix-rust/nix/pull/2095))
+
## [0.26.2] - 2023-01-18
+
### Fixed
-- Fix `SockaddrIn6` bug that was swapping flowinfo and scope_id byte ordering.
+
+- Fix `SockaddrIn6` bug that was swapping `flowinfo` and `scope_id` byte
+ ordering.
([#1964](https://github.com/nix-rust/nix/pull/1964))
## [0.26.1] - 2022-11-29
@@ -209,7 +320,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
(#[1563](https://github.com/nix-rust/nix/pull/1563))
- Added `process_vm_readv` and `process_vm_writev` on Android.
(#[1557](https://github.com/nix-rust/nix/pull/1557))
-- Added `nix::uncontext` module on s390x.
+- Added `nix::ucontext` module on s390x.
(#[1662](https://github.com/nix-rust/nix/pull/1662))
- Implemented `Extend`, `FromIterator`, and `IntoIterator` for `SigSet` and
added `SigSet::iter` and `SigSetIter`.
diff --git a/Cargo.toml b/Cargo.toml
index 0afc445..bb04ab2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,10 +10,10 @@
# See Cargo.toml.orig for the original contents.
[package]
-edition = "2018"
-rust-version = "1.56"
+edition = "2021"
+rust-version = "1.65"
name = "nix"
-version = "0.26.2"
+version = "0.27.1"
authors = ["The nix-rust Project Developers"]
include = [
"src/**/*",
@@ -29,6 +29,7 @@ license = "MIT"
repository = "https://github.com/nix-rust/nix"
[package.metadata.docs.rs]
+all-features = true
rustdoc-args = [
"--cfg",
"docsrs",
@@ -65,32 +66,30 @@ path = "test/test_mount.rs"
harness = false
[[test]]
-name = "test-ptymaster-drop"
-path = "test/test_ptymaster_drop.rs"
+name = "test-prctl"
+path = "test/sys/test_prctl.rs"
[dependencies.bitflags]
-version = "1.1"
+version = "2.3.1"
[dependencies.cfg-if]
version = "1.0"
[dependencies.libc]
-version = "0.2.137"
+version = "0.2.147"
features = ["extra_traits"]
+[dependencies.memoffset]
+version = "0.9"
+optional = true
+
[dependencies.pin-utils]
version = "0.1.0"
optional = true
-[dependencies.static_assertions]
-version = "1"
-
[dev-dependencies.assert-impl]
version = "0.1"
-[dev-dependencies.lazy_static]
-version = "1.4"
-
[dev-dependencies.parking_lot]
version = "0.12"
@@ -101,45 +100,12 @@ version = "0.8"
version = "1.0.7"
[dev-dependencies.tempfile]
-version = "3.3.0"
+version = "3.7.1"
[features]
acct = []
aio = ["pin-utils"]
-default = [
- "acct",
- "aio",
- "dir",
- "env",
- "event",
- "feature",
- "fs",
- "hostname",
- "inotify",
- "ioctl",
- "kmod",
- "mman",
- "mount",
- "mqueue",
- "net",
- "personality",
- "poll",
- "process",
- "pthread",
- "ptrace",
- "quota",
- "reboot",
- "resource",
- "sched",
- "signal",
- "socket",
- "term",
- "time",
- "ucontext",
- "uio",
- "user",
- "zerocopy",
-]
+default = []
dir = ["fs"]
env = []
event = []
@@ -177,9 +143,5 @@ zerocopy = [
[target."cfg(any(target_os = \"android\", target_os = \"linux\"))".dev-dependencies.caps]
version = "0.5.3"
-[target."cfg(not(target_os = \"redox\"))".dependencies.memoffset]
-version = "0.7"
-optional = true
-
[target."cfg(target_os = \"freebsd\")".dev-dependencies.sysctl]
version = "0.4"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 8b1d873..5a78060 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,9 +1,9 @@
[package]
name = "nix"
description = "Rust friendly bindings to *nix APIs"
-edition = "2018"
-version = "0.26.2"
-rust-version = "1.56"
+edition = "2021"
+version = "0.27.1"
+rust-version = "1.65"
authors = ["The nix-rust Project Developers"]
repository = "https://github.com/nix-rust/nix"
license = "MIT"
@@ -11,6 +11,7 @@ categories = ["os::unix-apis"]
include = ["src/**/*", "test/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
[package.metadata.docs.rs]
+all-features = true
rustdoc-args = ["--cfg", "docsrs"]
targets = [
"x86_64-unknown-linux-gnu",
@@ -27,23 +28,14 @@ targets = [
]
[dependencies]
-libc = { version = "0.2.137", features = [ "extra_traits" ] }
-bitflags = "1.1"
+libc = { version = "0.2.147", features = ["extra_traits"] }
+bitflags = "2.3.1"
cfg-if = "1.0"
pin-utils = { version = "0.1.0", optional = true }
-static_assertions = "1"
-
-[target.'cfg(not(target_os = "redox"))'.dependencies]
-memoffset = { version = "0.7", optional = true }
+memoffset = { version = "0.9", optional = true }
[features]
-default = [
- "acct", "aio", "dir", "env", "event", "feature", "fs",
- "hostname", "inotify", "ioctl", "kmod", "mman", "mount", "mqueue",
- "net", "personality", "poll", "process", "pthread", "ptrace", "quota",
- "reboot", "resource", "sched", "signal", "socket", "term", "time",
- "ucontext", "uio", "user", "zerocopy",
-]
+default = []
acct = []
aio = ["pin-utils"]
@@ -80,10 +72,9 @@ zerocopy = ["fs", "uio"]
[dev-dependencies]
assert-impl = "0.1"
-lazy_static = "1.4"
parking_lot = "0.12"
rand = "0.8"
-tempfile = "3.3.0"
+tempfile = "3.7.1"
semver = "1.0.7"
[target.'cfg(any(target_os = "android", target_os = "linux"))'.dev-dependencies]
@@ -110,5 +101,5 @@ path = "test/test_mount.rs"
harness = false
[[test]]
-name = "test-ptymaster-drop"
-path = "test/test_ptymaster_drop.rs"
+name = "test-prctl"
+path = "test/sys/test_prctl.rs"
diff --git a/METADATA b/METADATA
index b1b992d..54b6c34 100644
--- a/METADATA
+++ b/METADATA
@@ -1,6 +1,6 @@
# This project was upgraded with external_updater.
# Usage: tools/external_updater/updater.sh update rust/crates/nix
-# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+# 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"
@@ -11,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/nix/nix-0.26.2.crate"
+ value: "https://static.crates.io/crates/nix/nix-0.27.1.crate"
}
- version: "0.26.2"
+ version: "0.27.1"
license_type: NOTICE
last_upgrade_date {
year: 2023
- month: 2
- day: 16
+ month: 11
+ day: 14
}
}
diff --git a/README.md b/README.md
index 2c42b90..e172de2 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ pub fn gethostname() -> Result<OsString>;
## Supported Platforms
-nix target support consists of two tiers. While nix attempts to support all
+nix target support consists of three tiers. While nix attempts to support all
platforms supported by [libc](https://github.com/rust-lang/libc), only some
platforms are actively supported due to either technical or manpower
limitations. Support for platforms is split into three tiers:
@@ -41,55 +41,70 @@ limitations. Support for platforms is split into three tiers:
blocks the inclusion of new code. Tests may be run, but failures
in tests don't block the inclusion of new code.
* Tier 3 - Builds for this target are run in CI. Failures during the build
- *do not* block the inclusion of new code. Testing may be run, but
- failures in tests don't block the inclusion of new code.
+ *do not* necessarily block the inclusion of new code. That is, at
+ our discretion a Tier 3 target may be dropped at any time, if it
+ would otherwise block development.
+
+Platforms not listed are supported on a best-effort basis, relying on our users
+to report any problems.
The following targets are supported by `nix`:
-Tier 1:
- * aarch64-apple-darwin
- * aarch64-unknown-linux-gnu
- * arm-unknown-linux-gnueabi
- * armv7-unknown-linux-gnueabihf
- * i686-unknown-freebsd
- * i686-unknown-linux-gnu
- * i686-unknown-linux-musl
- * mips-unknown-linux-gnu
- * mips64-unknown-linux-gnuabi64
- * mips64el-unknown-linux-gnuabi64
- * mipsel-unknown-linux-gnu
- * powerpc64le-unknown-linux-gnu
- * x86_64-unknown-freebsd
- * x86_64-unknown-linux-gnu
- * x86_64-unknown-linux-musl
-
-Tier 2:
- * aarch64-apple-ios
- * aarch64-linux-android
- * arm-linux-androideabi
- * arm-unknown-linux-musleabi
- * armv7-linux-androideabi
- * i686-linux-android
- * powerpc-unknown-linux-gnu
- * s390x-unknown-linux-gnu
- * x86_64-apple-ios
- * x86_64-linux-android
- * x86_64-apple-darwin
- * x86_64-unknown-illumos
- * x86_64-unknown-netbsd
-
-Tier 3:
- * armv7-unknown-linux-uclibceabihf
- * x86_64-fuchsia
- * x86_64-unknown-dragonfly
- * x86_64-unknown-haiku
- * x86_64-unknown-linux-gnux32
- * x86_64-unknown-openbsd
- * x86_64-unknown-redox
+<table>
+ <tr>
+ <th>Tier 1</th>
+ <th>Tier 2</th>
+ <th>Tier 3</th>
+ </tr>
+ <tr>
+ <td>
+ <ul>
+ <li>aarch64-apple-darwin</li>
+ <li>aarch64-unknown-linux-gnu</li>
+ <li>arm-unknown-linux-gnueabi</li>
+ <li>armv7-unknown-linux-gnueabihf</li>
+ <li>i686-unknown-freebsd</li>
+ <li>i686-unknown-linux-gnu</li>
+ <li>i686-unknown-linux-musl</li>
+ <li>mips-unknown-linux-gnu</li>
+ <li>mips64-unknown-linux-gnuabi64</li>
+ <li>mips64el-unknown-linux-gnuabi64</li>
+ <li>mipsel-unknown-linux-gnu</li>
+ <li>powerpc64le-unknown-linux-gnu</li>
+ <li>x86_64-unknown-freebsd</li>
+ <li>x86_64-unknown-linux-gnu</li>
+ <li>x86_64-unknown-linux-musl</li>
+ </ul>
+ </td>
+ <td>
+ <ul>
+ <li>aarch64-apple-ios</li>
+ <li>aarch64-linux-android</li>
+ <li>arm-linux-androideabi</li>
+ <li>arm-unknown-linux-musleabi</li>
+ <li>armv7-linux-androideabi</li>
+ <li>i686-linux-android</li>
+ <li>s390x-unknown-linux-gnu</li>
+ <li>x86_64-linux-android</li>
+ <li>x86_64-unknown-illumos</li>
+ <li>x86_64-unknown-netbsd</li>
+ </td>
+ <td>
+ <li>armv7-unknown-linux-uclibceabihf</li>
+ <li>powerpc64-unknown-linux-gnu</li>
+ <li>x86_64-fuchsia</li>
+ <li>x86_64-unknown-dragonfly</li>
+ <li>x86_64-unknown-haiku</li>
+ <li>x86_64-unknown-linux-gnux32</li>
+ <li>x86_64-unknown-openbsd</li>
+ <li>x86_64-unknown-redox</li>
+ </td>
+ </tr>
+</table>
## Minimum Supported Rust Version (MSRV)
-nix is supported on Rust 1.56.1 and higher. Its MSRV will not be
+nix is supported on Rust 1.65 and higher. Its MSRV will not be
changed in the future without bumping the major or minor version.
## Contributing
diff --git a/cargo2android.json b/cargo2android.json
deleted file mode 100644
index 1bd5b8b..0000000
--- a/cargo2android.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "dependencies": true,
- "device": true,
- "min-sdk-version": "29",
- "run": true,
- "vendor-available": true,
- "dep-suffixes": {
- "bitflags": "-1.3.2"
- }
-}
diff --git a/cargo_embargo.json b/cargo_embargo.json
new file mode 100644
index 0000000..6df39c1
--- /dev/null
+++ b/cargo_embargo.json
@@ -0,0 +1,21 @@
+{
+ "features": [
+ "event",
+ "feature",
+ "fs",
+ "ioctl",
+ "mount",
+ "mman",
+ "net",
+ "poll",
+ "sched",
+ "signal",
+ "socket",
+ "term",
+ "time",
+ "uio",
+ "user"
+ ],
+ "min_sdk_version": "29",
+ "run_cargo": false
+}
diff --git a/patches/unistd.diff b/patches/unistd.diff
deleted file mode 100644
index 4815309..0000000
--- a/patches/unistd.diff
+++ /dev/null
@@ -1,22 +0,0 @@
-diff --git a/src/unistd.rs b/src/unistd.rs
-index 42e1456..8cdb54b 100644
---- a/src/unistd.rs
-+++ b/src/unistd.rs
-@@ -2984,12 +2984,12 @@ impl From<&libc::passwd> for User {
- fn from(pw: &libc::passwd) -> User {
- unsafe {
- User {
-- name: CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned(),
-- passwd: CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes()).unwrap(),
-+ name: if pw.pw_name.is_null() { Default::default() } else { CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned() },
-+ passwd: if pw.pw_passwd.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes()).unwrap() },
- #[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
-- gecos: CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes()).unwrap(),
-- dir: PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_dir).to_bytes())),
-- shell: PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_shell).to_bytes())),
-+ gecos: if pw.pw_gecos.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes()).unwrap() },
-+ dir: if pw.pw_dir.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_dir).to_bytes())) },
-+ shell: if pw.pw_shell.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_shell).to_bytes())) },
- uid: Uid::from_raw(pw.pw_uid),
- gid: Gid::from_raw(pw.pw_gid),
- #[cfg(not(any(target_os = "android",
diff --git a/src/dir.rs b/src/dir.rs
index 5ce5036..96a5843 100644
--- a/src/dir.rs
+++ b/src/dir.rs
@@ -101,6 +101,9 @@ impl Drop for Dir {
}
}
+// The pass by mut is technically needless only because the inner NonNull is
+// Copy. But philosophically we're mutating the Dir, so we pass by mut.
+#[allow(clippy::needless_pass_by_ref_mut)]
fn next(dir: &mut Dir) -> Option<Result<Entry>> {
unsafe {
// Note: POSIX specifies that portable applications should dynamically allocate a
@@ -221,7 +224,8 @@ impl Entry {
#[allow(clippy::unnecessary_cast)]
pub fn ino(&self) -> u64 {
cfg_if! {
- if #[cfg(any(target_os = "android",
+ if #[cfg(any(target_os = "aix",
+ target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "haiku",
@@ -240,7 +244,7 @@ impl Entry {
/// Returns the bare file name of this directory entry without any other leading path component.
pub fn file_name(&self) -> &ffi::CStr {
- unsafe { ::std::ffi::CStr::from_ptr(self.0.d_name.as_ptr()) }
+ unsafe { ffi::CStr::from_ptr(self.0.d_name.as_ptr()) }
}
/// Returns the type of this directory entry, if known.
@@ -250,6 +254,7 @@ impl Entry {
/// `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"
@@ -267,6 +272,7 @@ impl Entry {
// illumos, Solaris, and Haiku systems do not have the d_type member at all:
#[cfg(any(
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "haiku"
diff --git a/src/errno.rs b/src/errno.rs
index d8ad28d..50b3524 100644
--- a/src/errno.rs
+++ b/src/errno.rs
@@ -34,6 +34,10 @@ cfg_if! {
unsafe fn errno_location() -> *mut c_int {
libc::_errnop()
}
+ } else if #[cfg(any(target_os = "aix"))] {
+ unsafe fn errno_location() -> *mut c_int {
+ libc::_Errno()
+ }
}
}
@@ -223,6 +227,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia"
@@ -232,6 +237,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia"
@@ -241,6 +247,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia"
@@ -250,6 +257,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia"
@@ -259,6 +267,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia"
@@ -268,6 +277,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia"
@@ -277,6 +287,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia"
@@ -286,6 +297,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia"
@@ -421,6 +433,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia"
@@ -457,6 +470,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia"
@@ -466,6 +480,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia"
@@ -482,6 +497,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "fuchsia"
))]
EBADMSG => "Not a data message",
@@ -492,6 +508,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "fuchsia",
target_os = "haiku"
))]
@@ -572,6 +589,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia",
@@ -582,6 +600,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "fuchsia"
@@ -722,6 +741,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "fuchsia"
))]
EOWNERDEAD => "Owner died",
@@ -732,6 +752,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "linux",
target_os = "android",
+ target_os = "aix",
target_os = "fuchsia"
))]
ENOTRECOVERABLE => "State not recoverable",
@@ -868,6 +889,7 @@ fn desc(errno: Errno) -> &'static str {
target_os = "ios",
target_os = "openbsd",
target_os = "netbsd",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "haiku"
@@ -879,6 +901,7 @@ fn desc(errno: Errno) -> &'static str {
target_os = "freebsd",
target_os = "dragonfly",
target_os = "ios",
+ target_os = "aix",
target_os = "openbsd",
target_os = "netbsd"
))]
@@ -889,6 +912,7 @@ fn desc(errno: Errno) -> &'static str {
target_os = "freebsd",
target_os = "dragonfly",
target_os = "ios",
+ target_os = "aix",
target_os = "openbsd",
target_os = "netbsd",
target_os = "redox"
@@ -903,6 +927,7 @@ fn desc(errno: Errno) -> &'static str {
target_os = "openbsd",
target_os = "netbsd",
target_os = "redox",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "haiku"
@@ -917,6 +942,7 @@ fn desc(errno: Errno) -> &'static str {
target_os = "openbsd",
target_os = "netbsd",
target_os = "redox",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
target_os = "haiku"
@@ -928,6 +954,7 @@ fn desc(errno: Errno) -> &'static str {
target_os = "freebsd",
target_os = "dragonfly",
target_os = "ios",
+ target_os = "aix",
target_os = "openbsd",
target_os = "netbsd",
target_os = "redox"
@@ -1009,6 +1036,7 @@ fn desc(errno: Errno) -> &'static str {
target_os = "freebsd",
target_os = "dragonfly",
target_os = "ios",
+ target_os = "aix",
target_os = "openbsd",
target_os = "netbsd",
target_os = "redox"
@@ -1044,6 +1072,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "aix",
target_os = "netbsd",
target_os = "redox"
))]
@@ -1060,6 +1089,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "aix",
target_os = "netbsd",
target_os = "redox"
))]
@@ -1068,6 +1098,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "aix",
target_os = "netbsd",
target_os = "redox"
))]
@@ -1076,6 +1107,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "aix",
target_os = "netbsd",
target_os = "redox"
))]
@@ -1084,6 +1116,7 @@ fn desc(errno: Errno) -> &'static str {
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris"
))]
@@ -3131,3 +3164,217 @@ mod consts {
}
}
}
+
+#[cfg(target_os = "aix")]
+mod consts {
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ #[repr(i32)]
+ #[non_exhaustive]
+ pub enum Errno {
+ UnknownErrno = 0,
+ EPERM = libc::EPERM,
+ ENOENT = libc::ENOENT,
+ ESRCH = libc::ESRCH,
+ EINTR = libc::EINTR,
+ EIO = libc::EIO,
+ ENXIO = libc::ENXIO,
+ E2BIG = libc::E2BIG,
+ ENOEXEC = libc::ENOEXEC,
+ EBADF = libc::EBADF,
+ ECHILD = libc::ECHILD,
+ EAGAIN = libc::EAGAIN,
+ ENOMEM = libc::ENOMEM,
+ EACCES = libc::EACCES,
+ EFAULT = libc::EFAULT,
+ ENOTBLK = libc::ENOTBLK,
+ EBUSY = libc::EBUSY,
+ EEXIST = libc::EEXIST,
+ EXDEV = libc::EXDEV,
+ ENODEV = libc::ENODEV,
+ ENOTDIR = libc::ENOTDIR,
+ EISDIR = libc::EISDIR,
+ EINVAL = libc::EINVAL,
+ ENFILE = libc::ENFILE,
+ EMFILE = libc::EMFILE,
+ ENOTTY = libc::ENOTTY,
+ ETXTBSY = libc::ETXTBSY,
+ EFBIG = libc::EFBIG,
+ ENOSPC = libc::ENOSPC,
+ ESPIPE = libc::ESPIPE,
+ EROFS = libc::EROFS,
+ EMLINK = libc::EMLINK,
+ EPIPE = libc::EPIPE,
+ EDOM = libc::EDOM,
+ ERANGE = libc::ERANGE,
+ EDEADLK = libc::EDEADLK,
+ ENAMETOOLONG = libc::ENAMETOOLONG,
+ ENOLCK = libc::ENOLCK,
+ ENOSYS = libc::ENOSYS,
+ ENOTEMPTY = libc::ENOTEMPTY,
+ ELOOP = libc::ELOOP,
+ ENOMSG = libc::ENOMSG,
+ EIDRM = libc::EIDRM,
+ EINPROGRESS = libc::EINPROGRESS,
+ EALREADY = libc::EALREADY,
+ ENOTSOCK = libc::ENOTSOCK,
+ EDESTADDRREQ = libc::EDESTADDRREQ,
+ EMSGSIZE = libc::EMSGSIZE,
+ EPROTOTYPE = libc::EPROTOTYPE,
+ ENOPROTOOPT = libc::ENOPROTOOPT,
+ EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
+ ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
+ EPFNOSUPPORT = libc::EPFNOSUPPORT,
+ EAFNOSUPPORT = libc::EAFNOSUPPORT,
+ EADDRINUSE = libc::EADDRINUSE,
+ EADDRNOTAVAIL = libc::EADDRNOTAVAIL,
+ ENETDOWN = libc::ENETDOWN,
+ ENETUNREACH = libc::ENETUNREACH,
+ ENETRESET = libc::ENETRESET,
+ ECONNABORTED = libc::ECONNABORTED,
+ ECONNRESET = libc::ECONNRESET,
+ ENOBUFS = libc::ENOBUFS,
+ EISCONN = libc::EISCONN,
+ ENOTCONN = libc::ENOTCONN,
+ ESHUTDOWN = libc::ESHUTDOWN,
+ ETOOMANYREFS = libc::ETOOMANYREFS,
+ ETIMEDOUT = libc::ETIMEDOUT,
+ ECONNREFUSED = libc::ECONNREFUSED,
+ EHOSTDOWN = libc::EHOSTDOWN,
+ EHOSTUNREACH = libc::EHOSTUNREACH,
+ ECHRNG = libc::ECHRNG,
+ EL2NSYNC = libc::EL2NSYNC,
+ EL3HLT = libc::EL3HLT,
+ EL3RST = libc::EL3RST,
+ ELNRNG = libc::ELNRNG,
+ EUNATCH = libc::EUNATCH,
+ ENOCSI = libc::ENOCSI,
+ EL2HLT = libc::EL2HLT,
+ ENOLINK = libc::ENOLINK,
+ EPROTO = libc::EPROTO,
+ EMULTIHOP = libc::EMULTIHOP,
+ EBADMSG = libc::EBADMSG,
+ EOVERFLOW = libc::EOVERFLOW,
+ EILSEQ = libc::EILSEQ,
+ ERESTART = libc::ERESTART,
+ EOWNERDEAD = libc::EOWNERDEAD,
+ ENOTRECOVERABLE = libc::ENOTRECOVERABLE,
+ ENOTSUP = libc::ENOTSUP,
+ EPROCLIM = libc::EPROCLIM,
+ EUSERS = libc::EUSERS,
+ EDQUOT = libc::EDQUOT,
+ ESTALE = libc::ESTALE,
+ EREMOTE = libc::EREMOTE,
+ ECANCELED = libc::ECANCELED,
+ ENODATA = libc::ENODATA,
+ ENOSR = libc::ENOSR,
+ ENOSTR = libc::ENOSTR,
+ ETIME = libc::ETIME,
+ EOPNOTSUPP = libc::EOPNOTSUPP,
+ }
+
+ pub const fn from_i32(e: i32) -> Errno {
+ use self::Errno::*;
+
+ match e {
+ libc::EPERM => EPERM,
+ libc::ENOENT => ENOENT,
+ libc::ESRCH => ESRCH,
+ libc::EINTR => EINTR,
+ libc::EIO => EIO,
+ libc::ENXIO => ENXIO,
+ libc::E2BIG => E2BIG,
+ libc::ENOEXEC => ENOEXEC,
+ libc::EBADF => EBADF,
+ libc::ECHILD => ECHILD,
+ libc::EAGAIN => EAGAIN,
+ libc::ENOMEM => ENOMEM,
+ libc::EACCES => EACCES,
+ libc::EFAULT => EFAULT,
+ libc::ENOTBLK => ENOTBLK,
+ libc::EBUSY => EBUSY,
+ libc::EEXIST => EEXIST,
+ libc::EXDEV => EXDEV,
+ libc::ENODEV => ENODEV,
+ libc::ENOTDIR => ENOTDIR,
+ libc::EISDIR => EISDIR,
+ libc::EINVAL => EINVAL,
+ libc::ENFILE => ENFILE,
+ libc::EMFILE => EMFILE,
+ libc::ENOTTY => ENOTTY,
+ libc::ETXTBSY => ETXTBSY,
+ libc::EFBIG => EFBIG,
+ libc::ENOSPC => ENOSPC,
+ libc::ESPIPE => ESPIPE,
+ libc::EROFS => EROFS,
+ libc::EMLINK => EMLINK,
+ libc::EPIPE => EPIPE,
+ libc::EDOM => EDOM,
+ libc::ERANGE => ERANGE,
+ libc::EDEADLK => EDEADLK,
+ libc::ENAMETOOLONG => ENAMETOOLONG,
+ libc::ENOLCK => ENOLCK,
+ libc::ENOSYS => ENOSYS,
+ libc::ENOTEMPTY => ENOTEMPTY,
+ libc::ELOOP => ELOOP,
+ libc::ENOMSG => ENOMSG,
+ libc::EIDRM => EIDRM,
+ libc::EINPROGRESS => EINPROGRESS,
+ libc::EALREADY => EALREADY,
+ libc::ENOTSOCK => ENOTSOCK,
+ libc::EDESTADDRREQ => EDESTADDRREQ,
+ libc::EMSGSIZE => EMSGSIZE,
+ libc::EPROTOTYPE => EPROTOTYPE,
+ libc::ENOPROTOOPT => ENOPROTOOPT,
+ libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
+ libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
+ libc::EPFNOSUPPORT => EPFNOSUPPORT,
+ libc::EAFNOSUPPORT => EAFNOSUPPORT,
+ libc::EADDRINUSE => EADDRINUSE,
+ libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
+ libc::ENETDOWN => ENETDOWN,
+ libc::ENETUNREACH => ENETUNREACH,
+ libc::ENETRESET => ENETRESET,
+ libc::ECONNABORTED => ECONNABORTED,
+ libc::ECONNRESET => ECONNRESET,
+ libc::ENOBUFS => ENOBUFS,
+ libc::EISCONN => EISCONN,
+ libc::ENOTCONN => ENOTCONN,
+ libc::ESHUTDOWN => ESHUTDOWN,
+ libc::ETOOMANYREFS => ETOOMANYREFS,
+ libc::ETIMEDOUT => ETIMEDOUT,
+ libc::ECONNREFUSED => ECONNREFUSED,
+ libc::EHOSTDOWN => EHOSTDOWN,
+ libc::EHOSTUNREACH => EHOSTUNREACH,
+ libc::ECHRNG => ECHRNG,
+ libc::EL2NSYNC => EL2NSYNC,
+ libc::EL3HLT => EL3HLT,
+ libc::EL3RST => EL3RST,
+ libc::ELNRNG => ELNRNG,
+ libc::EUNATCH => EUNATCH,
+ libc::ENOCSI => ENOCSI,
+ libc::EL2HLT => EL2HLT,
+ libc::ENOLINK => ENOLINK,
+ libc::EPROTO => EPROTO,
+ libc::EMULTIHOP => EMULTIHOP,
+ libc::EBADMSG => EBADMSG,
+ libc::EOVERFLOW => EOVERFLOW,
+ libc::EILSEQ => EILSEQ,
+ libc::ERESTART => ERESTART,
+ libc::ENOTRECOVERABLE => ENOTRECOVERABLE,
+ libc::EOWNERDEAD => EOWNERDEAD,
+ libc::ENOTSUP => ENOTSUP,
+ libc::EPROCLIM => EPROCLIM,
+ libc::EUSERS => EUSERS,
+ libc::EDQUOT => EDQUOT,
+ libc::ESTALE => ESTALE,
+ libc::EREMOTE => EREMOTE,
+ libc::ECANCELED => ECANCELED,
+ libc::ENODATA => ENODATA,
+ libc::ENOSR => ENOSR,
+ libc::ENOSTR => ENOSTR,
+ libc::ETIME => ETIME,
+ libc::EOPNOTSUPP => EOPNOTSUPP,
+ _ => UnknownErrno,
+ }
+ }
+}
diff --git a/src/fcntl.rs b/src/fcntl.rs
index 6508283..9bfecda 100644
--- a/src/fcntl.rs
+++ b/src/fcntl.rs
@@ -5,11 +5,19 @@ use std::ffi::OsString;
use std::os::raw;
use std::os::unix::ffi::OsStringExt;
use std::os::unix::io::RawFd;
+// For splice and copy_file_range
+#[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "linux"
+))]
+use std::{
+ os::unix::io::{AsFd, AsRawFd},
+ ptr,
+};
#[cfg(feature = "fs")]
use crate::{sys::stat::Mode, NixPath, Result};
-#[cfg(any(target_os = "android", target_os = "linux"))]
-use std::ptr; // For splice and copy_file_range
#[cfg(any(
target_os = "linux",
@@ -35,7 +43,7 @@ libc_bitflags! {
AT_NO_AUTOMOUNT;
#[cfg(any(target_os = "android", target_os = "linux"))]
AT_EMPTY_PATH;
- #[cfg(any(target_os = "illumos", target_os = "solaris"))]
+ #[cfg(not(target_os = "android"))]
AT_EACCESS;
}
}
@@ -54,7 +62,10 @@ libc_bitflags!(
/// Open the file in append-only mode.
O_APPEND;
/// Generate a signal when input or output becomes possible.
- #[cfg(not(any(target_os = "illumos", target_os = "solaris", target_os = "haiku")))]
+ #[cfg(not(any(target_os = "aix",
+ target_os = "illumos",
+ target_os = "solaris",
+ target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
O_ASYNC;
/// Closes the file descriptor once an `execve` call is made.
@@ -193,9 +204,13 @@ feature! {
// The conversion is not identical on all operating systems.
#[allow(clippy::useless_conversion)]
-pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
- let fd = path.with_nix_path(|cstr| {
- unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
+pub fn open<P: ?Sized + NixPath>(
+ path: &P,
+ oflag: OFlag,
+ mode: Mode,
+) -> Result<RawFd> {
+ let fd = path.with_nix_path(|cstr| unsafe {
+ libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint)
})?;
Errno::result(fd)
@@ -210,8 +225,8 @@ pub fn openat<P: ?Sized + NixPath>(
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) }
+ let fd = path.with_nix_path(|cstr| unsafe {
+ libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint)
})?;
Errno::result(fd)
}
@@ -237,7 +252,7 @@ pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
}
}
-#[cfg(all(target_os = "linux", target_env = "gnu",))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
#[cfg(feature = "fs")]
libc_bitflags! {
#[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
@@ -250,10 +265,7 @@ libc_bitflags! {
feature! {
#![feature = "fs"]
-#[cfg(all(
- target_os = "linux",
- target_env = "gnu",
-))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
pub fn renameat2<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
old_dirfd: Option<RawFd>,
old_path: &P1,
@@ -306,56 +318,85 @@ fn readlink_maybe_at<P: ?Sized + NixPath>(
})
}
-fn inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P) -> Result<OsString> {
+fn inner_readlink<P: ?Sized + NixPath>(
+ dirfd: Option<RawFd>,
+ path: &P,
+) -> Result<OsString> {
let mut v = Vec::with_capacity(libc::PATH_MAX as usize);
- // simple case: result is strictly less than `PATH_MAX`
- let res = readlink_maybe_at(dirfd, path, &mut v)?;
- let len = Errno::result(res)?;
- debug_assert!(len >= 0);
- if (len as usize) < v.capacity() {
- return wrap_readlink_result(v, res);
+
+ {
+ // simple case: result is strictly less than `PATH_MAX`
+ let res = readlink_maybe_at(dirfd, path, &mut v)?;
+ let len = Errno::result(res)?;
+ debug_assert!(len >= 0);
+ if (len as usize) < v.capacity() {
+ return wrap_readlink_result(v, res);
+ }
}
+
// Uh oh, the result is too long...
// Let's try to ask lstat how many bytes to allocate.
- let reported_size = match dirfd {
- #[cfg(target_os = "redox")]
- Some(_) => unreachable!(),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- Some(dirfd) => {
- let flags = if path.is_empty() { AtFlags::AT_EMPTY_PATH } else { AtFlags::empty() };
- super::sys::stat::fstatat(dirfd, path, flags | AtFlags::AT_SYMLINK_NOFOLLOW)
- },
- #[cfg(not(any(target_os = "android", target_os = "linux", target_os = "redox")))]
- Some(dirfd) => super::sys::stat::fstatat(dirfd, path, AtFlags::AT_SYMLINK_NOFOLLOW),
- None => super::sys::stat::lstat(path)
- }
+ let mut try_size = {
+ let reported_size = match dirfd {
+ #[cfg(target_os = "redox")]
+ Some(_) => unreachable!(),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Some(dirfd) => {
+ let flags = if path.is_empty() {
+ AtFlags::AT_EMPTY_PATH
+ } else {
+ AtFlags::empty()
+ };
+ super::sys::stat::fstatat(
+ dirfd,
+ path,
+ flags | AtFlags::AT_SYMLINK_NOFOLLOW,
+ )
+ }
+ #[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "redox"
+ )))]
+ Some(dirfd) => super::sys::stat::fstatat(
+ dirfd,
+ path,
+ AtFlags::AT_SYMLINK_NOFOLLOW,
+ ),
+ None => super::sys::stat::lstat(path),
+ }
.map(|x| x.st_size)
.unwrap_or(0);
- let mut try_size = if reported_size > 0 {
- // Note: even if `lstat`'s apparently valid answer turns out to be
- // wrong, we will still read the full symlink no matter what.
- reported_size as usize + 1
- } else {
- // If lstat doesn't cooperate, or reports an error, be a little less
- // precise.
- (libc::PATH_MAX as usize).max(128) << 1
+
+ if reported_size > 0 {
+ // Note: even if `lstat`'s apparently valid answer turns out to be
+ // wrong, we will still read the full symlink no matter what.
+ reported_size as usize + 1
+ } else {
+ // If lstat doesn't cooperate, or reports an error, be a little less
+ // precise.
+ (libc::PATH_MAX as usize).max(128) << 1
+ }
};
+
loop {
- v.reserve_exact(try_size);
- let res = readlink_maybe_at(dirfd, path, &mut v)?;
- let len = Errno::result(res)?;
- debug_assert!(len >= 0);
- if (len as usize) < v.capacity() {
- break wrap_readlink_result(v, res);
- } else {
- // Ugh! Still not big enough!
- match try_size.checked_shl(1) {
- Some(next_size) => try_size = next_size,
- // It's absurd that this would happen, but handle it sanely
- // anyway.
- None => break Err(Errno::ENAMETOOLONG),
+ {
+ v.reserve_exact(try_size);
+ let res = readlink_maybe_at(dirfd, path, &mut v)?;
+ let len = Errno::result(res)?;
+ debug_assert!(len >= 0);
+ if (len as usize) < v.capacity() {
+ return wrap_readlink_result(v, res);
}
}
+
+ // Ugh! Still not big enough!
+ match try_size.checked_shl(1) {
+ Some(next_size) => try_size = next_size,
+ // It's absurd that this would happen, but handle it sanely
+ // anyway.
+ None => break Err(Errno::ENAMETOOLONG),
+ }
}
}
@@ -364,7 +405,10 @@ pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> {
}
#[cfg(not(target_os = "redox"))]
-pub fn readlinkat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P) -> Result<OsString> {
+pub fn readlinkat<P: ?Sized + NixPath>(
+ dirfd: RawFd,
+ path: &P,
+) -> Result<OsString> {
inner_readlink(Some(dirfd), path)
}
@@ -427,9 +471,17 @@ pub enum FcntlArg<'a> {
F_OFD_SETLKW(&'a libc::flock),
#[cfg(any(target_os = "linux", target_os = "android"))]
F_OFD_GETLK(&'a mut libc::flock),
- #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "freebsd"
+ ))]
F_ADD_SEALS(SealFlag),
- #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "freebsd"
+ ))]
F_GET_SEALS,
#[cfg(any(target_os = "macos", target_os = "ios"))]
F_FULLFSYNC,
@@ -458,7 +510,9 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
let res = unsafe {
match arg {
F_DUPFD(rawfd) => libc::fcntl(fd, libc::F_DUPFD, rawfd),
- F_DUPFD_CLOEXEC(rawfd) => libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, rawfd),
+ F_DUPFD_CLOEXEC(rawfd) => {
+ libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, rawfd)
+ }
F_GETFD => libc::fcntl(fd, libc::F_GETFD),
F_SETFD(flag) => libc::fcntl(fd, libc::F_SETFD, flag.bits()),
F_GETFL => libc::fcntl(fd, libc::F_GETFL),
@@ -475,9 +529,19 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock),
#[cfg(any(target_os = "android", target_os = "linux"))]
F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock),
- #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
- F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()),
- #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "freebsd"
+ ))]
+ F_ADD_SEALS(flag) => {
+ libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits())
+ }
+ #[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "freebsd"
+ ))]
F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS),
#[cfg(any(target_os = "macos", target_os = "ios"))]
F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC),
@@ -503,7 +567,7 @@ pub enum FlockArg {
UnlockNonblock,
}
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "solaris")))]
pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> {
use self::FlockArg::*;
@@ -512,8 +576,12 @@ pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> {
LockShared => libc::flock(fd, libc::LOCK_SH),
LockExclusive => libc::flock(fd, libc::LOCK_EX),
Unlock => libc::flock(fd, libc::LOCK_UN),
- LockSharedNonblock => libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB),
- LockExclusiveNonblock => libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB),
+ LockSharedNonblock => {
+ libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB)
+ }
+ LockExclusiveNonblock => {
+ libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB)
+ }
UnlockNonblock => libc::flock(fd, libc::LOCK_UN | libc::LOCK_NB),
}
};
@@ -552,44 +620,65 @@ feature! {
///
/// The `copy_file_range` system call performs an in-kernel copy between
/// file descriptors `fd_in` and `fd_out` without the additional cost of
-/// transferring data from the kernel to user space and then back into the
-/// kernel. It copies up to `len` bytes of data from file descriptor `fd_in` to
-/// file descriptor `fd_out`, overwriting any data that exists within the
-/// requested range of the target file.
+/// transferring data from the kernel to user space and back again. There may be
+/// additional optimizations for specific file systems. It copies up to `len`
+/// bytes of data from file descriptor `fd_in` to file descriptor `fd_out`,
+/// overwriting any data that exists within the requested range of the target
+/// file.
///
/// If the `off_in` and/or `off_out` arguments are used, the values
/// will be mutated to reflect the new position within the file after
-/// copying. If they are not used, the relevant filedescriptors will be seeked
+/// copying. If they are not used, the relevant file descriptors will be seeked
/// to the new position.
///
/// On successful completion the number of bytes actually copied will be
/// returned.
-#[cfg(any(target_os = "android", target_os = "linux"))]
-pub fn copy_file_range(
- fd_in: RawFd,
- off_in: Option<&mut libc::loff_t>,
- fd_out: RawFd,
- off_out: Option<&mut libc::loff_t>,
+// Note: FreeBSD defines the offset argument as "off_t". Linux and Android
+// define it as "loff_t". But on both OSes, on all supported platforms, those
+// are 64 bits. So Nix uses i64 to make the docs simple and consistent.
+#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
+pub fn copy_file_range<Fd1: AsFd, Fd2: AsFd>(
+ fd_in: Fd1,
+ off_in: Option<&mut i64>,
+ fd_out: Fd2,
+ off_out: Option<&mut i64>,
len: usize,
) -> Result<usize> {
let off_in = off_in
- .map(|offset| offset as *mut libc::loff_t)
+ .map(|offset| offset as *mut i64)
.unwrap_or(ptr::null_mut());
let off_out = off_out
- .map(|offset| offset as *mut libc::loff_t)
+ .map(|offset| offset as *mut i64)
.unwrap_or(ptr::null_mut());
- let ret = unsafe {
- libc::syscall(
- libc::SYS_copy_file_range,
- fd_in,
- off_in,
- fd_out,
- off_out,
- len,
- 0,
- )
- };
+ cfg_if::cfg_if! {
+ if #[cfg(target_os = "freebsd")] {
+ let ret = unsafe {
+ libc::copy_file_range(
+ fd_in.as_fd().as_raw_fd(),
+ off_in,
+ fd_out.as_fd().as_raw_fd(),
+ off_out,
+ len,
+ 0,
+ )
+ };
+ } else {
+ // May Linux distros still don't include copy_file_range in their
+ // libc implementations, so we need to make a direct syscall.
+ let ret = unsafe {
+ libc::syscall(
+ libc::SYS_copy_file_range,
+ fd_in,
+ off_in,
+ fd_out.as_fd().as_raw_fd(),
+ off_out,
+ len,
+ 0,
+ )
+ };
+ }
+ }
Errno::result(ret).map(|r| r as usize)
}
@@ -609,12 +698,19 @@ pub fn splice(
.map(|offset| offset as *mut libc::loff_t)
.unwrap_or(ptr::null_mut());
- let ret = unsafe { libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) };
+ let ret = unsafe {
+ libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits())
+ };
Errno::result(ret).map(|r| r as usize)
}
#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Result<usize> {
+pub fn tee(
+ fd_in: RawFd,
+ fd_out: RawFd,
+ len: usize,
+ flags: SpliceFFlags,
+) -> Result<usize> {
let ret = unsafe { libc::tee(fd_in, fd_out, len, flags.bits()) };
Errno::result(ret).map(|r| r as usize)
}
@@ -623,9 +719,8 @@ pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Resu
pub fn vmsplice(
fd: RawFd,
iov: &[std::io::IoSlice<'_>],
- flags: SpliceFFlags
- ) -> Result<usize>
-{
+ flags: SpliceFFlags,
+) -> Result<usize> {
let ret = unsafe {
libc::vmsplice(
fd,
@@ -638,7 +733,7 @@ pub fn vmsplice(
}
}
-#[cfg(any(target_os = "linux"))]
+#[cfg(target_os = "linux")]
#[cfg(feature = "fs")]
libc_bitflags!(
/// Mode argument flags for fallocate determining operation performed on a given range.
@@ -678,7 +773,7 @@ feature! {
///
/// Allows the caller to directly manipulate the allocated disk space for the
/// file referred to by fd.
-#[cfg(any(target_os = "linux"))]
+#[cfg(target_os = "linux")]
#[cfg(feature = "fs")]
pub fn fallocate(
fd: RawFd,
@@ -755,14 +850,19 @@ impl SpacectlRange {
/// ```
#[cfg(target_os = "freebsd")]
pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result<SpacectlRange> {
- let mut rqsr = libc::spacectl_range{r_offset: range.0, r_len: range.1};
- let res = unsafe { libc::fspacectl(
+ let mut rqsr = libc::spacectl_range {
+ r_offset: range.0,
+ r_len: range.1,
+ };
+ let res = unsafe {
+ libc::fspacectl(
fd,
libc::SPACECTL_DEALLOC, // Only one command is supported ATM
&rqsr,
- 0, // No flags are currently supported
- &mut rqsr
- )};
+ 0, // No flags are currently supported
+ &mut rqsr,
+ )
+ };
Errno::result(res).map(|_| SpacectlRange(rqsr.r_offset, rqsr.r_len))
}
@@ -797,18 +897,25 @@ pub fn fspacectl(fd: RawFd, range: SpacectlRange) -> Result<SpacectlRange> {
/// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef");
/// ```
#[cfg(target_os = "freebsd")]
-pub fn fspacectl_all(fd: RawFd, offset: libc::off_t, len: libc::off_t)
- -> Result<()>
-{
- let mut rqsr = libc::spacectl_range{r_offset: offset, r_len: len};
+pub fn fspacectl_all(
+ fd: RawFd,
+ offset: libc::off_t,
+ len: libc::off_t,
+) -> Result<()> {
+ let mut rqsr = libc::spacectl_range {
+ r_offset: offset,
+ r_len: len,
+ };
while rqsr.r_len > 0 {
- let res = unsafe { libc::fspacectl(
+ let res = unsafe {
+ libc::fspacectl(
fd,
libc::SPACECTL_DEALLOC, // Only one command is supported ATM
&rqsr,
- 0, // No flags are currently supported
- &mut rqsr
- )};
+ 0, // No flags are currently supported
+ &mut rqsr,
+ )
+ };
Errno::result(res)?;
}
Ok(())
@@ -825,8 +932,8 @@ pub fn fspacectl_all(fd: RawFd, offset: libc::off_t, len: libc::off_t)
))]
mod posix_fadvise {
use crate::errno::Errno;
- use std::os::unix::io::RawFd;
use crate::Result;
+ use std::os::unix::io::RawFd;
#[cfg(feature = "fs")]
libc_enum! {
@@ -871,7 +978,11 @@ mod posix_fadvise {
target_os = "wasi",
target_os = "freebsd"
))]
-pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<()> {
+pub fn posix_fallocate(
+ fd: RawFd,
+ offset: libc::off_t,
+ len: libc::off_t,
+) -> Result<()> {
let res = unsafe { libc::posix_fallocate(fd, offset, len) };
match Errno::result(res) {
Err(err) => Err(err),
diff --git a/src/features.rs b/src/features.rs
index 39d1760..9e292cb 100644
--- a/src/features.rs
+++ b/src/features.rs
@@ -6,6 +6,7 @@ mod os {
use crate::sys::utsname::uname;
use crate::Result;
use std::os::unix::ffi::OsStrExt;
+ use std::sync::atomic::{AtomicUsize, Ordering};
// Features:
// * atomic cloexec on socket: 2.6.27
@@ -72,15 +73,15 @@ mod os {
}
fn kernel_version() -> Result<usize> {
- static mut KERNEL_VERS: usize = 0;
+ static KERNEL_VERS: AtomicUsize = AtomicUsize::new(0);
+ let mut kernel_vers = KERNEL_VERS.load(Ordering::Relaxed);
- unsafe {
- if KERNEL_VERS == 0 {
- KERNEL_VERS = parse_kernel_version()?;
- }
-
- Ok(KERNEL_VERS)
+ if kernel_vers == 0 {
+ kernel_vers = parse_kernel_version()?;
+ KERNEL_VERS.store(kernel_vers, Ordering::Relaxed);
}
+
+ Ok(kernel_vers)
}
/// Check if the OS supports atomic close-on-exec for sockets
@@ -112,6 +113,7 @@ mod os {
}
#[cfg(any(
+ target_os = "aix",
target_os = "macos",
target_os = "ios",
target_os = "fuchsia",
diff --git a/src/kmod.rs b/src/kmod.rs
index 1fa6c17..d3725c3 100644
--- a/src/kmod.rs
+++ b/src/kmod.rs
@@ -3,7 +3,7 @@
//! For more details see
use std::ffi::CStr;
-use std::os::unix::io::AsRawFd;
+use std::os::unix::io::{AsFd, AsRawFd};
use crate::errno::Errno;
use crate::Result;
@@ -79,15 +79,15 @@ libc_bitflags!(
/// ```
///
/// See [`man init_module(2)`](https://man7.org/linux/man-pages/man2/init_module.2.html) for more information.
-pub fn finit_module<T: AsRawFd>(
- fd: &T,
+pub fn finit_module<Fd: AsFd>(
+ fd: Fd,
param_values: &CStr,
flags: ModuleInitFlags,
) -> Result<()> {
let res = unsafe {
libc::syscall(
libc::SYS_finit_module,
- fd.as_raw_fd(),
+ fd.as_fd().as_raw_fd(),
param_values.as_ptr(),
flags.bits(),
)
diff --git a/src/lib.rs b/src/lib.rs
index 6b82125..af0c67b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -16,7 +16,7 @@
//! * `fs` - File system functionality
//! * `hostname` - Get and set the system's hostname
//! * `inotify` - Linux's `inotify` file system notification API
-//! * `ioctl` - The `ioctl` syscall, and wrappers for my specific instances
+//! * `ioctl` - The `ioctl` syscall, and wrappers for many specific instances
//! * `kmod` - Load and unload kernel modules
//! * `mman` - Stuff relating to memory management
//! * `mount` - Mount and unmount file systems
@@ -47,7 +47,43 @@
#![recursion_limit = "500"]
#![deny(unused)]
#![allow(unused_macros)]
-#![cfg_attr(not(feature = "default"), allow(unused_imports))]
+#![cfg_attr(
+ not(all(
+ feature = "acct",
+ feature = "aio",
+ feature = "dir",
+ feature = "env",
+ feature = "event",
+ feature = "feature",
+ feature = "fs",
+ feature = "hostname",
+ feature = "inotify",
+ feature = "ioctl",
+ feature = "kmod",
+ feature = "mman",
+ feature = "mount",
+ feature = "mqueue",
+ feature = "net",
+ feature = "personality",
+ feature = "poll",
+ feature = "process",
+ feature = "pthread",
+ feature = "ptrace",
+ feature = "quota",
+ feature = "reboot",
+ feature = "resource",
+ feature = "sched",
+ feature = "socket",
+ feature = "signal",
+ feature = "term",
+ feature = "time",
+ feature = "ucontext",
+ feature = "uio",
+ feature = "user",
+ feature = "zerocopy",
+ )),
+ allow(unused_imports)
+)]
#![deny(unstable_features)]
#![deny(missing_copy_implementations)]
#![deny(missing_debug_implementations)]
@@ -144,7 +180,12 @@ feature! {
// provides bindings for them.
#[cfg(all(
target_os = "linux",
- any(target_arch = "s390x", target_arch = "x86", target_arch = "x86_64")
+ any(
+ target_arch = "aarch64",
+ target_arch = "s390x",
+ target_arch = "x86",
+ target_arch = "x86_64"
+ )
))]
feature! {
#![feature = "ucontext"]
diff --git a/src/macros.rs b/src/macros.rs
index 99e0de8..adff2bc 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -63,6 +63,8 @@ macro_rules! libc_bitflags {
}
) => {
::bitflags::bitflags! {
+ #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+ #[repr(transparent)]
$(#[$outer])*
pub struct $BitFlags: $T {
$(
@@ -95,7 +97,6 @@ macro_rules! libc_bitflags {
/// }
/// ```
// Some targets don't use all rules.
-#[allow(unknown_lints)]
#[allow(unused_macro_rules)]
macro_rules! libc_enum {
// Exit rule.
@@ -133,6 +134,8 @@ macro_rules! libc_enum {
impl ::std::convert::TryFrom<$repr> for $BitFlags {
type Error = $crate::Error;
#[allow(unused_doc_comments)]
+ #[allow(deprecated)]
+ #[allow(unused_attributes)]
fn try_from(x: $repr) -> $crate::Result<Self> {
match x {
$($try_froms)*
diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs
index d124f1f..6ed2dc7 100644
--- a/src/mount/bsd.rs
+++ b/src/mount/bsd.rs
@@ -391,8 +391,8 @@ impl<'a> Nmount<'a> {
});
let niov = self.iov.len() as c_uint;
- let iovp = self.iov.as_mut_ptr() as *mut libc::iovec;
- let res = unsafe { libc::nmount(iovp, niov, flags.bits) };
+ let iovp = self.iov.as_mut_ptr();
+ let res = unsafe { libc::nmount(iovp, niov, flags.bits()) };
match Errno::result(res) {
Ok(_) => Ok(()),
Err(error) => {
@@ -446,7 +446,7 @@ where
P: ?Sized + NixPath,
{
let res = mountpoint.with_nix_path(|cstr| unsafe {
- libc::unmount(cstr.as_ptr(), flags.bits)
+ libc::unmount(cstr.as_ptr(), flags.bits())
})?;
Errno::result(res).map(drop)
diff --git a/src/mount/linux.rs b/src/mount/linux.rs
index cf6a60b..e987603 100644
--- a/src/mount/linux.rs
+++ b/src/mount/linux.rs
@@ -1,9 +1,9 @@
-#![allow(missing_docs)]
use crate::errno::Errno;
use crate::{NixPath, Result};
use libc::{self, c_int, c_ulong};
libc_bitflags!(
+ /// Used with [`mount`].
pub struct MsFlags: c_ulong {
/// Mount read-only
MS_RDONLY;
@@ -27,36 +27,80 @@ libc_bitflags!(
MS_NODIRATIME;
/// Linux 2.4.0 - Bind directory at different place
MS_BIND;
+ /// Move an existing mount to a new location
MS_MOVE;
+ /// Used to create a recursive bind mount.
MS_REC;
+ /// Suppress the display of certain kernel warning messages.
MS_SILENT;
+ /// VFS does not apply the umask
MS_POSIXACL;
+ /// The resulting mount cannot subsequently be bind mounted.
MS_UNBINDABLE;
+ /// Make this mount point private.
MS_PRIVATE;
+ /// If this is a shared mount point that is a member of a peer group
+ /// that contains other members, convert it to a slave mount.
MS_SLAVE;
+ /// Make this mount point shared.
MS_SHARED;
+ /// When a file on this filesystem is accessed, update the file's
+ /// last access time (atime) only if the current value of atime is
+ /// less than or equal to the file's last modification time (mtime) or
+ /// last status change time (ctime).
MS_RELATIME;
+ /// Mount request came from within the kernel
+ #[deprecated(since = "0.27.0", note = "Should only be used in-kernel")]
MS_KERNMOUNT;
+ /// Update inode I_version field
MS_I_VERSION;
+ /// Always update the last access time (atime) when files on this
+ /// filesystem are accessed.
MS_STRICTATIME;
+ /// Reduce on-disk updates of inode timestamps (atime, mtime, ctime) by
+ /// maintaining these changes only in memory.
MS_LAZYTIME;
+ #[deprecated(since = "0.27.0", note = "Should only be used in-kernel")]
+ #[allow(missing_docs)] // Not documented in Linux
MS_ACTIVE;
+ #[deprecated(since = "0.27.0", note = "Should only be used in-kernel")]
+ #[allow(missing_docs)] // Not documented in Linux
MS_NOUSER;
+ #[allow(missing_docs)] // Not documented in Linux; possibly kernel-only
MS_RMT_MASK;
+ #[allow(missing_docs)] // Not documented in Linux; possibly kernel-only
MS_MGC_VAL;
+ #[allow(missing_docs)] // Not documented in Linux; possibly kernel-only
MS_MGC_MSK;
}
);
libc_bitflags!(
+ /// Used with [`umount2].
pub struct MntFlags: c_int {
+ /// Attempt to unmount even if still in use, aborting pending requests.
MNT_FORCE;
+ /// Lazy unmount. Disconnect the file system immediately, but don't
+ /// actually unmount it until it ceases to be busy.
MNT_DETACH;
+ /// Mark the mount point as expired.
MNT_EXPIRE;
+ /// Don't dereference `target` if it is a symlink.
UMOUNT_NOFOLLOW;
}
);
+/// Mount a file system.
+///
+/// # Arguments
+/// - `source` - Specifies the file system. e.g. `/dev/sd0`.
+/// - `target` - Specifies the destination. e.g. `/mnt`.
+/// - `fstype` - The file system type, e.g. `ext4`.
+/// - `flags` - Optional flags controlling the mount.
+/// - `data` - Optional file system specific data.
+///
+/// # See Also
+/// [`mount`](https://man7.org/linux/man-pages/man2/mount.2.html)
pub fn mount<
P1: ?Sized + NixPath,
P2: ?Sized + NixPath,
@@ -88,7 +132,7 @@ pub fn mount<
s,
t.as_ptr(),
ty,
- flags.bits,
+ flags.bits(),
d as *const libc::c_void,
)
})
@@ -99,6 +143,7 @@ pub fn mount<
Errno::result(res).map(drop)
}
+/// Unmount the file system mounted at `target`.
pub fn umount<P: ?Sized + NixPath>(target: &P) -> Result<()> {
let res =
target.with_nix_path(|cstr| unsafe { libc::umount(cstr.as_ptr()) })?;
@@ -106,9 +151,12 @@ pub fn umount<P: ?Sized + NixPath>(target: &P) -> Result<()> {
Errno::result(res).map(drop)
}
+/// Unmount the file system mounted at `target`.
+///
+/// See also [`umount`](https://man7.org/linux/man-pages/man2/umount.2.html)
pub fn umount2<P: ?Sized + NixPath>(target: &P, flags: MntFlags) -> Result<()> {
let res = target.with_nix_path(|cstr| unsafe {
- libc::umount2(cstr.as_ptr(), flags.bits)
+ libc::umount2(cstr.as_ptr(), flags.bits())
})?;
Errno::result(res).map(drop)
diff --git a/src/mqueue.rs b/src/mqueue.rs
index 33599bf..fb07d2a 100644
--- a/src/mqueue.rs
+++ b/src/mqueue.rs
@@ -9,16 +9,16 @@
//! use nix::sys::stat::Mode;
//!
//! const MSG_SIZE: mq_attr_member_t = 32;
-//! let mq_name= CString::new("/a_nix_test_queue").unwrap();
+//! let mq_name= "/a_nix_test_queue";
//!
//! let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
//! let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
-//! let mqd0 = mq_open(&mq_name, oflag0, mode, None).unwrap();
+//! let mqd0 = mq_open(mq_name, oflag0, mode, None).unwrap();
//! let msg_to_send = b"msg_1";
//! mq_send(&mqd0, msg_to_send, 1).unwrap();
//!
//! let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY;
-//! let mqd1 = mq_open(&mq_name, oflag1, mode, None).unwrap();
+//! let mqd1 = mq_open(mq_name, oflag1, mode, None).unwrap();
//! let mut buf = [0u8; 32];
//! let mut prio = 0u32;
//! let len = mq_receive(&mqd1, &mut buf, &mut prio).unwrap();
@@ -31,12 +31,20 @@
//! [Further reading and details on the C API](https://man7.org/linux/man-pages/man7/mq_overview.7.html)
use crate::errno::Errno;
+use crate::NixPath;
use crate::Result;
use crate::sys::stat::Mode;
use libc::{self, c_char, mqd_t, size_t};
-use std::ffi::CStr;
use std::mem;
+#[cfg(any(
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "dragonfly"
+))]
+use std::os::unix::io::{
+ AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd,
+};
libc_bitflags! {
/// Used with [`mq_open`].
@@ -139,33 +147,41 @@ impl MqAttr {
/// Open a message queue
///
/// See also [`mq_open(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html)
-// The mode.bits cast is only lossless on some OSes
+// The mode.bits() cast is only lossless on some OSes
#[allow(clippy::cast_lossless)]
-pub fn mq_open(
- name: &CStr,
+pub fn mq_open<P>(
+ name: &P,
oflag: MQ_OFlag,
mode: Mode,
attr: Option<&MqAttr>,
-) -> Result<MqdT> {
- let res = match attr {
+) -> Result<MqdT>
+where
+ P: ?Sized + NixPath,
+{
+ let res = name.with_nix_path(|cstr| match attr {
Some(mq_attr) => unsafe {
libc::mq_open(
- name.as_ptr(),
+ cstr.as_ptr(),
oflag.bits(),
mode.bits() as libc::c_int,
&mq_attr.mq_attr as *const libc::mq_attr,
)
},
- None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) },
- };
+ None => unsafe { libc::mq_open(cstr.as_ptr(), oflag.bits()) },
+ })?;
+
Errno::result(res).map(MqdT)
}
/// Remove a message queue
///
/// See also [`mq_unlink(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html)
-pub fn mq_unlink(name: &CStr) -> Result<()> {
- let res = unsafe { libc::mq_unlink(name.as_ptr()) };
+pub fn mq_unlink<P>(name: &P) -> Result<()>
+where
+ P: ?Sized + NixPath,
+{
+ let res =
+ name.with_nix_path(|cstr| unsafe { libc::mq_unlink(cstr.as_ptr()) })?;
Errno::result(res).map(drop)
}
@@ -197,6 +213,32 @@ pub fn mq_receive(
Errno::result(res).map(|r| r as usize)
}
+feature! {
+ #![feature = "time"]
+ use crate::sys::time::TimeSpec;
+ /// Receive a message from a message queue with a timeout
+ ///
+ /// See also ['mq_timedreceive(2)'](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html)
+ pub fn mq_timedreceive(
+ mqdes: &MqdT,
+ message: &mut [u8],
+ msg_prio: &mut u32,
+ abstime: &TimeSpec,
+ ) -> Result<usize> {
+ let len = message.len() as size_t;
+ let res = unsafe {
+ libc::mq_timedreceive(
+ mqdes.0,
+ message.as_mut_ptr() as *mut c_char,
+ len,
+ msg_prio as *mut u32,
+ abstime.as_ref(),
+ )
+ };
+ Errno::result(res).map(|r| r as usize)
+ }
+}
+
/// Send a message to a message queue
///
/// See also [`mq_send(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html)
@@ -274,3 +316,43 @@ pub fn mq_remove_nonblock(mqd: &MqdT) -> Result<MqAttr> {
);
mq_setattr(mqd, &newattr)
}
+
+#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "dragonfly"))]
+impl AsFd for MqdT {
+ /// Borrow the underlying message queue descriptor.
+ fn as_fd(&self) -> BorrowedFd {
+ // SAFETY: [MqdT] will only contain a valid fd by construction.
+ unsafe { BorrowedFd::borrow_raw(self.0) }
+ }
+}
+
+#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "dragonfly"))]
+impl AsRawFd for MqdT {
+ /// Return the underlying message queue descriptor.
+ ///
+ /// Returned descriptor is a "shallow copy" of the descriptor, so it refers
+ /// to the same underlying kernel object as `self`.
+ fn as_raw_fd(&self) -> RawFd {
+ self.0
+ }
+}
+
+#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "dragonfly"))]
+impl FromRawFd for MqdT {
+ /// Construct an [MqdT] from [RawFd].
+ ///
+ /// # Safety
+ /// The `fd` given must be a valid and open file descriptor for a message
+ /// queue.
+ unsafe fn from_raw_fd(fd: RawFd) -> MqdT {
+ MqdT(fd)
+ }
+}
+
+#[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "dragonfly"))]
+impl IntoRawFd for MqdT {
+ /// Consume this [MqdT] and return a [RawFd].
+ fn into_raw_fd(self) -> RawFd {
+ self.0
+ }
+}
diff --git a/src/net/if_.rs b/src/net/if_.rs
index b2423bc..ec46260 100644
--- a/src/net/if_.rs
+++ b/src/net/if_.rs
@@ -334,6 +334,7 @@ libc_bitflags!(
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
+ target_os = "illumos",
))]
#[cfg_attr(docsrs, doc(cfg(all())))]
mod if_nameindex {
@@ -465,5 +466,6 @@ mod if_nameindex {
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
+ target_os = "illumos",
))]
pub use if_nameindex::*;
diff --git a/src/poll.rs b/src/poll.rs
index 6f227fe..9181bf7 100644
--- a/src/poll.rs
+++ b/src/poll.rs
@@ -1,5 +1,5 @@
//! Wait for events to trigger on specific file descriptors
-use std::os::unix::io::{AsRawFd, RawFd};
+use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd};
use crate::errno::Errno;
use crate::Result;
@@ -14,20 +14,36 @@ use crate::Result;
/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-pub struct PollFd {
+pub struct PollFd<'fd> {
pollfd: libc::pollfd,
+ _fd: std::marker::PhantomData<BorrowedFd<'fd>>,
}
-impl PollFd {
+impl<'fd> PollFd<'fd> {
/// Creates a new `PollFd` specifying the events of interest
/// for a given file descriptor.
- pub const fn new(fd: RawFd, events: PollFlags) -> PollFd {
+ //
+ // Different from other I/O-safe interfaces, here, we have to take `AsFd`
+ // by reference to prevent the case where the `fd` is closed but it is
+ // still in use. For example:
+ //
+ // ```rust
+ // let (reader, _) = pipe().unwrap();
+ //
+ // // If `PollFd::new()` takes `AsFd` by value, then `reader` will be consumed,
+ // // but the file descriptor of `reader` will still be in use.
+ // let pollfd = PollFd::new(reader, flag);
+ //
+ // // Do something with `pollfd`, which uses the CLOSED fd.
+ // ```
+ pub fn new<Fd: AsFd>(fd: &'fd Fd, events: PollFlags) -> PollFd<'fd> {
PollFd {
pollfd: libc::pollfd {
- fd,
+ fd: fd.as_fd().as_raw_fd(),
events: events.bits(),
revents: PollFlags::empty().bits(),
},
+ _fd: std::marker::PhantomData,
}
}
@@ -68,9 +84,29 @@ impl PollFd {
}
}
-impl AsRawFd for PollFd {
- fn as_raw_fd(&self) -> RawFd {
- self.pollfd.fd
+impl<'fd> AsFd for PollFd<'fd> {
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ // Safety:
+ //
+ // BorrowedFd::borrow_raw(RawFd) requires that the raw fd being passed
+ // must remain open for the duration of the returned BorrowedFd, this is
+ // guaranteed as the returned BorrowedFd has the lifetime parameter same
+ // as `self`:
+ // "fn as_fd<'self>(&'self self) -> BorrowedFd<'self>"
+ // which means that `self` (PollFd) is guaranteed to outlive the returned
+ // BorrowedFd. (Lifetime: PollFd > BorrowedFd)
+ //
+ // And the lifetime parameter of PollFd::new(fd, ...) ensures that `fd`
+ // (an owned file descriptor) must outlive the returned PollFd:
+ // "pub fn new<Fd: AsFd>(fd: &'fd Fd, events: PollFlags) -> PollFd<'fd>"
+ // (Lifetime: Owned fd > PollFd)
+ //
+ // With two above relationships, we can conclude that the `Owned file
+ // descriptor` will outlive the returned BorrowedFd,
+ // (Lifetime: Owned fd > BorrowedFd)
+ // i.e., the raw fd being passed will remain valid for the lifetime of
+ // the returned BorrowedFd.
+ unsafe { BorrowedFd::borrow_raw(self.pollfd.fd) }
}
}
diff --git a/src/pty.rs b/src/pty.rs
index 28ae5e9..455828b 100644
--- a/src/pty.rs
+++ b/src/pty.rs
@@ -5,37 +5,39 @@ pub use libc::winsize as Winsize;
use std::ffi::CStr;
use std::io;
+#[cfg(not(target_os = "aix"))]
use std::mem;
use std::os::unix::prelude::*;
use crate::errno::Errno;
+#[cfg(not(target_os = "aix"))]
use crate::sys::termios::Termios;
#[cfg(feature = "process")]
-use crate::unistd::{ForkResult, Pid};
+use crate::unistd::ForkResult;
+#[cfg(all(feature = "process", not(target_os = "aix")))]
+use crate::unistd::Pid;
use crate::{fcntl, unistd, Result};
/// Representation of a master/slave pty pair
///
-/// This is returned by `openpty`. Note that this type does *not* implement `Drop`, so the user
-/// must manually close the file descriptors.
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+/// This is returned by [`openpty`].
+#[derive(Debug)]
pub struct OpenptyResult {
/// The master port in a virtual pty pair
- pub master: RawFd,
+ pub master: OwnedFd,
/// The slave port in a virtual pty pair
- pub slave: RawFd,
+ pub slave: OwnedFd,
}
feature! {
#![feature = "process"]
/// Representation of a master with a forked pty
///
-/// This is returned by `forkpty`. Note that this type does *not* implement `Drop`, so the user
-/// must manually close the file descriptors.
-#[derive(Clone, Copy, Debug)]
+/// This is returned by [`forkpty`].
+#[derive(Debug)]
pub struct ForkptyResult {
/// The master port in a virtual pty pair
- pub master: RawFd,
+ pub master: OwnedFd,
/// Metadata about forked process
pub fork_result: ForkResult,
}
@@ -43,51 +45,33 @@ pub struct ForkptyResult {
/// Representation of the Master device in a master/slave pty pair
///
-/// While this datatype is a thin wrapper around `RawFd`, it enforces that the available PTY
-/// functions are given the correct file descriptor. Additionally this type implements `Drop`,
-/// so that when it's consumed or goes out of scope, it's automatically cleaned-up.
-#[derive(Debug, Eq, Hash, PartialEq)]
-pub struct PtyMaster(RawFd);
+/// While this datatype is a thin wrapper around `OwnedFd`, it enforces that the available PTY
+/// functions are given the correct file descriptor.
+#[derive(Debug)]
+pub struct PtyMaster(OwnedFd);
impl AsRawFd for PtyMaster {
fn as_raw_fd(&self) -> RawFd {
- self.0
+ self.0.as_raw_fd()
}
}
impl IntoRawFd for PtyMaster {
fn into_raw_fd(self) -> RawFd {
let fd = self.0;
- mem::forget(self);
- fd
- }
-}
-
-impl Drop for PtyMaster {
- fn drop(&mut self) {
- // On drop, we ignore errors like EINTR and EIO because there's no clear
- // way to handle them, we can't return anything, and (on FreeBSD at
- // least) the file descriptor is deallocated in these cases. However,
- // we must panic on EBADF, because it is always an error to close an
- // invalid file descriptor. That frequently indicates a double-close
- // condition, which can cause confusing errors for future I/O
- // operations.
- let e = unistd::close(self.0);
- if e == Err(Errno::EBADF) {
- panic!("Closing an invalid file descriptor!");
- };
+ fd.into_raw_fd()
}
}
impl io::Read for PtyMaster {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- unistd::read(self.0, buf).map_err(io::Error::from)
+ unistd::read(self.0.as_raw_fd(), buf).map_err(io::Error::from)
}
}
impl io::Write for PtyMaster {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- unistd::write(self.0, buf).map_err(io::Error::from)
+ unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
@@ -96,13 +80,13 @@ impl io::Write for PtyMaster {
impl io::Read for &PtyMaster {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- unistd::read(self.0, buf).map_err(io::Error::from)
+ unistd::read(self.0.as_raw_fd(), buf).map_err(io::Error::from)
}
}
impl io::Write for &PtyMaster {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- unistd::write(self.0, buf).map_err(io::Error::from)
+ unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
@@ -164,7 +148,7 @@ pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> {
return Err(Errno::last());
}
- Ok(PtyMaster(fd))
+ Ok(PtyMaster(unsafe { OwnedFd::from_raw_fd(fd) }))
}
/// Get the name of the slave pseudoterminal (see
@@ -244,6 +228,7 @@ pub fn unlockpt(fd: &PtyMaster) -> Result<()> {
/// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's
/// terminal settings of the slave will be set to the values in `termios`.
#[inline]
+#[cfg(not(target_os = "aix"))]
pub fn openpty<
'a,
'b,
@@ -308,8 +293,8 @@ pub fn openpty<
unsafe {
Ok(OpenptyResult {
- master: master.assume_init(),
- slave: slave.assume_init(),
+ master: OwnedFd::from_raw_fd(master.assume_init()),
+ slave: OwnedFd::from_raw_fd(slave.assume_init()),
})
}
}
@@ -335,6 +320,7 @@ feature! {
/// special care must be taken to only invoke code you can control and audit.
///
/// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html
+#[cfg(not(target_os = "aix"))]
pub unsafe fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>(
winsize: T,
termios: U,
@@ -364,7 +350,7 @@ pub unsafe fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b T
})?;
Ok(ForkptyResult {
- master: master.assume_init(),
+ master: OwnedFd::from_raw_fd(master.assume_init()),
fork_result,
})
}
diff --git a/src/sched.rs b/src/sched.rs
index d5b1233..c9d5d6d 100644
--- a/src/sched.rs
+++ b/src/sched.rs
@@ -16,7 +16,7 @@ mod sched_linux_like {
use libc::{self, c_int, c_void};
use std::mem;
use std::option::Option;
- use std::os::unix::io::RawFd;
+ use std::os::unix::io::{AsFd, AsRawFd};
// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
@@ -95,7 +95,17 @@ mod sched_linux_like {
/// address need not be the highest address of the region. Nix will take
/// care of that requirement. The user only needs to provide a reference to
/// a normally allocated buffer.
- pub fn clone(
+ ///
+ /// # Safety
+ ///
+ /// Because `clone` creates a child process with its stack located in
+ /// `stack` without specifying the size of the stack, special care must be
+ /// taken to ensure that the child process does not overflow the provided
+ /// stack space.
+ ///
+ /// See [`fork`](crate::unistd::fork) for additional safety concerns related
+ /// to executing child processes.
+ pub unsafe fn clone(
mut cb: CloneCb,
stack: &mut [u8],
flags: CloneFlags,
@@ -106,20 +116,18 @@ mod sched_linux_like {
(*cb)() as c_int
}
- let res = unsafe {
- let combined = flags.bits() | signal.unwrap_or(0);
- let ptr = stack.as_mut_ptr().add(stack.len());
- let ptr_aligned = ptr.sub(ptr as usize % 16);
- libc::clone(
- mem::transmute(
- callback
- as extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32,
- ),
- ptr_aligned as *mut c_void,
- combined,
- &mut cb as *mut _ as *mut c_void,
- )
- };
+ let combined = flags.bits() | signal.unwrap_or(0);
+ let ptr = stack.as_mut_ptr().add(stack.len());
+ let ptr_aligned = ptr.sub(ptr as usize % 16);
+ let res = libc::clone(
+ mem::transmute(
+ callback
+ as extern "C" fn(*mut Box<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)
}
@@ -136,8 +144,8 @@ mod sched_linux_like {
/// reassociate thread with a namespace
///
/// See also [setns(2)](https://man7.org/linux/man-pages/man2/setns.2.html)
- pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
- let res = unsafe { libc::setns(fd, nstype.bits()) };
+ pub fn setns<Fd: AsFd>(fd: Fd, nstype: CloneFlags) -> Result<()> {
+ let res = unsafe { libc::setns(fd.as_fd().as_raw_fd(), nstype.bits()) };
Errno::result(res).map(drop)
}
diff --git a/src/sys/aio.rs b/src/sys/aio.rs
index e2ce19b..5471177 100644
--- a/src/sys/aio.rs
+++ b/src/sys/aio.rs
@@ -163,7 +163,7 @@ impl AioCb {
0 => Ok(()),
num if num > 0 => Err(Errno::from_i32(num)),
-1 => Err(Errno::last()),
- num => panic!("unknown aio_error return value {:?}", num),
+ num => panic!("unknown aio_error return value {num:?}"),
}
}
@@ -1051,8 +1051,14 @@ pub fn aio_suspend(
list: &[&dyn AsRef<libc::aiocb>],
timeout: Option<TimeSpec>,
) -> Result<()> {
- let p = list as *const [&dyn AsRef<libc::aiocb>]
- as *const [*const libc::aiocb] as *const *const libc::aiocb;
+ // Note that this allocation could be eliminated by making the argument
+ // generic, and accepting arguments like &[AioWrite]. But that would
+ // prevent using aio_suspend to wait on a heterogeneous list of mixed
+ // operations.
+ let v = list.iter()
+ .map(|x| x.as_ref() as *const libc::aiocb)
+ .collect::<Vec<*const libc::aiocb>>();
+ let p = v.as_ptr();
let timep = match timeout {
None => ptr::null::<libc::timespec>(),
Some(x) => x.as_ref() as *const libc::timespec,
@@ -1136,14 +1142,11 @@ pub fn aio_suspend(
/// # use std::sync::atomic::{AtomicBool, Ordering};
/// # use std::thread;
/// # use std::time;
-/// # use lazy_static::lazy_static;
/// # use nix::errno::Errno;
/// # use nix::sys::aio::*;
/// # use nix::sys::signal::*;
/// # use tempfile::tempfile;
-/// lazy_static! {
-/// pub static ref SIGNALED: AtomicBool = AtomicBool::new(false);
-/// }
+/// pub static SIGNALED: AtomicBool = AtomicBool::new(false);
///
/// extern fn sigfunc(_: c_int) {
/// SIGNALED.store(true, Ordering::Relaxed);
@@ -1172,6 +1175,7 @@ pub fn aio_suspend(
/// // notification, we know that all operations are complete.
/// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len());
/// ```
+#[deprecated(since = "0.27.0", note = "https://github.com/nix-rust/nix/issues/2017")]
pub fn lio_listio(
mode: LioMode,
list: &mut [Pin<&mut dyn AsMut<libc::aiocb>>],
diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs
index 58def2e..36f9c17 100644
--- a/src/sys/epoll.rs
+++ b/src/sys/epoll.rs
@@ -2,8 +2,7 @@ use crate::errno::Errno;
use crate::Result;
use libc::{self, c_int};
use std::mem;
-use std::os::unix::io::RawFd;
-use std::ptr;
+use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd};
libc_bitflags!(
pub struct EpollFlags: c_int {
@@ -70,6 +69,126 @@ impl EpollEvent {
}
}
+/// A safe wrapper around [`epoll`](https://man7.org/linux/man-pages/man7/epoll.7.html).
+/// ```
+/// # use nix::sys::{epoll::{Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{eventfd, EfdFlags}};
+/// # use nix::unistd::write;
+/// # use std::os::unix::io::{OwnedFd, FromRawFd, AsRawFd, AsFd};
+/// # use std::time::{Instant, Duration};
+/// # fn main() -> nix::Result<()> {
+/// const DATA: u64 = 17;
+/// const MILLIS: u64 = 100;
+///
+/// // Create epoll
+/// let epoll = Epoll::new(EpollCreateFlags::empty())?;
+///
+/// // Create eventfd & Add event
+/// let eventfd = eventfd(0, EfdFlags::empty())?;
+/// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?;
+///
+/// // Arm eventfd & Time wait
+/// write(eventfd.as_raw_fd(), &1u64.to_ne_bytes())?;
+/// let now = Instant::now();
+///
+/// // Wait on event
+/// let mut events = [EpollEvent::empty()];
+/// epoll.wait(&mut events, MILLIS as isize)?;
+///
+/// // Assert data correct & timeout didn't occur
+/// assert_eq!(events[0].data(), DATA);
+/// assert!(now.elapsed() < Duration::from_millis(MILLIS));
+/// # Ok(())
+/// # }
+/// ```
+#[derive(Debug)]
+pub struct Epoll(pub OwnedFd);
+impl Epoll {
+ /// Creates a new epoll instance and returns a file descriptor referring to that instance.
+ ///
+ /// [`epoll_create1`](https://man7.org/linux/man-pages/man2/epoll_create1.2.html).
+ pub fn new(flags: EpollCreateFlags) -> Result<Self> {
+ let res = unsafe { libc::epoll_create1(flags.bits()) };
+ let fd = Errno::result(res)?;
+ let owned_fd = unsafe { OwnedFd::from_raw_fd(fd) };
+ Ok(Self(owned_fd))
+ }
+ /// Add an entry to the interest list of the epoll file descriptor for
+ /// specified in events.
+ ///
+ /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_ADD`.
+ pub fn add<Fd: AsFd>(&self, fd: Fd, mut event: EpollEvent) -> Result<()> {
+ self.epoll_ctl(EpollOp::EpollCtlAdd, fd, &mut event)
+ }
+ /// Remove (deregister) the target file descriptor `fd` from the interest list.
+ ///
+ /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_DEL` .
+ pub fn delete<Fd: AsFd>(&self, fd: Fd) -> Result<()> {
+ self.epoll_ctl(EpollOp::EpollCtlDel, fd, None)
+ }
+ /// Change the settings associated with `fd` in the interest list to the new settings specified
+ /// in `event`.
+ ///
+ /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_MOD`.
+ pub fn modify<Fd: AsFd>(
+ &self,
+ fd: Fd,
+ event: &mut EpollEvent,
+ ) -> Result<()> {
+ self.epoll_ctl(EpollOp::EpollCtlMod, fd, event)
+ }
+ /// Waits for I/O events, blocking the calling thread if no events are currently available.
+ /// (This can be thought of as fetching items from the ready list of the epoll instance.)
+ ///
+ /// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html)
+ pub fn wait(
+ &self,
+ events: &mut [EpollEvent],
+ timeout: isize,
+ ) -> Result<usize> {
+ let res = unsafe {
+ libc::epoll_wait(
+ self.0.as_raw_fd(),
+ events.as_mut_ptr() as *mut libc::epoll_event,
+ events.len() as c_int,
+ timeout as c_int,
+ )
+ };
+
+ Errno::result(res).map(|r| r as usize)
+ }
+ /// This system call is used to add, modify, or remove entries in the interest list of the epoll
+ /// instance referred to by `self`. It requests that the operation `op` be performed for the
+ /// target file descriptor, `fd`.
+ ///
+ /// When possible prefer [`Epoll::add`], [`Epoll::delete`] and [`Epoll::modify`].
+ ///
+ /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html)
+ fn epoll_ctl<'a, Fd: AsFd, T>(
+ &self,
+ op: EpollOp,
+ fd: Fd,
+ event: T,
+ ) -> Result<()>
+ where
+ T: Into<Option<&'a mut EpollEvent>>,
+ {
+ let event: Option<&mut EpollEvent> = event.into();
+ let ptr = event
+ .map(|x| &mut x.event as *mut libc::epoll_event)
+ .unwrap_or(std::ptr::null_mut());
+ unsafe {
+ Errno::result(libc::epoll_ctl(
+ self.0.as_raw_fd(),
+ op as c_int,
+ fd.as_fd().as_raw_fd(),
+ ptr,
+ ))
+ .map(drop)
+ }
+ }
+}
+
+#[deprecated(since = "0.27.0", note = "Use Epoll::new() instead")]
#[inline]
pub fn epoll_create() -> Result<RawFd> {
let res = unsafe { libc::epoll_create(1024) };
@@ -77,6 +196,7 @@ pub fn epoll_create() -> Result<RawFd> {
Errno::result(res)
}
+#[deprecated(since = "0.27.0", note = "Use Epoll::new() instead")]
#[inline]
pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
let res = unsafe { libc::epoll_create1(flags.bits()) };
@@ -84,6 +204,7 @@ pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
Errno::result(res)
}
+#[deprecated(since = "0.27.0", note = "Use Epoll::epoll_ctl() instead")]
#[inline]
pub fn epoll_ctl<'a, T>(
epfd: RawFd,
@@ -102,13 +223,14 @@ where
if let Some(ref mut event) = event {
libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event)
} else {
- libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut())
+ libc::epoll_ctl(epfd, op as c_int, fd, std::ptr::null_mut())
}
};
Errno::result(res).map(drop)
}
}
+#[deprecated(since = "0.27.0", note = "Use Epoll::wait() instead")]
#[inline]
pub fn epoll_wait(
epfd: RawFd,
diff --git a/src/sys/event.rs b/src/sys/event.rs
index d8ad628..ec7f7e2 100644
--- a/src/sys/event.rs
+++ b/src/sys/event.rs
@@ -1,5 +1,7 @@
-/* TOOD: Implement for other kqueue based systems
- */
+//! Kernel event notification mechanism
+//!
+//! # See Also
+//! [kqueue(2)](https://www.freebsd.org/cgi/man.cgi?query=kqueue)
use crate::{Errno, Result};
#[cfg(not(target_os = "netbsd"))]
@@ -8,16 +10,74 @@ use libc::{c_int, c_long, intptr_t, time_t, timespec, uintptr_t};
use libc::{c_long, intptr_t, size_t, time_t, timespec, uintptr_t};
use std::convert::TryInto;
use std::mem;
-use std::os::unix::io::RawFd;
+use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd};
use std::ptr;
-// Redefine kevent in terms of programmer-friendly enums and bitfields.
+/// A kernel event queue. Used to notify a process of various asynchronous
+/// events.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct KEvent {
kevent: libc::kevent,
}
+/// A kernel event queue.
+///
+/// Used by the kernel to notify the process of various types of asynchronous
+/// events.
+#[repr(transparent)]
+#[derive(Debug)]
+pub struct Kqueue(OwnedFd);
+
+impl Kqueue {
+ /// Create a new kernel event queue.
+ pub fn new() -> Result<Self> {
+ let res = unsafe { libc::kqueue() };
+
+ Errno::result(res).map(|fd| unsafe { Self(OwnedFd::from_raw_fd(fd)) })
+ }
+
+ /// Register new events with the kqueue, and return any pending events to
+ /// the user.
+ ///
+ /// This method will block until either the timeout expires, or a registered
+ /// event triggers a notification.
+ ///
+ /// # Arguments
+ /// - `changelist` - Any new kevents to register for notifications.
+ /// - `eventlist` - Storage space for the kernel to return notifications.
+ /// - `timeout` - An optional timeout.
+ ///
+ /// # Returns
+ /// Returns the number of events placed in the `eventlist`. If an error
+ /// occurs while processing an element of the `changelist` and there is
+ /// enough room in the `eventlist`, then the event will be placed in the
+ /// `eventlist` with `EV_ERROR` set in `flags` and the system error in
+ /// `data`.
+ pub fn kevent(
+ &self,
+ changelist: &[KEvent],
+ eventlist: &mut [KEvent],
+ timeout_opt: Option<timespec>,
+ ) -> Result<usize> {
+ let res = unsafe {
+ libc::kevent(
+ self.0.as_raw_fd(),
+ changelist.as_ptr() as *const libc::kevent,
+ changelist.len() as type_of_nchanges,
+ eventlist.as_mut_ptr() as *mut libc::kevent,
+ eventlist.len() as type_of_nchanges,
+ if let Some(ref timeout) = timeout_opt {
+ timeout as *const timespec
+ } else {
+ ptr::null()
+ },
+ )
+ };
+ Errno::result(res).map(|r| r as usize)
+ }
+}
+
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
@@ -26,7 +86,7 @@ pub struct KEvent {
target_os = "openbsd"
))]
type type_of_udata = *mut libc::c_void;
-#[cfg(any(target_os = "netbsd"))]
+#[cfg(target_os = "netbsd")]
type type_of_udata = intptr_t;
#[cfg(target_os = "netbsd")]
@@ -37,22 +97,34 @@ libc_enum! {
#[cfg_attr(target_os = "netbsd", repr(u32))]
#[cfg_attr(not(target_os = "netbsd"), repr(i16))]
#[non_exhaustive]
+ /// Kqueue filter types. These are all the different types of event that a
+ /// kqueue can notify for.
pub enum EventFilter {
+ /// Notifies on the completion of a POSIX AIO operation.
EVFILT_AIO,
- /// Returns whenever there is no remaining data in the write buffer
#[cfg(target_os = "freebsd")]
+ /// Returns whenever there is no remaining data in the write buffer
EVFILT_EMPTY,
#[cfg(target_os = "dragonfly")]
+ /// Takes a descriptor as the identifier, and returns whenever one of
+ /// the specified exceptional conditions has occurred on the descriptor.
EVFILT_EXCEPT,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos"))]
+ /// Establishes a file system monitor.
EVFILT_FS,
#[cfg(target_os = "freebsd")]
+ /// Notify for completion of a list of POSIX AIO operations.
+ /// # See Also
+ /// [lio_listio(2)](https://www.freebsd.org/cgi/man.cgi?query=lio_listio)
EVFILT_LIO,
#[cfg(any(target_os = "ios", target_os = "macos"))]
+ /// Mach portsets
EVFILT_MACHPORT,
+ /// Notifies when a process performs one or more of the requested
+ /// events.
EVFILT_PROC,
/// Returns events associated with the process referenced by a given
/// process descriptor, created by `pdfork()`. The events to monitor are:
@@ -60,20 +132,31 @@ libc_enum! {
/// - NOTE_EXIT: the process has exited. The exit status will be stored in data.
#[cfg(target_os = "freebsd")]
EVFILT_PROCDESC,
+ /// Takes a file descriptor as the identifier, and notifies whenever
+ /// there is data available to read.
EVFILT_READ,
- /// Returns whenever an asynchronous `sendfile()` call completes.
#[cfg(target_os = "freebsd")]
+ #[doc(hidden)]
+ #[deprecated(since = "0.27.0", note = "Never fully implemented by the OS")]
EVFILT_SENDFILE,
+ /// Takes a signal number to monitor as the identifier and notifies when
+ /// the given signal is delivered to the process.
EVFILT_SIGNAL,
+ /// Establishes a timer and notifies when the timer expires.
EVFILT_TIMER,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos"))]
+ /// Notifies only when explicitly requested by the user.
EVFILT_USER,
#[cfg(any(target_os = "ios", target_os = "macos"))]
+ /// Virtual memory events
EVFILT_VM,
+ /// Notifies when a requested event happens on a specified file.
EVFILT_VNODE,
+ /// Takes a file descriptor as the identifier, and notifies whenever
+ /// it is possible to write to the file without blocking.
EVFILT_WRITE,
}
impl TryFrom<type_of_event_filter>
@@ -86,131 +169,194 @@ libc_enum! {
target_os = "macos",
target_os = "openbsd"
))]
+#[doc(hidden)]
pub type type_of_event_flag = u16;
-#[cfg(any(target_os = "netbsd"))]
+#[cfg(target_os = "netbsd")]
+#[doc(hidden)]
pub type type_of_event_flag = u32;
libc_bitflags! {
+ /// Event flags. See the man page for details.
+ // There's no useful documentation we can write for the individual flags
+ // that wouldn't simply be repeating the man page.
pub struct EventFlag: type_of_event_flag {
+ #[allow(missing_docs)]
EV_ADD;
+ #[allow(missing_docs)]
EV_CLEAR;
+ #[allow(missing_docs)]
EV_DELETE;
+ #[allow(missing_docs)]
EV_DISABLE;
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "netbsd", target_os = "openbsd"))]
+ #[allow(missing_docs)]
EV_DISPATCH;
#[cfg(target_os = "freebsd")]
+ #[allow(missing_docs)]
EV_DROP;
+ #[allow(missing_docs)]
EV_ENABLE;
+ #[allow(missing_docs)]
EV_EOF;
+ #[allow(missing_docs)]
EV_ERROR;
#[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[allow(missing_docs)]
EV_FLAG0;
+ #[allow(missing_docs)]
EV_FLAG1;
#[cfg(target_os = "dragonfly")]
+ #[allow(missing_docs)]
EV_NODATA;
+ #[allow(missing_docs)]
EV_ONESHOT;
#[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[allow(missing_docs)]
EV_OOBAND;
#[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[allow(missing_docs)]
EV_POLL;
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "netbsd", target_os = "openbsd"))]
+ #[allow(missing_docs)]
EV_RECEIPT;
}
}
libc_bitflags!(
+ /// Filter-specific flags. See the man page for details.
+ // There's no useful documentation we can write for the individual flags
+ // that wouldn't simply be repeating the man page.
+ #[allow(missing_docs)]
pub struct FilterFlag: u32 {
#[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[allow(missing_docs)]
NOTE_ABSOLUTE;
+ #[allow(missing_docs)]
NOTE_ATTRIB;
+ #[allow(missing_docs)]
NOTE_CHILD;
+ #[allow(missing_docs)]
NOTE_DELETE;
#[cfg(target_os = "openbsd")]
+ #[allow(missing_docs)]
NOTE_EOF;
+ #[allow(missing_docs)]
NOTE_EXEC;
+ #[allow(missing_docs)]
NOTE_EXIT;
#[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[allow(missing_docs)]
NOTE_EXITSTATUS;
+ #[allow(missing_docs)]
NOTE_EXTEND;
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "dragonfly"))]
+ #[allow(missing_docs)]
NOTE_FFAND;
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "dragonfly"))]
+ #[allow(missing_docs)]
NOTE_FFCOPY;
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "dragonfly"))]
+ #[allow(missing_docs)]
NOTE_FFCTRLMASK;
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "dragonfly"))]
+ #[allow(missing_docs)]
NOTE_FFLAGSMASK;
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "dragonfly"))]
+ #[allow(missing_docs)]
NOTE_FFNOP;
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "dragonfly"))]
+ #[allow(missing_docs)]
NOTE_FFOR;
+ #[allow(missing_docs)]
NOTE_FORK;
+ #[allow(missing_docs)]
NOTE_LINK;
+ #[allow(missing_docs)]
NOTE_LOWAT;
#[cfg(target_os = "freebsd")]
+ #[allow(missing_docs)]
NOTE_MSECONDS;
#[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[allow(missing_docs)]
NOTE_NONE;
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
+ #[allow(missing_docs)]
NOTE_NSECONDS;
#[cfg(target_os = "dragonfly")]
+ #[allow(missing_docs)]
NOTE_OOB;
+ #[allow(missing_docs)]
NOTE_PCTRLMASK;
+ #[allow(missing_docs)]
NOTE_PDATAMASK;
+ #[allow(missing_docs)]
NOTE_RENAME;
+ #[allow(missing_docs)]
NOTE_REVOKE;
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
+ #[allow(missing_docs)]
NOTE_SECONDS;
#[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[allow(missing_docs)]
NOTE_SIGNAL;
+ #[allow(missing_docs)]
NOTE_TRACK;
+ #[allow(missing_docs)]
NOTE_TRACKERR;
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "dragonfly"))]
+ #[allow(missing_docs)]
NOTE_TRIGGER;
#[cfg(target_os = "openbsd")]
+ #[allow(missing_docs)]
NOTE_TRUNCATE;
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
+ #[allow(missing_docs)]
NOTE_USECONDS;
#[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[allow(missing_docs)]
NOTE_VM_ERROR;
#[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[allow(missing_docs)]
NOTE_VM_PRESSURE;
#[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[allow(missing_docs)]
NOTE_VM_PRESSURE_SUDDEN_TERMINATE;
#[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[allow(missing_docs)]
NOTE_VM_PRESSURE_TERMINATE;
+ #[allow(missing_docs)]
NOTE_WRITE;
}
);
-pub fn kqueue() -> Result<RawFd> {
- let res = unsafe { libc::kqueue() };
-
- Errno::result(res)
+#[allow(missing_docs)]
+#[deprecated(since = "0.27.0", note = "Use KEvent::new instead")]
+pub fn kqueue() -> Result<Kqueue> {
+ Kqueue::new()
}
// KEvent can't derive Send because on some operating systems, udata is defined
@@ -220,6 +366,8 @@ unsafe impl Send for KEvent {}
impl KEvent {
#[allow(clippy::needless_update)] // Not needless on all platforms.
+ /// Construct a new `KEvent` suitable for submission to the kernel via the
+ /// `changelist` argument of [`Kqueue::kevent`].
pub fn new(
ident: uintptr_t,
filter: EventFilter,
@@ -242,33 +390,46 @@ impl KEvent {
}
}
+ /// Value used to identify this event. The exact interpretation is
+ /// determined by the attached filter, but often is a raw file descriptor.
pub fn ident(&self) -> uintptr_t {
self.kevent.ident
}
+ /// Identifies the kernel filter used to process this event.
+ ///
+ /// Will only return an error if the kernel reports an event via a filter
+ /// that is unknown to Nix.
pub fn filter(&self) -> Result<EventFilter> {
self.kevent.filter.try_into()
}
+ /// Flags control what the kernel will do when this event is added with
+ /// [`Kqueue::kevent`].
pub fn flags(&self) -> EventFlag {
EventFlag::from_bits(self.kevent.flags).unwrap()
}
+ /// Filter-specific flags.
pub fn fflags(&self) -> FilterFlag {
FilterFlag::from_bits(self.kevent.fflags).unwrap()
}
+ /// Filter-specific data value.
pub fn data(&self) -> intptr_t {
self.kevent.data as intptr_t
}
+ /// Opaque user-defined value passed through the kernel unchanged.
pub fn udata(&self) -> intptr_t {
self.kevent.udata as intptr_t
}
}
+#[allow(missing_docs)]
+#[deprecated(since = "0.27.0", note = "Use Kqueue::kevent instead")]
pub fn kevent(
- kq: RawFd,
+ kq: &Kqueue,
changelist: &[KEvent],
eventlist: &mut [KEvent],
timeout_ms: usize,
@@ -279,7 +440,7 @@ pub fn kevent(
tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long,
};
- kevent_ts(kq, changelist, eventlist, Some(timeout))
+ kq.kevent(changelist, eventlist, Some(timeout))
}
#[cfg(any(
@@ -293,30 +454,20 @@ type type_of_nchanges = c_int;
#[cfg(target_os = "netbsd")]
type type_of_nchanges = size_t;
+#[allow(missing_docs)]
+#[deprecated(since = "0.27.0", note = "Use Kqueue::kevent instead")]
pub fn kevent_ts(
- kq: RawFd,
+ kq: &Kqueue,
changelist: &[KEvent],
eventlist: &mut [KEvent],
timeout_opt: Option<timespec>,
) -> Result<usize> {
- let res = unsafe {
- libc::kevent(
- kq,
- changelist.as_ptr() as *const libc::kevent,
- changelist.len() as type_of_nchanges,
- eventlist.as_mut_ptr() as *mut libc::kevent,
- eventlist.len() as type_of_nchanges,
- if let Some(ref timeout) = timeout_opt {
- timeout as *const timespec
- } else {
- ptr::null()
- },
- )
- };
-
- Errno::result(res).map(|r| r as usize)
+ kq.kevent(changelist, eventlist, timeout_opt)
}
+/// Modify an existing [`KEvent`].
+// Probably should deprecate. Would anybody ever use it over `KEvent::new`?
+#[deprecated(since = "0.27.0", note = "Use Kqueue::kevent instead")]
#[inline]
pub fn ev_set(
ev: &mut KEvent,
diff --git a/src/sys/eventfd.rs b/src/sys/eventfd.rs
index cd90672..f172351 100644
--- a/src/sys/eventfd.rs
+++ b/src/sys/eventfd.rs
@@ -1,6 +1,6 @@
use crate::errno::Errno;
use crate::Result;
-use std::os::unix::io::RawFd;
+use std::os::unix::io::{FromRawFd, OwnedFd};
libc_bitflags! {
pub struct EfdFlags: libc::c_int {
@@ -10,8 +10,8 @@ libc_bitflags! {
}
}
-pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd> {
+pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<OwnedFd> {
let res = unsafe { libc::eventfd(initval, flags.bits()) };
- Errno::result(res).map(|r| r as RawFd)
+ Errno::result(res).map(|r| unsafe { OwnedFd::from_raw_fd(r) })
}
diff --git a/src/sys/inotify.rs b/src/sys/inotify.rs
index 84356ec..e5fe930 100644
--- a/src/sys/inotify.rs
+++ b/src/sys/inotify.rs
@@ -32,7 +32,7 @@ use libc::{c_char, c_int};
use std::ffi::{CStr, OsStr, OsString};
use std::mem::{size_of, MaybeUninit};
use std::os::unix::ffi::OsStrExt;
-use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
use std::ptr;
libc_bitflags! {
@@ -101,9 +101,9 @@ libc_bitflags! {
/// An inotify instance. This is also a file descriptor, you can feed it to
/// other interfaces consuming file descriptors, epoll for example.
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug)]
pub struct Inotify {
- fd: RawFd,
+ fd: OwnedFd,
}
/// This object is returned when you create a new watch on an inotify instance.
@@ -143,7 +143,7 @@ impl Inotify {
pub fn init(flags: InitFlags) -> Result<Inotify> {
let res = Errno::result(unsafe { libc::inotify_init1(flags.bits()) });
- res.map(|fd| Inotify { fd })
+ res.map(|fd| Inotify { fd: unsafe { OwnedFd::from_raw_fd(fd) } })
}
/// Adds a new watch on the target file or directory.
@@ -152,12 +152,12 @@ impl Inotify {
///
/// For more information see, [inotify_add_watch(2)](https://man7.org/linux/man-pages/man2/inotify_add_watch.2.html).
pub fn add_watch<P: ?Sized + NixPath>(
- self,
+ &self,
path: &P,
mask: AddWatchFlags,
) -> Result<WatchDescriptor> {
let res = path.with_nix_path(|cstr| unsafe {
- libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits())
+ libc::inotify_add_watch(self.fd.as_raw_fd(), cstr.as_ptr(), mask.bits())
})?;
Errno::result(res).map(|wd| WatchDescriptor { wd })
@@ -169,7 +169,7 @@ impl Inotify {
/// Returns an EINVAL error if the watch descriptor is invalid.
///
/// For more information see, [inotify_rm_watch(2)](https://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html).
- pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> {
+ pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> {
cfg_if! {
if #[cfg(target_os = "linux")] {
let arg = wd.wd;
@@ -177,7 +177,7 @@ impl Inotify {
let arg = wd.wd as u32;
}
}
- let res = unsafe { libc::inotify_rm_watch(self.fd, arg) };
+ let res = unsafe { libc::inotify_rm_watch(self.fd.as_raw_fd(), arg) };
Errno::result(res).map(drop)
}
@@ -188,14 +188,14 @@ impl Inotify {
///
/// Returns as many events as available. If the call was non blocking and no
/// events could be read then the EAGAIN error is returned.
- pub fn read_events(self) -> Result<Vec<InotifyEvent>> {
+ pub fn read_events(&self) -> Result<Vec<InotifyEvent>> {
let header_size = size_of::<libc::inotify_event>();
const BUFSIZ: usize = 4096;
let mut buffer = [0u8; BUFSIZ];
let mut events = Vec::new();
let mut offset = 0;
- let nread = read(self.fd, &mut buffer)?;
+ let nread = read(self.fd.as_raw_fd(), &mut buffer)?;
while (nread - offset) >= header_size {
let event = unsafe {
@@ -235,14 +235,14 @@ impl Inotify {
}
}
-impl AsRawFd for Inotify {
- fn as_raw_fd(&self) -> RawFd {
- self.fd
+impl FromRawFd for Inotify {
+ unsafe fn from_raw_fd(fd: RawFd) -> Self {
+ Inotify { fd: OwnedFd::from_raw_fd(fd) }
}
}
-impl FromRawFd for Inotify {
- unsafe fn from_raw_fd(fd: RawFd) -> Self {
- Inotify { fd }
+impl AsFd for Inotify {
+ fn as_fd(&'_ self) -> BorrowedFd<'_> {
+ self.fd.as_fd()
}
}
diff --git a/src/sys/ioctl/linux.rs b/src/sys/ioctl/linux.rs
index 0c0a209..610b8dd 100644
--- a/src/sys/ioctl/linux.rs
+++ b/src/sys/ioctl/linux.rs
@@ -1,3 +1,5 @@
+use cfg_if::cfg_if;
+
/// The datatype used for the ioctl number
#[cfg(any(target_os = "android", target_env = "musl"))]
#[doc(hidden)]
@@ -14,47 +16,41 @@ pub const NRBITS: ioctl_num_type = 8;
#[doc(hidden)]
pub const TYPEBITS: ioctl_num_type = 8;
-#[cfg(any(
- target_arch = "mips",
- target_arch = "mips64",
- target_arch = "powerpc",
- target_arch = "powerpc64",
- target_arch = "sparc64"
-))]
-mod consts {
- #[doc(hidden)]
- pub const NONE: u8 = 1;
- #[doc(hidden)]
- pub const READ: u8 = 2;
- #[doc(hidden)]
- pub const WRITE: u8 = 4;
- #[doc(hidden)]
- pub const SIZEBITS: u8 = 13;
- #[doc(hidden)]
- pub const DIRBITS: u8 = 3;
-}
-
-// "Generic" ioctl protocol
-#[cfg(any(
- target_arch = "x86",
- target_arch = "arm",
- target_arch = "s390x",
- target_arch = "x86_64",
- target_arch = "aarch64",
- target_arch = "riscv32",
- target_arch = "riscv64"
-))]
-mod consts {
- #[doc(hidden)]
- pub const NONE: u8 = 0;
- #[doc(hidden)]
- pub const READ: u8 = 2;
- #[doc(hidden)]
- pub const WRITE: u8 = 1;
- #[doc(hidden)]
- pub const SIZEBITS: u8 = 14;
- #[doc(hidden)]
- pub const DIRBITS: u8 = 2;
+cfg_if! {
+ if #[cfg(any(
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "sparc64"
+ ))] {
+ mod consts {
+ #[doc(hidden)]
+ pub const NONE: u8 = 1;
+ #[doc(hidden)]
+ pub const READ: u8 = 2;
+ #[doc(hidden)]
+ pub const WRITE: u8 = 4;
+ #[doc(hidden)]
+ pub const SIZEBITS: u8 = 13;
+ #[doc(hidden)]
+ pub const DIRBITS: u8 = 3;
+ }
+ } else {
+ // "Generic" ioctl protocol
+ mod consts {
+ #[doc(hidden)]
+ pub const NONE: u8 = 0;
+ #[doc(hidden)]
+ pub const READ: u8 = 2;
+ #[doc(hidden)]
+ pub const WRITE: u8 = 1;
+ #[doc(hidden)]
+ pub const SIZEBITS: u8 = 14;
+ #[doc(hidden)]
+ pub const DIRBITS: u8 = 2;
+ }
+ }
}
pub use self::consts::*;
diff --git a/src/sys/ioctl/mod.rs b/src/sys/ioctl/mod.rs
index 98d6b5c..0b3fe3e 100644
--- a/src/sys/ioctl/mod.rs
+++ b/src/sys/ioctl/mod.rs
@@ -712,7 +712,7 @@ macro_rules! ioctl_read_buf {
pub unsafe fn $name(fd: $crate::libc::c_int,
data: &mut [$ty])
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data))
}
)
}
@@ -751,7 +751,7 @@ macro_rules! ioctl_write_buf {
pub unsafe fn $name(fd: $crate::libc::c_int,
data: &[$ty])
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data))
}
)
}
@@ -780,7 +780,7 @@ macro_rules! ioctl_readwrite_buf {
pub unsafe fn $name(fd: $crate::libc::c_int,
data: &mut [$ty])
-> $crate::Result<$crate::libc::c_int> {
- convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data))
}
)
}
diff --git a/src/sys/memfd.rs b/src/sys/memfd.rs
index e43e1e5..d147ccf 100644
--- a/src/sys/memfd.rs
+++ b/src/sys/memfd.rs
@@ -1,7 +1,7 @@
//! Interfaces for managing memory-backed files.
use cfg_if::cfg_if;
-use std::os::unix::io::RawFd;
+use std::os::unix::io::{FromRawFd, OwnedFd, RawFd};
use crate::errno::Errno;
use crate::Result;
@@ -40,7 +40,8 @@ libc_bitflags!(
/// For more information, see [`memfd_create(2)`].
///
/// [`memfd_create(2)`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html
-pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> {
+#[inline] // Delays codegen, preventing linker errors with dylibs and --no-allow-shlib-undefined
+pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<OwnedFd> {
let res = unsafe {
cfg_if! {
if #[cfg(all(
@@ -62,5 +63,5 @@ pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> {
}
};
- Errno::result(res).map(|r| r as RawFd)
+ Errno::result(res).map(|r| unsafe { OwnedFd::from_raw_fd(r as RawFd) })
}
diff --git a/src/sys/mman.rs b/src/sys/mman.rs
index 2bee091..8cfd6d6 100644
--- a/src/sys/mman.rs
+++ b/src/sys/mman.rs
@@ -8,7 +8,7 @@ use crate::Result;
#[cfg(feature = "fs")]
use crate::{fcntl::OFlag, sys::stat::Mode};
use libc::{self, c_int, c_void, off_t, size_t};
-use std::{os::unix::io::RawFd, num::NonZeroUsize};
+use std::{num::NonZeroUsize, os::unix::io::{AsRawFd, AsFd}};
libc_bitflags! {
/// Desired memory protection of a memory mapping.
@@ -82,7 +82,7 @@ libc_bitflags! {
/// Do not reserve swap space for this mapping.
///
/// This was removed in FreeBSD 11 and is unused in DragonFlyBSD.
- #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))]
+ #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", target_os = "aix")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
MAP_NORESERVE;
/// Populate page tables for a mapping.
@@ -282,6 +282,8 @@ libc_enum! {
#[cfg_attr(docsrs, doc(cfg(all())))]
MADV_DODUMP,
/// Specify that the application no longer needs the pages in the given range.
+ #[cfg(not(target_os = "aix"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
MADV_FREE,
/// Request that the system not flush the current range to disk unless it needs to.
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
@@ -416,20 +418,20 @@ pub fn munlockall() -> Result<()> {
/// See the [`mmap(2)`] man page for detailed requirements.
///
/// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html
-pub unsafe fn mmap(
+pub unsafe fn mmap<F: AsFd>(
addr: Option<NonZeroUsize>,
length: NonZeroUsize,
prot: ProtFlags,
flags: MapFlags,
- fd: RawFd,
+ f: Option<F>,
offset: off_t,
) -> Result<*mut c_void> {
- let ptr = addr.map_or(
- std::ptr::null_mut(),
- |a| usize::from(a) as *mut c_void
- );
-
- let ret = libc::mmap(ptr, length.into(), prot.bits(), flags.bits(), fd, offset);
+ let ptr =
+ addr.map_or(std::ptr::null_mut(), |a| usize::from(a) as *mut c_void);
+
+ let 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);
if ret == libc::MAP_FAILED {
Err(Errno::last())
@@ -519,11 +521,12 @@ pub unsafe fn madvise(
/// # use nix::libc::size_t;
/// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags};
/// # use std::ptr;
+/// # use std::os::unix::io::BorrowedFd;
/// const ONE_K: size_t = 1024;
/// let one_k_non_zero = std::num::NonZeroUsize::new(ONE_K).unwrap();
/// let mut slice: &mut [u8] = unsafe {
-/// let mem = mmap(None, one_k_non_zero, ProtFlags::PROT_NONE,
-/// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap();
+/// let mem = mmap::<BorrowedFd>(None, one_k_non_zero, ProtFlags::PROT_NONE,
+/// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, None, 0).unwrap();
/// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap();
/// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
/// };
@@ -567,9 +570,11 @@ pub fn shm_open<P>(
name: &P,
flag: OFlag,
mode: Mode
- ) -> Result<RawFd>
+ ) -> Result<std::os::unix::io::OwnedFd>
where P: ?Sized + NixPath
{
+ use std::os::unix::io::{FromRawFd, OwnedFd};
+
let ret = name.with_nix_path(|cstr| {
#[cfg(any(target_os = "macos", target_os = "ios"))]
unsafe {
@@ -581,7 +586,10 @@ pub fn shm_open<P>(
}
})?;
- Errno::result(ret)
+ match ret {
+ -1 => Err(Errno::last()),
+ fd => Ok(unsafe{ OwnedFd::from_raw_fd(fd) })
+ }
}
}
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index 2065059..bf047b3 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -25,7 +25,6 @@ feature! {
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
- #[allow(missing_docs)]
pub mod event;
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -68,6 +67,12 @@ feature! {
pub mod personality;
}
+#[cfg(target_os = "linux")]
+feature! {
+ #![feature = "process"]
+ pub mod prctl;
+}
+
feature! {
#![feature = "pthread"]
pub mod pthread;
@@ -111,7 +116,6 @@ feature! {
pub mod resource;
}
-#[cfg(not(target_os = "redox"))]
feature! {
#![feature = "poll"]
pub mod select;
@@ -139,7 +143,6 @@ feature! {
pub mod signalfd;
}
-#[cfg(not(target_os = "redox"))]
feature! {
#![feature = "socket"]
#[allow(missing_docs)]
diff --git a/src/sys/personality.rs b/src/sys/personality.rs
index f295a05..30231dd 100644
--- a/src/sys/personality.rs
+++ b/src/sys/personality.rs
@@ -80,7 +80,10 @@ pub fn get() -> Result<Persona> {
///
/// Example:
///
-/// ```
+// Disable test on aarch64 until we know why it fails.
+// https://github.com/nix-rust/nix/issues/2060
+#[cfg_attr(target_arch = "aarch64", doc = " ```no_run")]
+#[cfg_attr(not(target_arch = "aarch64"), doc = " ```")]
/// # use nix::sys::personality::{self, Persona};
/// let mut pers = personality::get().unwrap();
/// assert!(!pers.contains(Persona::ADDR_NO_RANDOMIZE));
diff --git a/src/sys/prctl.rs b/src/sys/prctl.rs
new file mode 100644
index 0000000..995382c
--- /dev/null
+++ b/src/sys/prctl.rs
@@ -0,0 +1,208 @@
+//! prctl is a Linux-only API for performing operations on a process or thread.
+//!
+//! Note that careless use of some prctl() operations can confuse the user-space run-time
+//! environment, so these operations should be used with care.
+//!
+//! For more documentation, please read [prctl(2)](https://man7.org/linux/man-pages/man2/prctl.2.html).
+
+use crate::errno::Errno;
+use crate::sys::signal::Signal;
+use crate::Result;
+
+use libc::{c_int, c_ulong};
+use std::convert::TryFrom;
+use std::ffi::{CStr, CString};
+
+libc_enum! {
+ /// The type of hardware memory corruption kill policy for the thread.
+
+ #[repr(i32)]
+ #[non_exhaustive]
+ #[allow(non_camel_case_types)]
+ pub enum PrctlMCEKillPolicy {
+ /// The thread will receive SIGBUS as soon as a memory corruption is detected.
+ PR_MCE_KILL_EARLY,
+ /// The process is killed only when it accesses a corrupted page.
+ PR_MCE_KILL_LATE,
+ /// Uses the system-wide default.
+ PR_MCE_KILL_DEFAULT,
+ }
+ impl TryFrom<i32>
+}
+
+fn prctl_set_bool(option: c_int, status: bool) -> Result<()> {
+ let res = unsafe { libc::prctl(option, status as c_ulong, 0, 0, 0) };
+ Errno::result(res).map(drop)
+}
+
+fn prctl_get_bool(option: c_int) -> Result<bool> {
+ let res = unsafe { libc::prctl(option, 0, 0, 0, 0) };
+ Errno::result(res).map(|res| res != 0)
+}
+
+/// Set the "child subreaper" attribute for this process
+pub fn set_child_subreaper(attribute: bool) -> Result<()> {
+ prctl_set_bool(libc::PR_SET_CHILD_SUBREAPER, attribute)
+}
+
+/// Get the "child subreaper" attribute for this process
+pub fn get_child_subreaper() -> Result<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) };
+
+ Errno::result(res).map(|_| subreaper != 0)
+}
+
+/// Set the dumpable attribute which determines if core dumps are created for this process.
+pub fn set_dumpable(attribute: bool) -> Result<()> {
+ prctl_set_bool(libc::PR_SET_DUMPABLE, attribute)
+}
+
+/// Get the dumpable attribute for this process.
+pub fn get_dumpable() -> Result<bool> {
+ prctl_get_bool(libc::PR_GET_DUMPABLE)
+}
+
+/// Set the "keep capabilities" attribute for this process. This causes the thread to retain
+/// capabilities even if it switches its UID to a nonzero value.
+pub fn set_keepcaps(attribute: bool) -> Result<()> {
+ prctl_set_bool(libc::PR_SET_KEEPCAPS, attribute)
+}
+
+/// Get the "keep capabilities" attribute for this process
+pub fn get_keepcaps() -> Result<bool> {
+ prctl_get_bool(libc::PR_GET_KEEPCAPS)
+}
+
+/// Clear the thread memory corruption kill policy and use the system-wide default
+pub fn clear_mce_kill() -> Result<()> {
+ let res = unsafe { libc::prctl(libc::PR_MCE_KILL, libc::PR_MCE_KILL_CLEAR, 0, 0, 0) };
+
+ Errno::result(res).map(drop)
+}
+
+/// Set the thread memory corruption kill policy
+pub fn set_mce_kill(policy: PrctlMCEKillPolicy) -> Result<()> {
+ let res = unsafe {
+ libc::prctl(
+ libc::PR_MCE_KILL,
+ libc::PR_MCE_KILL_SET,
+ policy as c_ulong,
+ 0,
+ 0,
+ )
+ };
+
+ Errno::result(res).map(drop)
+}
+
+/// Get the thread memory corruption kill policy
+pub fn get_mce_kill() -> Result<PrctlMCEKillPolicy> {
+ let res = unsafe { libc::prctl(libc::PR_MCE_KILL_GET, 0, 0, 0, 0) };
+
+ match Errno::result(res) {
+ Ok(val) => Ok(PrctlMCEKillPolicy::try_from(val)?),
+ Err(e) => Err(e),
+ }
+}
+
+/// Set the parent-death signal of the calling process. This is the signal that the calling process
+/// will get when its parent dies.
+pub fn set_pdeathsig<T: Into<Option<Signal>>>(signal: T) -> Result<()> {
+ let sig = match signal.into() {
+ Some(s) => s as c_int,
+ None => 0,
+ };
+
+ let res = unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, sig, 0, 0, 0) };
+
+ Errno::result(res).map(drop)
+}
+
+/// Returns the current parent-death signal
+pub fn get_pdeathsig() -> Result<Option<Signal>> {
+ // prctl writes into this var
+ let mut sig: c_int = 0;
+
+ let res = unsafe { libc::prctl(libc::PR_GET_PDEATHSIG, &mut sig, 0, 0, 0) };
+
+ match Errno::result(res) {
+ Ok(_) => Ok(match sig {
+ 0 => None,
+ _ => Some(Signal::try_from(sig)?),
+ }),
+ Err(e) => Err(e),
+ }
+}
+
+/// Set the name of the calling thread. Strings longer than 15 bytes will be truncated.
+pub fn set_name(name: &CStr) -> Result<()> {
+ let res = unsafe { libc::prctl(libc::PR_SET_NAME, name.as_ptr(), 0, 0, 0) };
+
+ Errno::result(res).map(drop)
+}
+
+/// Return the name of the calling thread
+pub fn get_name() -> Result<CString> {
+ // Size of buffer determined by linux/sched.h TASK_COMM_LEN
+ let buf = [0u8; 16];
+
+ let res = unsafe { libc::prctl(libc::PR_GET_NAME, &buf, 0, 0, 0) };
+
+ let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
+ let name = CStr::from_bytes_with_nul(&buf[..=len]).map_err(|_| Errno::EINVAL)?;
+
+ Errno::result(res).map(|_| name.to_owned())
+}
+
+/// Sets the timer slack value for the calling thread. Timer slack is used by the kernel to group
+/// timer expirations and make them the supplied amount of nanoseconds late.
+pub fn set_timerslack(ns: u64) -> Result<()> {
+ let res = unsafe { libc::prctl(libc::PR_SET_TIMERSLACK, ns, 0, 0, 0) };
+
+ Errno::result(res).map(drop)
+}
+
+/// Get the timerslack for the calling thread.
+pub fn get_timerslack() -> Result<i32> {
+ let res = unsafe { libc::prctl(libc::PR_GET_TIMERSLACK, 0, 0, 0, 0) };
+
+ Errno::result(res)
+}
+
+/// Disable all performance counters attached to the calling process.
+pub fn task_perf_events_disable() -> Result<()> {
+ let res = unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_DISABLE, 0, 0, 0, 0) };
+
+ Errno::result(res).map(drop)
+}
+
+/// Enable all performance counters attached to the calling process.
+pub fn task_perf_events_enable() -> Result<()> {
+ let res = unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_ENABLE, 0, 0, 0, 0) };
+
+ Errno::result(res).map(drop)
+}
+
+/// Set the calling threads "no new privs" attribute. Once set this option can not be unset.
+pub fn set_no_new_privs() -> Result<()> {
+ prctl_set_bool(libc::PR_SET_NO_NEW_PRIVS, true) // Cannot be unset
+}
+
+/// Get the "no new privs" attribute for the calling thread.
+pub fn get_no_new_privs() -> Result<bool> {
+ prctl_get_bool(libc::PR_GET_NO_NEW_PRIVS)
+}
+
+/// Set the state of the "THP disable" flag for the calling thread. Setting this disables
+/// transparent huge pages.
+pub fn set_thp_disable(flag: bool) -> Result<()> {
+ prctl_set_bool(libc::PR_SET_THP_DISABLE, flag)
+}
+
+/// Get the "THP disable" flag for the calling thread.
+pub fn get_thp_disable() -> Result<bool> {
+ prctl_get_bool(libc::PR_GET_THP_DISABLE)
+}
diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs
index 9687e05..8c134cf 100644
--- a/src/sys/ptrace/linux.rs
+++ b/src/sys/ptrace/linux.rs
@@ -269,7 +269,7 @@ unsafe fn ptrace_other(
.map(|_| 0)
}
-/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`.
+/// Set options, as with `ptrace(PTRACE_SETOPTIONS, ...)`.
pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
let res = unsafe {
libc::ptrace(
@@ -282,17 +282,17 @@ pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
Errno::result(res).map(drop)
}
-/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
+/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG, ...)`
pub fn getevent(pid: Pid) -> Result<c_long> {
ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid)
}
-/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)`
+/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO, ...)`
pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> {
ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid)
}
-/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)`
+/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO, ...)`
pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
let ret = unsafe {
Errno::clear();
@@ -517,12 +517,14 @@ pub fn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
}
}
-/// Reads a word from a processes memory at the given address
+/// Reads a word from a processes memory at the given address, as with
+/// ptrace(PTRACE_PEEKDATA, ...)
pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut())
}
-/// Writes a word into the processes memory at the given address
+/// Writes a word into the processes memory at the given address, as with
+/// ptrace(PTRACE_POKEDATA, ...)
///
/// # Safety
///
@@ -536,13 +538,13 @@ pub unsafe fn write(
ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
}
-/// Reads a word from a user area at `offset`.
+/// Reads a word from a user area at `offset`, as with ptrace(PTRACE_PEEKUSER, ...).
/// The user struct definition can be found in `/usr/include/sys/user.h`.
pub fn read_user(pid: Pid, offset: AddressType) -> Result<c_long> {
ptrace_peek(Request::PTRACE_PEEKUSER, pid, offset, ptr::null_mut())
}
-/// Writes a word to a user area at `offset`.
+/// Writes a word to a user area at `offset`, as with ptrace(PTRACE_POKEUSER, ...).
/// The user struct definition can be found in `/usr/include/sys/user.h`.
///
/// # Safety
diff --git a/src/sys/ptrace/mod.rs b/src/sys/ptrace/mod.rs
index 2b121c0..88648ac 100644
--- a/src/sys/ptrace/mod.rs
+++ b/src/sys/ptrace/mod.rs
@@ -1,4 +1,4 @@
-///! Provides helpers for making ptrace system calls
+//! Provides helpers for making ptrace system calls
#[cfg(any(target_os = "android", target_os = "linux"))]
mod linux;
diff --git a/src/sys/quota.rs b/src/sys/quota.rs
index b3c44ca..a32d07a 100644
--- a/src/sys/quota.rs
+++ b/src/sys/quota.rs
@@ -21,9 +21,8 @@ use std::{mem, ptr};
struct QuotaCmd(QuotaSubCmd, QuotaType);
impl QuotaCmd {
- #[allow(unused_unsafe)]
fn as_int(&self) -> c_int {
- unsafe { libc::QCMD(self.0 as i32, self.1 as i32) }
+ libc::QCMD(self.0 as i32, self.1 as i32)
}
}
diff --git a/src/sys/resource.rs b/src/sys/resource.rs
index 8927737..f42d32e 100644
--- a/src/sys/resource.rs
+++ b/src/sys/resource.rs
@@ -20,6 +20,7 @@ cfg_if! {
target_os = "ios",
target_os = "android",
target_os = "dragonfly",
+ target_os = "aix",
all(target_os = "linux", not(target_env = "gnu"))
))]{
use libc::rlimit;
@@ -51,6 +52,7 @@ libc_enum! {
target_os = "ios",
target_os = "android",
target_os = "dragonfly",
+ target_os = "aix",
all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc")))
), repr(i32))]
#[non_exhaustive]
@@ -115,6 +117,7 @@ libc_enum! {
target_os = "netbsd",
target_os = "openbsd",
target_os = "linux",
+ target_os = "aix",
))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The maximum number of simultaneous processes for this user id.
@@ -131,6 +134,7 @@ libc_enum! {
target_os = "netbsd",
target_os = "openbsd",
target_os = "linux",
+ target_os = "aix",
))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// When there is memory pressure and swap is available, prioritize
diff --git a/src/sys/select.rs b/src/sys/select.rs
index 7a94cff..0e2193b 100644
--- a/src/sys/select.rs
+++ b/src/sys/select.rs
@@ -7,7 +7,7 @@ use std::convert::TryFrom;
use std::iter::FusedIterator;
use std::mem;
use std::ops::Range;
-use std::os::unix::io::RawFd;
+use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
use std::ptr::{null, null_mut};
pub use libc::FD_SETSIZE;
@@ -15,7 +15,10 @@ pub use libc::FD_SETSIZE;
/// Contains a set of file descriptors used by [`select`]
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-pub struct FdSet(libc::fd_set);
+pub struct FdSet<'fd> {
+ set: libc::fd_set,
+ _fd: std::marker::PhantomData<BorrowedFd<'fd>>,
+}
fn assert_fd_valid(fd: RawFd) {
assert!(
@@ -24,37 +27,40 @@ fn assert_fd_valid(fd: RawFd) {
);
}
-impl FdSet {
+impl<'fd> FdSet<'fd> {
/// Create an empty `FdSet`
- pub fn new() -> FdSet {
+ pub fn new() -> FdSet<'fd> {
let mut fdset = mem::MaybeUninit::uninit();
unsafe {
libc::FD_ZERO(fdset.as_mut_ptr());
- FdSet(fdset.assume_init())
+ Self {
+ set: fdset.assume_init(),
+ _fd: std::marker::PhantomData,
+ }
}
}
/// Add a file descriptor to an `FdSet`
- pub fn insert(&mut self, fd: RawFd) {
- assert_fd_valid(fd);
- unsafe { libc::FD_SET(fd, &mut self.0) };
+ pub fn insert<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) };
}
/// Remove a file descriptor from an `FdSet`
- pub fn remove(&mut self, fd: RawFd) {
- assert_fd_valid(fd);
- unsafe { libc::FD_CLR(fd, &mut self.0) };
+ pub fn remove<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) };
}
/// Test an `FdSet` for the presence of a certain file descriptor.
- pub fn contains(&self, fd: RawFd) -> bool {
- assert_fd_valid(fd);
- unsafe { libc::FD_ISSET(fd, &self.0) }
+ pub fn contains<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) }
}
/// Remove all file descriptors from this `FdSet`.
pub fn clear(&mut self) {
- unsafe { libc::FD_ZERO(&mut self.0) };
+ unsafe { libc::FD_ZERO(&mut self.set) };
}
/// Finds the highest file descriptor in the set.
@@ -66,15 +72,18 @@ impl FdSet {
/// # Example
///
/// ```
+ /// # use std::os::unix::io::{AsRawFd, BorrowedFd};
/// # use nix::sys::select::FdSet;
+ /// let fd_four = unsafe {BorrowedFd::borrow_raw(4)};
+ /// let fd_nine = unsafe {BorrowedFd::borrow_raw(9)};
/// let mut set = FdSet::new();
- /// set.insert(4);
- /// set.insert(9);
- /// assert_eq!(set.highest(), Some(9));
+ /// set.insert(&fd_four);
+ /// set.insert(&fd_nine);
+ /// assert_eq!(set.highest().map(|borrowed_fd|borrowed_fd.as_raw_fd()), Some(9));
/// ```
///
/// [`select`]: fn.select.html
- pub fn highest(&self) -> Option<RawFd> {
+ pub fn highest(&self) -> Option<BorrowedFd<'_>> {
self.fds(None).next_back()
}
@@ -88,11 +97,13 @@ impl FdSet {
///
/// ```
/// # use nix::sys::select::FdSet;
- /// # use std::os::unix::io::RawFd;
+ /// # use std::os::unix::io::{AsRawFd, BorrowedFd, RawFd};
/// let mut set = FdSet::new();
- /// set.insert(4);
- /// set.insert(9);
- /// let fds: Vec<RawFd> = set.fds(None).collect();
+ /// let fd_four = unsafe {BorrowedFd::borrow_raw(4)};
+ /// let fd_nine = unsafe {BorrowedFd::borrow_raw(9)};
+ /// set.insert(&fd_four);
+ /// set.insert(&fd_nine);
+ /// let fds: Vec<RawFd> = set.fds(None).map(|borrowed_fd|borrowed_fd.as_raw_fd()).collect();
/// assert_eq!(fds, vec![4, 9]);
/// ```
#[inline]
@@ -104,7 +115,7 @@ impl FdSet {
}
}
-impl Default for FdSet {
+impl<'fd> Default for FdSet<'fd> {
fn default() -> Self {
Self::new()
}
@@ -112,18 +123,19 @@ impl Default for FdSet {
/// Iterator over `FdSet`.
#[derive(Debug)]
-pub struct Fds<'a> {
- set: &'a FdSet,
+pub struct Fds<'a, 'fd> {
+ set: &'a FdSet<'fd>,
range: Range<usize>,
}
-impl<'a> Iterator for Fds<'a> {
- type Item = RawFd;
+impl<'a, 'fd> Iterator for Fds<'a, 'fd> {
+ type Item = BorrowedFd<'fd>;
- fn next(&mut self) -> Option<RawFd> {
+ fn next(&mut self) -> Option<Self::Item> {
for i in &mut self.range {
- if self.set.contains(i as RawFd) {
- return Some(i as RawFd);
+ let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+ if self.set.contains(&borrowed_i) {
+ return Some(borrowed_i);
}
}
None
@@ -136,19 +148,20 @@ impl<'a> Iterator for Fds<'a> {
}
}
-impl<'a> DoubleEndedIterator for Fds<'a> {
+impl<'a, 'fd> DoubleEndedIterator for Fds<'a, 'fd> {
#[inline]
- fn next_back(&mut self) -> Option<RawFd> {
+ fn next_back(&mut self) -> Option<BorrowedFd<'fd>> {
while let Some(i) = self.range.next_back() {
- if self.set.contains(i as RawFd) {
- return Some(i as RawFd);
+ let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+ if self.set.contains(&borrowed_i) {
+ return Some(borrowed_i);
}
}
None
}
}
-impl<'a> FusedIterator for Fds<'a> {}
+impl<'a, 'fd> FusedIterator for Fds<'a, 'fd> {}
/// Monitors file descriptors for readiness
///
@@ -173,7 +186,7 @@ impl<'a> FusedIterator for Fds<'a> {}
/// [select(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html)
///
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
-pub fn select<'a, N, R, W, E, T>(
+pub fn select<'a, 'fd, N, R, W, E, T>(
nfds: N,
readfds: R,
writefds: W,
@@ -181,10 +194,11 @@ pub fn select<'a, N, R, W, E, T>(
timeout: T,
) -> Result<c_int>
where
+ 'fd: 'a,
N: Into<Option<c_int>>,
- R: Into<Option<&'a mut FdSet>>,
- W: Into<Option<&'a mut FdSet>>,
- E: Into<Option<&'a mut FdSet>>,
+ R: Into<Option<&'a mut FdSet<'fd>>>,
+ W: Into<Option<&'a mut FdSet<'fd>>>,
+ E: Into<Option<&'a mut FdSet<'fd>>>,
T: Into<Option<&'a mut TimeVal>>,
{
let mut readfds = readfds.into();
@@ -197,7 +211,11 @@ where
.iter_mut()
.chain(writefds.iter_mut())
.chain(errorfds.iter_mut())
- .map(|set| set.highest().unwrap_or(-1))
+ .map(|set| {
+ set.highest()
+ .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+ .unwrap_or(-1)
+ })
.max()
.unwrap_or(-1)
+ 1
@@ -256,17 +274,18 @@ use crate::sys::signal::SigSet;
/// [The new pselect() system call](https://lwn.net/Articles/176911/)
///
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
-pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
+pub fn pselect<'a, 'fd, N, R, W, E, T, S>(nfds: N,
readfds: R,
writefds: W,
errorfds: E,
timeout: T,
sigmask: S) -> Result<c_int>
where
+ 'fd: 'a,
N: Into<Option<c_int>>,
- R: Into<Option<&'a mut FdSet>>,
- W: Into<Option<&'a mut FdSet>>,
- E: Into<Option<&'a mut FdSet>>,
+ R: Into<Option<&'a mut FdSet<'fd>>>,
+ W: Into<Option<&'a mut FdSet<'fd>>>,
+ E: Into<Option<&'a mut FdSet<'fd>>>,
T: Into<Option<&'a TimeSpec>>,
S: Into<Option<&'a SigSet>>,
{
@@ -280,7 +299,7 @@ where
readfds.iter_mut()
.chain(writefds.iter_mut())
.chain(errorfds.iter_mut())
- .map(|set| set.highest().unwrap_or(-1))
+ .map(|set| set.highest().map(|borrowed_fd|borrowed_fd.as_raw_fd()).unwrap_or(-1))
.max()
.unwrap_or(-1) + 1
});
@@ -303,20 +322,22 @@ where
mod tests {
use super::*;
use crate::sys::time::{TimeVal, TimeValLike};
- use crate::unistd::{pipe, write};
- use std::os::unix::io::RawFd;
+ use crate::unistd::{close, pipe, write};
+ use std::os::unix::io::{FromRawFd, OwnedFd, RawFd};
#[test]
fn fdset_insert() {
let mut fd_set = FdSet::new();
for i in 0..FD_SETSIZE {
- assert!(!fd_set.contains(i as RawFd));
+ let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+ assert!(!fd_set.contains(&borrowed_i));
}
- fd_set.insert(7);
+ let fd_seven = unsafe { BorrowedFd::borrow_raw(7) };
+ fd_set.insert(&fd_seven);
- assert!(fd_set.contains(7));
+ assert!(fd_set.contains(&fd_seven));
}
#[test]
@@ -324,107 +345,183 @@ mod tests {
let mut fd_set = FdSet::new();
for i in 0..FD_SETSIZE {
- assert!(!fd_set.contains(i as RawFd));
+ let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+ assert!(!fd_set.contains(&borrowed_i));
}
- fd_set.insert(7);
- fd_set.remove(7);
+ let fd_seven = unsafe { BorrowedFd::borrow_raw(7) };
+ fd_set.insert(&fd_seven);
+ fd_set.remove(&fd_seven);
for i in 0..FD_SETSIZE {
- assert!(!fd_set.contains(i as RawFd));
+ let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+ assert!(!fd_set.contains(&borrowed_i));
}
}
#[test]
+ #[allow(non_snake_case)]
fn fdset_clear() {
let mut fd_set = FdSet::new();
- fd_set.insert(1);
- fd_set.insert((FD_SETSIZE / 2) as RawFd);
- fd_set.insert((FD_SETSIZE - 1) as RawFd);
+ let fd_one = unsafe { BorrowedFd::borrow_raw(1) };
+ let fd_FD_SETSIZE_devided_by_two =
+ unsafe { BorrowedFd::borrow_raw((FD_SETSIZE / 2) as RawFd) };
+ let fd_FD_SETSIZE_minus_one =
+ unsafe { BorrowedFd::borrow_raw((FD_SETSIZE - 1) as RawFd) };
+ fd_set.insert(&fd_one);
+ fd_set.insert(&fd_FD_SETSIZE_devided_by_two);
+ fd_set.insert(&fd_FD_SETSIZE_minus_one);
fd_set.clear();
for i in 0..FD_SETSIZE {
- assert!(!fd_set.contains(i as RawFd));
+ let borrowed_i = unsafe { BorrowedFd::borrow_raw(i as RawFd) };
+ assert!(!fd_set.contains(&borrowed_i));
}
}
#[test]
fn fdset_highest() {
let mut set = FdSet::new();
- assert_eq!(set.highest(), None);
- set.insert(0);
- assert_eq!(set.highest(), Some(0));
- set.insert(90);
- assert_eq!(set.highest(), Some(90));
- set.remove(0);
- assert_eq!(set.highest(), Some(90));
- set.remove(90);
- assert_eq!(set.highest(), None);
-
- set.insert(4);
- set.insert(5);
- set.insert(7);
- assert_eq!(set.highest(), Some(7));
+ assert_eq!(
+ set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+ None
+ );
+ let fd_zero = unsafe { BorrowedFd::borrow_raw(0) };
+ let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) };
+ set.insert(&fd_zero);
+ assert_eq!(
+ set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+ Some(0)
+ );
+ set.insert(&fd_ninety);
+ assert_eq!(
+ set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+ Some(90)
+ );
+ set.remove(&fd_zero);
+ assert_eq!(
+ set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+ Some(90)
+ );
+ set.remove(&fd_ninety);
+ assert_eq!(
+ set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+ None
+ );
+
+ let fd_four = unsafe { BorrowedFd::borrow_raw(4) };
+ let fd_five = unsafe { BorrowedFd::borrow_raw(5) };
+ let fd_seven = unsafe { BorrowedFd::borrow_raw(7) };
+ set.insert(&fd_four);
+ set.insert(&fd_five);
+ set.insert(&fd_seven);
+ assert_eq!(
+ set.highest().map(|borrowed_fd| borrowed_fd.as_raw_fd()),
+ Some(7)
+ );
}
#[test]
fn fdset_fds() {
let mut set = FdSet::new();
- assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![]);
- set.insert(0);
- assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0]);
- set.insert(90);
- assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0, 90]);
+ let fd_zero = unsafe { BorrowedFd::borrow_raw(0) };
+ let fd_ninety = unsafe { BorrowedFd::borrow_raw(90) };
+ assert_eq!(
+ set.fds(None)
+ .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+ .collect::<Vec<_>>(),
+ 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)).collect::<Vec<_>>(), vec![0]);
- assert_eq!(set.fds(Some(90)).collect::<Vec<_>>(), vec![0, 90]);
+ 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();
- write(w1, b"hi!").unwrap();
+ let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
+ let w1 = unsafe { OwnedFd::from_raw_fd(w1) };
let (r2, _w2) = pipe().unwrap();
+ let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
+ write(w1.as_raw_fd(), b"hi!").unwrap();
let mut fd_set = FdSet::new();
- fd_set.insert(r1);
- fd_set.insert(r2);
+ fd_set.insert(&r1);
+ fd_set.insert(&r2);
let mut timeout = TimeVal::seconds(10);
assert_eq!(
1,
select(None, &mut fd_set, None, None, &mut timeout).unwrap()
);
- assert!(fd_set.contains(r1));
- assert!(!fd_set.contains(r2));
+ assert!(fd_set.contains(&r1));
+ assert!(!fd_set.contains(&r2));
+ close(_w2).unwrap();
}
#[test]
fn test_select_nfds() {
let (r1, w1) = pipe().unwrap();
- write(w1, b"hi!").unwrap();
let (r2, _w2) = pipe().unwrap();
+ let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
+ let w1 = unsafe { OwnedFd::from_raw_fd(w1) };
+ let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
+ write(w1.as_raw_fd(), b"hi!").unwrap();
let mut fd_set = FdSet::new();
- fd_set.insert(r1);
- fd_set.insert(r2);
+ fd_set.insert(&r1);
+ fd_set.insert(&r2);
let mut timeout = TimeVal::seconds(10);
- assert_eq!(
- 1,
- select(
- Some(fd_set.highest().unwrap() + 1),
- &mut fd_set,
- None,
- None,
- &mut timeout
- )
- .unwrap()
- );
- assert!(fd_set.contains(r1));
- assert!(!fd_set.contains(r2));
+ {
+ assert_eq!(
+ 1,
+ select(
+ Some(
+ fd_set
+ .highest()
+ .map(|borrowed_fd| borrowed_fd.as_raw_fd())
+ .unwrap()
+ + 1
+ ),
+ &mut fd_set,
+ None,
+ None,
+ &mut timeout
+ )
+ .unwrap()
+ );
+ }
+ assert!(fd_set.contains(&r1));
+ assert!(!fd_set.contains(&r2));
+ close(_w2).unwrap();
}
#[test]
@@ -432,16 +529,17 @@ mod tests {
let (r1, w1) = pipe().unwrap();
write(w1, b"hi!").unwrap();
let (r2, _w2) = pipe().unwrap();
-
+ let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
+ let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
let mut fd_set = FdSet::new();
- fd_set.insert(r1);
- fd_set.insert(r2);
+ fd_set.insert(&r1);
+ fd_set.insert(&r2);
let mut timeout = TimeVal::seconds(10);
assert_eq!(
1,
select(
- ::std::cmp::max(r1, r2) + 1,
+ std::cmp::max(r1.as_raw_fd(), r2.as_raw_fd()) + 1,
&mut fd_set,
None,
None,
@@ -449,7 +547,8 @@ mod tests {
)
.unwrap()
);
- assert!(fd_set.contains(r1));
- assert!(!fd_set.contains(r2));
+ assert!(fd_set.contains(&r1));
+ assert!(!fd_set.contains(&r2));
+ close(_w2).unwrap();
}
}
diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs
index fb293a4..9f3c333 100644
--- a/src/sys/sendfile.rs
+++ b/src/sys/sendfile.rs
@@ -1,7 +1,7 @@
//! Send data from a file to a socket, bypassing userland.
use cfg_if::cfg_if;
-use std::os::unix::io::RawFd;
+use std::os::unix::io::{AsFd, AsRawFd};
use std::ptr;
use libc::{self, off_t};
@@ -23,16 +23,23 @@ use crate::Result;
/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html)
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
-pub fn sendfile(
- out_fd: RawFd,
- in_fd: RawFd,
+pub fn sendfile<F1: AsFd, F2: AsFd>(
+ out_fd: F1,
+ in_fd: F2,
offset: Option<&mut off_t>,
count: usize,
) -> Result<usize> {
let offset = offset
.map(|offset| offset as *mut _)
.unwrap_or(ptr::null_mut());
- let ret = unsafe { libc::sendfile(out_fd, in_fd, offset, count) };
+ let ret = unsafe {
+ libc::sendfile(
+ out_fd.as_fd().as_raw_fd(),
+ in_fd.as_fd().as_raw_fd(),
+ offset,
+ count,
+ )
+ };
Errno::result(ret).map(|r| r as usize)
}
@@ -50,16 +57,23 @@ pub fn sendfile(
/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html)
#[cfg(target_os = "linux")]
#[cfg_attr(docsrs, doc(cfg(all())))]
-pub fn sendfile64(
- out_fd: RawFd,
- in_fd: RawFd,
+pub fn sendfile64<F1: AsFd, F2: AsFd>(
+ out_fd: F1,
+ in_fd: F2,
offset: Option<&mut libc::off64_t>,
count: usize,
) -> Result<usize> {
let offset = offset
.map(|offset| offset as *mut _)
.unwrap_or(ptr::null_mut());
- let ret = unsafe { libc::sendfile64(out_fd, in_fd, offset, count) };
+ let ret = unsafe {
+ libc::sendfile64(
+ out_fd.as_fd().as_raw_fd(),
+ in_fd.as_fd().as_raw_fd(),
+ offset,
+ count,
+ )
+ };
Errno::result(ret).map(|r| r as usize)
}
@@ -156,9 +170,9 @@ cfg_if! {
/// For more information, see
/// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2)
#[allow(clippy::too_many_arguments)]
- pub fn sendfile(
- in_fd: RawFd,
- out_sock: RawFd,
+ pub fn sendfile<F1: AsFd, F2: AsFd>(
+ in_fd: F1,
+ out_sock: F2,
offset: off_t,
count: Option<usize>,
headers: Option<&[&[u8]]>,
@@ -175,8 +189,8 @@ cfg_if! {
let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
let return_code = unsafe {
- libc::sendfile(in_fd,
- out_sock,
+ libc::sendfile(in_fd.as_fd().as_raw_fd(),
+ out_sock.as_fd().as_raw_fd(),
offset,
count.unwrap_or(0),
hdtr_ptr as *mut libc::sf_hdtr,
@@ -206,9 +220,9 @@ cfg_if! {
///
/// For more information, see
/// [the sendfile(2) man page.](https://leaf.dragonflybsd.org/cgi/web-man?command=sendfile&section=2)
- pub fn sendfile(
- in_fd: RawFd,
- out_sock: RawFd,
+ pub fn sendfile<F1: AsFd, F2: AsFd>(
+ in_fd: F1,
+ out_sock: F2,
offset: off_t,
count: Option<usize>,
headers: Option<&[&[u8]]>,
@@ -218,8 +232,8 @@ cfg_if! {
let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
let return_code = unsafe {
- libc::sendfile(in_fd,
- out_sock,
+ libc::sendfile(in_fd.as_fd().as_raw_fd(),
+ out_sock.as_fd().as_raw_fd(),
offset,
count.unwrap_or(0),
hdtr_ptr as *mut libc::sf_hdtr,
@@ -252,9 +266,9 @@ cfg_if! {
///
/// For more information, see
/// [the sendfile(2) man page.](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html)
- pub fn sendfile(
- in_fd: RawFd,
- out_sock: RawFd,
+ pub fn sendfile<F1: AsFd, F2: AsFd>(
+ in_fd: F1,
+ out_sock: F2,
offset: off_t,
count: Option<off_t>,
headers: Option<&[&[u8]]>,
@@ -264,8 +278,8 @@ cfg_if! {
let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
let return_code = unsafe {
- libc::sendfile(in_fd,
- out_sock,
+ libc::sendfile(in_fd.as_fd().as_raw_fd(),
+ out_sock.as_fd().as_raw_fd(),
offset,
&mut len as *mut off_t,
hdtr_ptr as *mut libc::sf_hdtr,
diff --git a/src/sys/signal.rs b/src/sys/signal.rs
index d3746e6..c946e4a 100644
--- a/src/sys/signal.rs
+++ b/src/sys/signal.rs
@@ -13,7 +13,11 @@ use std::os::unix::io::RawFd;
use std::ptr;
use std::str::FromStr;
-#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
+#[cfg(not(any(
+ target_os = "fuchsia",
+ target_os = "openbsd",
+ target_os = "redox"
+)))]
#[cfg(any(feature = "aio", feature = "signal"))]
pub use self::sigevent::*;
@@ -93,7 +97,8 @@ libc_enum! {
#[cfg_attr(docsrs, doc(cfg(all())))]
SIGIO,
#[cfg(any(target_os = "android", target_os = "emscripten",
- target_os = "fuchsia", target_os = "linux"))]
+ target_os = "fuchsia", target_os = "linux",
+ target_os = "aix"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Power failure imminent.
SIGPWR,
@@ -107,7 +112,8 @@ libc_enum! {
SIGEMT,
#[cfg(not(any(target_os = "android", target_os = "emscripten",
target_os = "fuchsia", target_os = "linux",
- target_os = "redox", target_os = "haiku")))]
+ target_os = "redox", target_os = "haiku",
+ target_os = "aix")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Information request
SIGINFO,
@@ -186,6 +192,7 @@ impl FromStr for Signal {
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
+ target_os = "aix",
target_os = "haiku"
)))]
"SIGINFO" => Signal::SIGINFO,
@@ -250,6 +257,7 @@ impl Signal {
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
+ target_os = "aix",
target_os = "linux"
))]
Signal::SIGPWR => "SIGPWR",
@@ -269,6 +277,7 @@ impl Signal {
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
+ target_os = "aix",
target_os = "haiku"
)))]
Signal::SIGINFO => "SIGINFO",
@@ -345,11 +354,20 @@ const SIGNALS: [Signal; 30] = [
SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
];
+#[cfg(target_os = "aix")]
+#[cfg(feature = "signal")]
+const SIGNALS: [Signal; 30] = [
+ SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGEMT, SIGFPE, SIGKILL, SIGSEGV,
+ SIGSYS, SIGPIPE, SIGALRM, SIGTERM, SIGUSR1, SIGUSR2, SIGPWR, SIGWINCH,
+ SIGURG, SIGPOLL, SIGIO, SIGSTOP, SIGTSTP, SIGCONT, SIGTTIN, SIGTTOU,
+ SIGVTALRM, SIGPROF, SIGXCPU, SIGXFSZ, SIGTRAP,
+];
#[cfg(not(any(
target_os = "linux",
target_os = "android",
target_os = "fuchsia",
target_os = "emscripten",
+ target_os = "aix",
target_os = "redox",
target_os = "haiku"
)))]
@@ -641,7 +659,6 @@ impl<'a> IntoIterator for &'a SigSet {
}
/// A signal handler.
-#[allow(unknown_lints)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SigHandler {
/// Default signal handling.
@@ -670,6 +687,7 @@ impl SigAction {
/// is the `SigAction` variant). `mask` specifies other signals to block during execution of
/// the signal-catching function.
pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
+ #[cfg(not(target_os = "aix"))]
unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
(*p).sa_sigaction = match handler {
SigHandler::SigDfl => libc::SIG_DFL,
@@ -680,6 +698,16 @@ impl SigAction {
};
}
+ #[cfg(target_os = "aix")]
+ unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
+ (*p).sa_union.__su_sigaction = match handler {
+ SigHandler::SigDfl => mem::transmute::<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,
+ };
+ }
+
let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
unsafe {
let p = s.as_mut_ptr();
@@ -707,6 +735,7 @@ impl SigAction {
}
/// Returns the action's handler.
+ #[cfg(not(target_os = "aix"))]
pub fn handler(&self) -> SigHandler {
match self.sigaction.sa_sigaction {
libc::SIG_DFL => SigHandler::SigDfl,
@@ -739,6 +768,26 @@ impl SigAction {
as extern fn(libc::c_int)),
}
}
+
+ /// Returns the action's handler.
+ #[cfg(target_os = "aix")]
+ pub fn handler(&self) -> SigHandler {
+ unsafe {
+ match self.sigaction.sa_union.__su_sigaction as usize {
+ libc::SIG_DFL => SigHandler::SigDfl,
+ libc::SIG_IGN => SigHandler::SigIgn,
+ p if self.flags().contains(SaFlags::SA_SIGINFO) =>
+ SigHandler::SigAction(
+ *(&p as *const usize
+ as *const extern fn(_, _, _))
+ as extern fn(_, _, _)),
+ p => SigHandler::Handler(
+ *(&p as *const usize
+ as *const extern fn(libc::c_int))
+ as extern fn(libc::c_int)),
+ }
+ }
+ }
}
/// Changes the action taken by a process on receipt of a specific signal.
@@ -792,13 +841,10 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigActi
/// Use a signal handler to set a flag variable:
///
/// ```no_run
-/// # #[macro_use] extern crate lazy_static;
/// # use std::convert::TryFrom;
/// # use std::sync::atomic::{AtomicBool, Ordering};
/// # use nix::sys::signal::{self, Signal, SigHandler};
-/// lazy_static! {
-/// static ref SIGNALED: AtomicBool = AtomicBool::new(false);
-/// }
+/// static SIGNALED: AtomicBool = AtomicBool::new(false);
///
/// extern fn handle_sigint(signal: libc::c_int) {
/// let signal = Signal::try_from(signal).unwrap();
@@ -973,14 +1019,14 @@ feature! {
#[cfg(target_os = "freebsd")]
pub type type_of_thread_id = libc::lwpid_t;
/// Identifies a thread for [`SigevNotify::SigevThreadId`]
-#[cfg(target_os = "linux")]
+#[cfg(any(target_env = "gnu", target_env = "uclibc"))]
pub type type_of_thread_id = libc::pid_t;
/// Specifies the notification method used by a [`SigEvent`]
// sigval is actually a union of a int and a void*. But it's never really used
// as a pointer, because neither libc nor the kernel ever dereference it. nix
// therefore presents it as an intptr_t, which is how kevent uses it.
-#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "openbsd", target_os = "redox")))]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SigevNotify {
/// No notification will be delivered
@@ -993,8 +1039,7 @@ pub enum SigevNotify {
/// structure of the queued signal.
si_value: libc::intptr_t
},
- // Note: SIGEV_THREAD is not implemented because libc::sigevent does not
- // expose a way to set the union members needed by SIGEV_THREAD.
+ // Note: SIGEV_THREAD is not implemented, but could be if desired.
/// Notify by delivering an event to a kqueue.
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
@@ -1004,8 +1049,24 @@ pub enum SigevNotify {
/// Will be contained in the kevent's `udata` field.
udata: libc::intptr_t
},
+ /// Notify by delivering an event to a kqueue, with optional event flags set
+ #[cfg(target_os = "freebsd")]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ #[cfg(feature = "event")]
+ SigevKeventFlags {
+ /// File descriptor of the kqueue to notify.
+ kq: RawFd,
+ /// Will be contained in the kevent's `udata` field.
+ udata: libc::intptr_t,
+ /// Flags that will be set on the delivered event. See `kevent(2)`.
+ flags: crate::sys::event::EventFlag
+ },
/// Notify by delivering a signal to a thread.
- #[cfg(any(target_os = "freebsd", target_os = "linux"))]
+ #[cfg(any(
+ target_os = "freebsd",
+ target_env = "gnu",
+ target_env = "uclibc",
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
SigevThreadId {
/// Signal to send
@@ -1019,24 +1080,150 @@ pub enum SigevNotify {
}
}
-#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
+#[cfg(not(any(
+ target_os = "fuchsia",
+ target_os = "openbsd",
+ target_os = "redox"
+)))]
#[cfg_attr(docsrs, doc(cfg(all())))]
mod sigevent {
feature! {
#![any(feature = "aio", feature = "signal")]
use std::mem;
- use std::ptr;
use super::SigevNotify;
- #[cfg(any(target_os = "freebsd", target_os = "linux"))]
- use super::type_of_thread_id;
+
+ #[cfg(target_os = "freebsd")]
+ pub(crate) use ffi::sigevent as libc_sigevent;
+ #[cfg(not(target_os = "freebsd"))]
+ pub(crate) use libc::sigevent as libc_sigevent;
+
+ // For FreeBSD only, we define the C structure here. Because the structure
+ // defined in libc isn't correct. The real sigevent contains union fields,
+ // but libc could not represent those when sigevent was originally added, so
+ // instead libc simply defined the most useful field. Now that Rust can
+ // represent unions, there's a PR to libc to fix it. However, it's stuck
+ // forever due to backwards compatibility concerns. Even though there's a
+ // workaround, libc refuses to merge it. I think it's just too complicated
+ // for them to want to think about right now, because that project is
+ // short-staffed. So we define it here instead, so we won't have to wait on
+ // libc.
+ // https://github.com/rust-lang/libc/pull/2813
+ #[cfg(target_os = "freebsd")]
+ mod ffi {
+ use std::{fmt, hash};
+
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ #[repr(C)]
+ pub struct __c_anonymous_sigev_thread {
+ pub _function: *mut libc::c_void, // Actually a function pointer
+ pub _attribute: *mut libc::pthread_attr_t,
+ }
+ #[derive(Clone, Copy)]
+ // This will never be used on its own, and its parent has a Debug impl,
+ // so it doesn't need one.
+ #[allow(missing_debug_implementations)]
+ #[repr(C)]
+ pub union __c_anonymous_sigev_un {
+ pub _threadid: libc::__lwpid_t,
+ pub _sigev_thread: __c_anonymous_sigev_thread,
+ pub _kevent_flags: libc::c_ushort,
+ __spare__: [libc::c_long; 8],
+ }
+
+ #[derive(Clone, Copy)]
+ #[repr(C)]
+ pub struct sigevent {
+ pub sigev_notify: libc::c_int,
+ pub sigev_signo: libc::c_int,
+ pub sigev_value: libc::sigval,
+ pub _sigev_un: __c_anonymous_sigev_un,
+ }
+
+ impl fmt::Debug for sigevent {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut ds = f.debug_struct("sigevent");
+ ds.field("sigev_notify", &self.sigev_notify)
+ .field("sigev_signo", &self.sigev_signo)
+ .field("sigev_value", &self.sigev_value);
+ // Safe because we check the sigev_notify discriminant
+ unsafe {
+ match self.sigev_notify {
+ libc::SIGEV_KEVENT => {
+ ds.field("sigev_notify_kevent_flags", &self._sigev_un._kevent_flags);
+ }
+ libc::SIGEV_THREAD_ID => {
+ ds.field("sigev_notify_thread_id", &self._sigev_un._threadid);
+ }
+ libc::SIGEV_THREAD => {
+ ds.field("sigev_notify_function", &self._sigev_un._sigev_thread._function);
+ ds.field("sigev_notify_attributes", &self._sigev_un._sigev_thread._attribute);
+ }
+ _ => ()
+ };
+ }
+ ds.finish()
+ }
+ }
+
+ impl PartialEq for sigevent {
+ fn eq(&self, other: &Self) -> bool {
+ let mut equals = self.sigev_notify == other.sigev_notify;
+ equals &= self.sigev_signo == other.sigev_signo;
+ equals &= self.sigev_value == other.sigev_value;
+ // Safe because we check the sigev_notify discriminant
+ unsafe {
+ match self.sigev_notify {
+ libc::SIGEV_KEVENT => {
+ equals &= self._sigev_un._kevent_flags == other._sigev_un._kevent_flags;
+ }
+ libc::SIGEV_THREAD_ID => {
+ equals &= self._sigev_un._threadid == other._sigev_un._threadid;
+ }
+ libc::SIGEV_THREAD => {
+ equals &= self._sigev_un._sigev_thread == other._sigev_un._sigev_thread;
+ }
+ _ => /* The union field is don't care */ ()
+ }
+ }
+ equals
+ }
+ }
+
+ impl Eq for sigevent {}
+
+ impl hash::Hash for sigevent {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ self.sigev_notify.hash(s);
+ self.sigev_signo.hash(s);
+ self.sigev_value.hash(s);
+ // Safe because we check the sigev_notify discriminant
+ unsafe {
+ match self.sigev_notify {
+ libc::SIGEV_KEVENT => {
+ self._sigev_un._kevent_flags.hash(s);
+ }
+ libc::SIGEV_THREAD_ID => {
+ self._sigev_un._threadid.hash(s);
+ }
+ libc::SIGEV_THREAD => {
+ self._sigev_un._sigev_thread.hash(s);
+ }
+ _ => /* The union field is don't care */ ()
+ }
+ }
+ }
+ }
+ }
/// Used to request asynchronous notification of the completion of certain
/// events, such as POSIX AIO and timers.
#[repr(C)]
- #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ #[derive(Clone, Debug, Eq, Hash, PartialEq)]
+ // It can't be Copy on all platforms.
+ #[allow(missing_copy_implementations)]
pub struct SigEvent {
- sigevent: libc::sigevent
+ sigevent: libc_sigevent
}
impl SigEvent {
@@ -1053,69 +1240,91 @@ mod sigevent {
/// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
/// `SIGEV_SIGNAL`. That field is part of a union that shares space with the
/// more genuinely useful `sigev_notify_thread_id`
- // Allow invalid_value warning on Fuchsia only.
- // See https://github.com/nix-rust/nix/issues/1441
- #[cfg_attr(target_os = "fuchsia", allow(invalid_value))]
pub fn new(sigev_notify: SigevNotify) -> SigEvent {
- let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() };
- sev.sigev_notify = match sigev_notify {
- SigevNotify::SigevNone => libc::SIGEV_NONE,
- SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
+ let mut sev: libc_sigevent = unsafe { mem::zeroed() };
+ match sigev_notify {
+ SigevNotify::SigevNone => {
+ sev.sigev_notify = libc::SIGEV_NONE;
+ },
+ SigevNotify::SigevSignal{signal, si_value} => {
+ sev.sigev_notify = libc::SIGEV_SIGNAL;
+ sev.sigev_signo = signal as libc::c_int;
+ sev.sigev_value.sival_ptr = si_value as *mut libc::c_void
+ },
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
- SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
+ SigevNotify::SigevKevent{kq, udata} => {
+ sev.sigev_notify = libc::SIGEV_KEVENT;
+ sev.sigev_signo = kq;
+ sev.sigev_value.sival_ptr = udata as *mut libc::c_void;
+ },
#[cfg(target_os = "freebsd")]
- SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
- #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
- SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
- #[cfg(all(target_os = "linux", target_env = "uclibc"))]
- SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
- #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
- SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined
- };
- sev.sigev_signo = match sigev_notify {
- SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
- #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
- SigevNotify::SigevKevent{ kq, ..} => kq,
- #[cfg(any(target_os = "linux", target_os = "freebsd"))]
- SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
- _ => 0
- };
- sev.sigev_value.sival_ptr = match sigev_notify {
- SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
- SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
- #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
- SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
- #[cfg(any(target_os = "freebsd", target_os = "linux"))]
- SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
- };
- SigEvent::set_tid(&mut sev, &sigev_notify);
+ #[cfg(feature = "event")]
+ SigevNotify::SigevKeventFlags{kq, udata, flags} => {
+ sev.sigev_notify = libc::SIGEV_KEVENT;
+ sev.sigev_signo = kq;
+ sev.sigev_value.sival_ptr = udata as *mut libc::c_void;
+ sev._sigev_un._kevent_flags = flags.bits();
+ },
+ #[cfg(target_os = "freebsd")]
+ SigevNotify::SigevThreadId{signal, thread_id, si_value} => {
+ sev.sigev_notify = libc::SIGEV_THREAD_ID;
+ sev.sigev_signo = signal as libc::c_int;
+ sev.sigev_value.sival_ptr = si_value as *mut libc::c_void;
+ sev._sigev_un._threadid = thread_id;
+ }
+ #[cfg(any(target_env = "gnu", target_env = "uclibc"))]
+ SigevNotify::SigevThreadId{signal, thread_id, si_value} => {
+ sev.sigev_notify = libc::SIGEV_THREAD_ID;
+ sev.sigev_signo = signal as libc::c_int;
+ sev.sigev_value.sival_ptr = si_value as *mut libc::c_void;
+ sev.sigev_notify_thread_id = thread_id;
+ }
+ }
SigEvent{sigevent: sev}
}
- #[cfg(any(target_os = "freebsd", target_os = "linux"))]
- fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
- sev.sigev_notify_thread_id = match *sigev_notify {
- SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
- _ => 0 as type_of_thread_id
- };
- }
-
- #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
- fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
+ /// Return a copy of the inner structure
+ #[cfg(target_os = "freebsd")]
+ pub fn sigevent(&self) -> libc::sigevent {
+ // Safe because they're really the same structure. See
+ // https://github.com/rust-lang/libc/pull/2813
+ unsafe {
+ mem::transmute::<libc_sigevent, libc::sigevent>(self.sigevent)
+ }
}
/// Return a copy of the inner structure
+ #[cfg(not(target_os = "freebsd"))]
pub fn sigevent(&self) -> libc::sigevent {
self.sigevent
}
/// Returns a mutable pointer to the `sigevent` wrapped by `self`
+ #[cfg(target_os = "freebsd")]
+ pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
+ // Safe because they're really the same structure. See
+ // https://github.com/rust-lang/libc/pull/2813
+ &mut self.sigevent as *mut libc_sigevent as *mut libc::sigevent
+ }
+
+ /// Returns a mutable pointer to the `sigevent` wrapped by `self`
+ #[cfg(not(target_os = "freebsd"))]
pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
&mut self.sigevent
}
}
impl<'a> From<&'a libc::sigevent> for SigEvent {
+ #[cfg(target_os = "freebsd")]
+ fn from(sigevent: &libc::sigevent) -> Self {
+ // Safe because they're really the same structure. See
+ // https://github.com/rust-lang/libc/pull/2813
+ let sigevent = unsafe {
+ mem::transmute::<libc::sigevent, libc_sigevent>(*sigevent)
+ };
+ SigEvent{ sigevent }
+ }
+ #[cfg(not(target_os = "freebsd"))]
fn from(sigevent: &libc::sigevent) -> Self {
SigEvent{ sigevent: *sigevent }
}
diff --git a/src/sys/signalfd.rs b/src/sys/signalfd.rs
index 095e590..2b80ea6 100644
--- a/src/sys/signalfd.rs
+++ b/src/sys/signalfd.rs
@@ -17,12 +17,11 @@
//! signal handlers.
use crate::errno::Errno;
pub use crate::sys::signal::{self, SigSet};
-use crate::unistd;
use crate::Result;
pub use libc::signalfd_siginfo as siginfo;
use std::mem;
-use std::os::unix::io::{AsRawFd, RawFd};
+use std::os::unix::io::{AsRawFd, RawFd, FromRawFd, OwnedFd, AsFd, BorrowedFd};
libc_bitflags! {
pub struct SfdFlags: libc::c_int {
@@ -31,7 +30,6 @@ libc_bitflags! {
}
}
-pub const SIGNALFD_NEW: RawFd = -1;
#[deprecated(since = "0.23.0", note = "use mem::size_of::<siginfo>() instead")]
pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::<siginfo>();
@@ -46,13 +44,19 @@ pub const SIGNALFD_SIGINFO_SIZE: usize = mem::size_of::<siginfo>();
/// signalfd (the default handler will be invoked instead).
///
/// See [the signalfd man page for more information](https://man7.org/linux/man-pages/man2/signalfd.2.html)
-pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> {
+#[deprecated(since = "0.27.0", note = "Use SignalFd instead")]
+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());
unsafe {
Errno::result(libc::signalfd(
- fd as libc::c_int,
+ raw_fd,
mask.as_ref(),
flags.bits(),
- ))
+ )).map(|raw_fd|FromRawFd::from_raw_fd(raw_fd))
}
}
@@ -82,8 +86,8 @@ pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> {
/// Err(err) => (), // some error happend
/// }
/// ```
-#[derive(Debug, Eq, Hash, PartialEq)]
-pub struct SignalFd(RawFd);
+#[derive(Debug)]
+pub struct SignalFd(OwnedFd);
impl SignalFd {
pub fn new(mask: &SigSet) -> Result<SignalFd> {
@@ -91,13 +95,13 @@ impl SignalFd {
}
pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result<SignalFd> {
- let fd = signalfd(SIGNALFD_NEW, mask, flags)?;
+ let fd = _signalfd(None::<OwnedFd>, mask, flags)?;
Ok(SignalFd(fd))
}
pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> {
- signalfd(self.0, mask, SfdFlags::empty()).map(drop)
+ _signalfd(Some(self.0.as_fd()), mask, SfdFlags::empty()).map(drop)
}
pub fn read_signal(&mut self) -> Result<Option<siginfo>> {
@@ -105,7 +109,7 @@ impl SignalFd {
let size = mem::size_of_val(&buffer);
let res = Errno::result(unsafe {
- libc::read(self.0, buffer.as_mut_ptr() as *mut libc::c_void, size)
+ libc::read(self.0.as_raw_fd(), buffer.as_mut_ptr() as *mut libc::c_void, size)
})
.map(|r| r as usize);
match res {
@@ -117,18 +121,14 @@ impl SignalFd {
}
}
-impl Drop for SignalFd {
- fn drop(&mut self) {
- let e = unistd::close(self.0);
- if !std::thread::panicking() && e == Err(Errno::EBADF) {
- panic!("Closing an invalid file descriptor!");
- };
+impl AsFd for SignalFd {
+ fn as_fd(&self) -> BorrowedFd {
+ self.0.as_fd()
}
}
-
impl AsRawFd for SignalFd {
fn as_raw_fd(&self) -> RawFd {
- self.0
+ self.0.as_raw_fd()
}
}
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index 4e565a5..1783531 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -9,11 +9,12 @@
target_os = "netbsd",
target_os = "openbsd",
target_os = "haiku",
- target_os = "fuchsia"
+ target_os = "fuchsia",
+ target_os = "aix",
))]
#[cfg(feature = "net")]
pub use self::datalink::LinkAddr;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
pub use self::vsock::VsockAddr;
use super::sa_family_t;
use crate::errno::Errno;
@@ -33,29 +34,22 @@ use std::convert::TryInto;
use std::ffi::OsStr;
use std::hash::{Hash, Hasher};
use std::os::unix::ffi::OsStrExt;
-#[cfg(any(target_os = "ios", target_os = "macos"))]
-use std::os::unix::io::RawFd;
use std::path::Path;
use std::{fmt, mem, net, ptr, slice};
/// Convert a std::net::Ipv4Addr into the libc form.
#[cfg(feature = "net")]
pub(crate) const fn ipv4addr_to_libc(addr: net::Ipv4Addr) -> libc::in_addr {
- static_assertions::assert_eq_size!(net::Ipv4Addr, libc::in_addr);
- // Safe because both types have the same memory layout, and no fancy Drop
- // impls.
- unsafe {
- mem::transmute(addr)
+ libc::in_addr {
+ s_addr: u32::from_ne_bytes(addr.octets())
}
}
/// Convert a std::net::Ipv6Addr into the libc form.
#[cfg(feature = "net")]
pub(crate) const fn ipv6addr_to_libc(addr: &net::Ipv6Addr) -> libc::in6_addr {
- static_assertions::assert_eq_size!(net::Ipv6Addr, libc::in6_addr);
- // Safe because both are Newtype wrappers around the same libc type
- unsafe {
- mem::transmute(*addr)
+ libc::in6_addr {
+ s6_addr: addr.octets()
}
}
@@ -80,6 +74,13 @@ pub enum AddressFamily {
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Netlink = libc::AF_NETLINK,
+ /// Kernel interface for interacting with the routing table
+ #[cfg(not(any(
+ target_os = "redox",
+ target_os = "linux",
+ target_os = "android"
+ )))]
+ Route = libc::PF_ROUTE,
/// Low level packet interface (see [`packet(7)`](https://man7.org/linux/man-pages/man7/packet.7.html))
#[cfg(any(
target_os = "android",
@@ -99,8 +100,11 @@ pub enum AddressFamily {
#[cfg_attr(docsrs, doc(cfg(all())))]
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/))
@@ -129,7 +133,7 @@ pub enum AddressFamily {
#[cfg_attr(docsrs, doc(cfg(all())))]
Rose = libc::AF_ROSE,
/// DECet protocol sockets.
- #[cfg(not(target_os = "haiku"))]
+ #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
Decnet = libc::AF_DECnet,
/// Reserved for "802.2LLC project"; never used.
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -161,7 +165,7 @@ pub enum AddressFamily {
#[cfg_attr(docsrs, doc(cfg(all())))]
Rds = libc::AF_RDS,
/// IBM SNA
- #[cfg(not(target_os = "haiku"))]
+ #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
Sna = libc::AF_SNA,
/// Socket interface over IrDA
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -198,10 +202,12 @@ pub enum AddressFamily {
Tipc = libc::AF_TIPC,
/// Bluetooth low-level socket protocol
#[cfg(not(any(
+ target_os = "aix",
target_os = "illumos",
target_os = "ios",
target_os = "macos",
- target_os = "solaris"
+ target_os = "solaris",
+ target_os = "redox",
)))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Bluetooth = libc::AF_BLUETOOTH,
@@ -216,9 +222,11 @@ pub enum AddressFamily {
RxRpc = libc::AF_RXRPC,
/// New "modular ISDN" driver interface protocol
#[cfg(not(any(
+ target_os = "aix",
target_os = "illumos",
target_os = "solaris",
- target_os = "haiku"
+ target_os = "haiku",
+ target_os = "redox",
)))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Isdn = libc::AF_ISDN,
@@ -244,7 +252,7 @@ pub enum AddressFamily {
#[cfg_attr(docsrs, doc(cfg(all())))]
Nfc = libc::AF_NFC,
/// VMWare VSockets protocol for hypervisor-guest interaction.
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
Vsock = libc::AF_VSOCK,
/// ARPANet IMP addresses
@@ -421,6 +429,12 @@ impl AddressFamily {
libc::AF_NETLINK => Some(AddressFamily::Netlink),
#[cfg(any(target_os = "macos", target_os = "macos"))]
libc::AF_SYSTEM => Some(AddressFamily::System),
+ #[cfg(not(any(
+ target_os = "redox",
+ target_os = "linux",
+ target_os = "android"
+ )))]
+ libc::PF_ROUTE => Some(AddressFamily::Route),
#[cfg(any(target_os = "android", target_os = "linux"))]
libc::AF_PACKET => Some(AddressFamily::Packet),
#[cfg(any(
@@ -433,315 +447,13 @@ impl AddressFamily {
target_os = "openbsd"
))]
libc::AF_LINK => Some(AddressFamily::Link),
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
libc::AF_VSOCK => Some(AddressFamily::Vsock),
_ => None,
}
}
}
-feature! {
-#![feature = "net"]
-
-#[deprecated(
- since = "0.24.0",
- note = "use SockaddrIn, SockaddrIn6, or SockaddrStorage instead"
-)]
-#[allow(missing_docs)] // Since they're all deprecated anyway
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-pub enum InetAddr {
- V4(libc::sockaddr_in),
- V6(libc::sockaddr_in6),
-}
-
-#[allow(missing_docs)] // It's deprecated anyway
-#[allow(deprecated)]
-impl InetAddr {
- #[allow(clippy::needless_update)] // It isn't needless on all OSes
- pub fn from_std(std: &net::SocketAddr) -> InetAddr {
- match *std {
- net::SocketAddr::V4(ref addr) => {
- InetAddr::V4(libc::sockaddr_in {
- #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
- target_os = "haiku", target_os = "hermit",
- target_os = "ios", target_os = "macos",
- target_os = "netbsd", target_os = "openbsd"))]
- sin_len: mem::size_of::<libc::sockaddr_in>() as u8,
- sin_family: AddressFamily::Inet as sa_family_t,
- sin_port: addr.port().to_be(), // network byte order
- sin_addr: Ipv4Addr::from_std(addr.ip()).0,
- .. unsafe { mem::zeroed() }
- })
- }
- net::SocketAddr::V6(ref addr) => {
- InetAddr::V6(libc::sockaddr_in6 {
- #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
- target_os = "haiku", target_os = "hermit",
- target_os = "ios", target_os = "macos",
- target_os = "netbsd", target_os = "openbsd"))]
- sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8,
- sin6_family: AddressFamily::Inet6 as sa_family_t,
- sin6_port: addr.port().to_be(), // network byte order
- sin6_addr: Ipv6Addr::from_std(addr.ip()).0,
- sin6_flowinfo: addr.flowinfo(), // host byte order
- sin6_scope_id: addr.scope_id(), // host byte order
- .. unsafe { mem::zeroed() }
- })
- }
- }
- }
-
- #[allow(clippy::needless_update)] // It isn't needless on all OSes
- pub fn new(ip: IpAddr, port: u16) -> InetAddr {
- match ip {
- IpAddr::V4(ref ip) => {
- InetAddr::V4(libc::sockaddr_in {
- sin_family: AddressFamily::Inet as sa_family_t,
- sin_port: port.to_be(),
- sin_addr: ip.0,
- .. unsafe { mem::zeroed() }
- })
- }
- IpAddr::V6(ref ip) => {
- InetAddr::V6(libc::sockaddr_in6 {
- sin6_family: AddressFamily::Inet6 as sa_family_t,
- sin6_port: port.to_be(),
- sin6_addr: ip.0,
- .. unsafe { mem::zeroed() }
- })
- }
- }
- }
- /// Gets the IP address associated with this socket address.
- pub const fn ip(&self) -> IpAddr {
- match *self {
- InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)),
- InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)),
- }
- }
-
- /// Gets the port number associated with this socket address
- pub const fn port(&self) -> u16 {
- match *self {
- InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port),
- InetAddr::V4(ref sa) => u16::from_be(sa.sin_port),
- }
- }
-
- pub fn to_std(&self) -> net::SocketAddr {
- match *self {
- InetAddr::V4(ref sa) => net::SocketAddr::V4(
- net::SocketAddrV4::new(
- Ipv4Addr(sa.sin_addr).to_std(),
- self.port())),
- InetAddr::V6(ref sa) => net::SocketAddr::V6(
- net::SocketAddrV6::new(
- Ipv6Addr(sa.sin6_addr).to_std(),
- self.port(),
- sa.sin6_flowinfo,
- sa.sin6_scope_id)),
- }
- }
-
- #[deprecated(since = "0.23.0", note = "use .to_string() instead")]
- pub fn to_str(&self) -> String {
- format!("{}", self)
- }
-}
-
-#[allow(deprecated)]
-impl fmt::Display for InetAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()),
- InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()),
- }
- }
-}
-
-/*
- *
- * ===== IpAddr =====
- *
- */
-#[allow(missing_docs)] // Since they're all deprecated anyway
-#[allow(deprecated)]
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-#[deprecated(
- since = "0.24.0",
- note = "Use std::net::IpAddr instead"
-)]
-pub enum IpAddr {
- V4(Ipv4Addr),
- V6(Ipv6Addr),
-}
-
-#[allow(deprecated)]
-#[allow(missing_docs)] // Since they're all deprecated anyway
-impl IpAddr {
- /// Create a new IpAddr that contains an IPv4 address.
- ///
- /// The result will represent the IP address a.b.c.d
- pub const fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
- IpAddr::V4(Ipv4Addr::new(a, b, c, d))
- }
-
- /// Create a new IpAddr that contains an IPv6 address.
- ///
- /// The result will represent the IP address a:b:c:d:e:f
- #[allow(clippy::many_single_char_names)]
- #[allow(clippy::too_many_arguments)]
- pub const fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr {
- IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
- }
-
- pub fn from_std(std: &net::IpAddr) -> IpAddr {
- match *std {
- net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)),
- net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)),
- }
- }
-
- pub const fn to_std(&self) -> net::IpAddr {
- match *self {
- IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()),
- IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()),
- }
- }
-}
-
-#[allow(deprecated)]
-impl fmt::Display for IpAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- IpAddr::V4(ref v4) => v4.fmt(f),
- IpAddr::V6(ref v6) => v6.fmt(f)
- }
- }
-}
-
-/*
- *
- * ===== Ipv4Addr =====
- *
- */
-
-#[deprecated(
- since = "0.24.0",
- note = "Use std::net::Ipv4Addr instead"
-)]
-#[allow(missing_docs)] // Since they're all deprecated anyway
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-#[repr(transparent)]
-pub struct Ipv4Addr(pub libc::in_addr);
-
-#[allow(deprecated)]
-#[allow(missing_docs)] // Since they're all deprecated anyway
-impl Ipv4Addr {
- #[allow(clippy::identity_op)] // More readable this way
- pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
- let ip = (((a as u32) << 24) |
- ((b as u32) << 16) |
- ((c as u32) << 8) |
- ((d as u32) << 0)).to_be();
-
- Ipv4Addr(libc::in_addr { s_addr: ip })
- }
-
- // Use pass by reference for symmetry with Ipv6Addr::from_std
- #[allow(clippy::trivially_copy_pass_by_ref)]
- pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr {
- let bits = std.octets();
- Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
- }
-
- pub const fn any() -> Ipv4Addr {
- Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY })
- }
-
- pub const fn octets(self) -> [u8; 4] {
- let bits = u32::from_be(self.0.s_addr);
- [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
- }
-
- pub const fn to_std(self) -> net::Ipv4Addr {
- let bits = self.octets();
- net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
- }
-}
-
-#[allow(deprecated)]
-impl fmt::Display for Ipv4Addr {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- let octets = self.octets();
- write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
- }
-}
-
-/*
- *
- * ===== Ipv6Addr =====
- *
- */
-
-#[deprecated(
- since = "0.24.0",
- note = "Use std::net::Ipv6Addr instead"
-)]
-#[allow(missing_docs)] // Since they're all deprecated anyway
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-#[repr(transparent)]
-pub struct Ipv6Addr(pub libc::in6_addr);
-
-// Note that IPv6 addresses are stored in big endian order on all architectures.
-// See https://tools.ietf.org/html/rfc1700 or consult your favorite search
-// engine.
-
-macro_rules! to_u8_array {
- ($($num:ident),*) => {
- [ $(($num>>8) as u8, ($num&0xff) as u8,)* ]
- }
-}
-
-macro_rules! to_u16_array {
- ($slf:ident, $($first:expr, $second:expr),*) => {
- [$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*]
- }
-}
-
-#[allow(deprecated)]
-#[allow(missing_docs)] // Since they're all deprecated anyway
-impl Ipv6Addr {
- #[allow(clippy::many_single_char_names)]
- #[allow(clippy::too_many_arguments)]
- pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
- Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)})
- }
-
- pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr {
- let s = std.segments();
- Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
- }
-
- /// Return the eight 16-bit segments that make up this address
- pub const fn segments(&self) -> [u16; 8] {
- to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
- }
-
- pub const fn to_std(&self) -> net::Ipv6Addr {
- let s = self.segments();
- net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
- }
-}
-
-#[allow(deprecated)]
-impl fmt::Display for Ipv6Addr {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- self.to_std().fmt(fmt)
- }
-}
-}
-
/// A wrapper around `sockaddr_un`.
#[derive(Clone, Copy, Debug)]
#[repr(C)]
@@ -755,7 +467,8 @@ pub struct UnixAddr {
target_os = "android",
target_os = "fuchsia",
target_os = "illumos",
- target_os = "linux"
+ target_os = "linux",
+ target_os = "redox",
))]
sun_len: u8,
}
@@ -775,6 +488,7 @@ enum UnixAddrKind<'a> {
}
impl<'a> UnixAddrKind<'a> {
/// Safety: sun & sun_len must be valid
+ #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms
unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self {
assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path));
let path_len =
@@ -811,6 +525,7 @@ impl<'a> UnixAddrKind<'a> {
impl UnixAddr {
/// Create a new sockaddr_un representing a filesystem path.
+ #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms
pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> {
path.with_nix_path(|cstr| unsafe {
let mut ret = libc::sockaddr_un {
@@ -858,6 +573,7 @@ impl UnixAddr {
/// processes to communicate with processes having a different filesystem view.
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
+ #[allow(clippy::unnecessary_cast)] // Not unnecessary on all platforms
pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> {
unsafe {
let mut ret = libc::sockaddr_un {
@@ -891,10 +607,11 @@ impl UnixAddr {
pub fn new_unnamed() -> UnixAddr {
let ret = libc::sockaddr_un {
sun_family: AddressFamily::Unix as sa_family_t,
- .. unsafe { mem::zeroed() }
+ ..unsafe { mem::zeroed() }
};
- let sun_len: u8 = offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap();
+ let sun_len: u8 =
+ offset_of!(libc::sockaddr_un, sun_path).try_into().unwrap();
unsafe { UnixAddr::from_raw_parts(ret, sun_len) }
}
@@ -918,7 +635,8 @@ impl UnixAddr {
if #[cfg(any(target_os = "android",
target_os = "fuchsia",
target_os = "illumos",
- target_os = "linux"
+ target_os = "linux",
+ target_os = "redox",
))]
{
UnixAddr { sun, sun_len }
@@ -984,7 +702,8 @@ impl UnixAddr {
if #[cfg(any(target_os = "android",
target_os = "fuchsia",
target_os = "illumos",
- target_os = "linux"
+ target_os = "linux",
+ target_os = "redox",
))]
{
self.sun_len
@@ -1030,7 +749,8 @@ impl SockaddrLike for UnixAddr {
if #[cfg(any(target_os = "android",
target_os = "fuchsia",
target_os = "illumos",
- target_os = "linux"
+ target_os = "linux",
+ target_os = "redox",
))] {
let su_len = len.unwrap_or(
mem::size_of::<libc::sockaddr_un>() as libc::socklen_t
@@ -1049,6 +769,22 @@ 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> {
+ // `new_length` is only used on some platforms, so it must be provided even when not used
+ #![allow(unused_variables)]
+ cfg_if! {
+ if #[cfg(any(target_os = "android",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "redox",
+ ))] {
+ self.sun_len = new_length as u8;
+ }
+ };
+ Ok(())
+ }
}
impl AsRef<libc::sockaddr_un> for UnixAddr {
@@ -1139,9 +875,10 @@ pub trait SockaddrLike: private::SockaddrLikePriv {
/// One common use is to match on the family of a union type, like this:
/// ```
/// # use nix::sys::socket::*;
+ /// # use std::os::unix::io::AsRawFd;
/// let fd = socket(AddressFamily::Inet, SockType::Stream,
/// SockFlag::empty(), None).unwrap();
- /// let ss: SockaddrStorage = getsockname(fd).unwrap();
+ /// let ss: SockaddrStorage = getsockname(fd.as_raw_fd()).unwrap();
/// match ss.family().unwrap() {
/// AddressFamily::Inet => println!("{}", ss.as_sockaddr_in().unwrap()),
/// AddressFamily::Inet6 => println!("{}", ss.as_sockaddr_in6().unwrap()),
@@ -1198,7 +935,32 @@ pub trait SockaddrLike: private::SockaddrLikePriv {
{
mem::size_of::<Self>() as libc::socklen_t
}
+
+ /// Set the length of this socket address
+ ///
+ /// This method may only be called on socket addresses whose lengths are dynamic, and it
+ /// returns an error if called on a type whose length is static.
+ ///
+ /// # Safety
+ ///
+ /// `new_length` must be a valid length for this type of address. Specifically, reads of that
+ /// length from `self` must be valid.
+ #[doc(hidden)]
+ unsafe fn set_length(&mut self, _new_length: usize) -> std::result::Result<(), SocketAddressLengthNotDynamic> {
+ Err(SocketAddressLengthNotDynamic)
+ }
+}
+
+/// The error returned by [`SockaddrLike::set_length`] on an address whose length is statically
+/// fixed.
+#[derive(Copy, Clone, Debug)]
+pub struct SocketAddressLengthNotDynamic;
+impl fmt::Display for SocketAddressLengthNotDynamic {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("Attempted to set length on socket whose length is statically fixed")
+ }
}
+impl std::error::Error for SocketAddressLengthNotDynamic {}
impl private::SockaddrLikePriv for () {
fn as_mut_ptr(&mut self) -> *mut libc::sockaddr {
@@ -1235,9 +997,6 @@ impl SockaddrLike for () {
}
/// An IPv4 socket address
-// This is identical to net::SocketAddrV4. But the standard library
-// doesn't allow direct access to the libc fields, which we need. So we
-// reimplement it here.
#[cfg(feature = "net")]
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
@@ -1260,6 +1019,7 @@ impl SockaddrIn {
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
+ target_os = "aix",
target_os = "haiku",
target_os = "openbsd"
))]
@@ -1502,11 +1262,12 @@ impl std::str::FromStr for SockaddrIn6 {
/// ```
/// # use nix::sys::socket::*;
/// # use std::str::FromStr;
+/// # use std::os::unix::io::AsRawFd;
/// let localhost = SockaddrIn::from_str("127.0.0.1:8081").unwrap();
/// let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(),
/// None).unwrap();
-/// bind(fd, &localhost).expect("bind");
-/// let ss: SockaddrStorage = getsockname(fd).expect("getsockname");
+/// bind(fd.as_raw_fd(), &localhost).expect("bind");
+/// let ss: SockaddrStorage = getsockname(fd.as_raw_fd()).expect("getsockname");
/// assert_eq!(&localhost, ss.as_sockaddr_in().unwrap());
/// ```
#[derive(Clone, Copy, Eq)]
@@ -1515,7 +1276,7 @@ pub union SockaddrStorage {
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
alg: AlgAddr,
- #[cfg(feature = "net")]
+ #[cfg(all(feature = "net", not(target_os = "redox")))]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
dl: LinkAddr,
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -1532,7 +1293,7 @@ pub union SockaddrStorage {
sin6: SockaddrIn6,
ss: libc::sockaddr_storage,
su: UnixAddr,
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
vsock: VsockAddr,
}
@@ -1567,7 +1328,9 @@ impl SockaddrLike for SockaddrStorage {
if i32::from(ss.ss_family) == libc::AF_UNIX {
// Safe because we UnixAddr is strictly smaller than
// SockaddrStorage, and we just initialized the structure.
- (*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr)).sun_len = len as u8;
+ (*(&mut ss as *mut libc::sockaddr_storage
+ as *mut UnixAddr))
+ .sun_len = len as u8;
}
Some(Self { ss })
}
@@ -1622,7 +1385,7 @@ impl SockaddrLike for SockaddrStorage {
libc::AF_SYSTEM => {
SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl })
}
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))]
libc::AF_VSOCK => {
VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock })
}
@@ -1642,7 +1405,16 @@ impl SockaddrLike for SockaddrStorage {
// The UnixAddr type knows its own length
Some(ua) => ua.len(),
// For all else, we're just a boring SockaddrStorage
- None => mem::size_of_val(self) as libc::socklen_t
+ None => mem::size_of_val(self) as libc::socklen_t,
+ }
+ }
+
+ 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)
+ },
+ None => Err(SocketAddressLengthNotDynamic),
}
}
}
@@ -1702,12 +1474,13 @@ impl SockaddrStorage {
}
}
// Sanity checks
- if self.family() != Some(AddressFamily::Unix) ||
- len < offset_of!(libc::sockaddr_un, sun_path) ||
- len > mem::size_of::<libc::sockaddr_un>() {
+ if self.family() != Some(AddressFamily::Unix)
+ || len < offset_of!(libc::sockaddr_un, sun_path)
+ || len > mem::size_of::<libc::sockaddr_un>()
+ {
None
} else {
- Some(unsafe{&self.su})
+ Some(unsafe { &self.su })
}
}
@@ -1731,12 +1504,13 @@ impl SockaddrStorage {
}
}
// Sanity checks
- if self.family() != Some(AddressFamily::Unix) ||
- len < offset_of!(libc::sockaddr_un, sun_path) ||
- len > mem::size_of::<libc::sockaddr_un>() {
+ if self.family() != Some(AddressFamily::Unix)
+ || len < offset_of!(libc::sockaddr_un, sun_path)
+ || len > mem::size_of::<libc::sockaddr_un>()
+ {
None
} else {
- Some(unsafe{&mut self.su})
+ Some(unsafe { &mut self.su })
}
}
@@ -1787,7 +1561,7 @@ impl SockaddrStorage {
accessors! {as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr,
AddressFamily::System, libc::sockaddr_ctl, sctl}
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr,
AddressFamily::Vsock, libc::sockaddr_vm, vsock}
@@ -1837,7 +1611,7 @@ impl fmt::Display for SockaddrStorage {
#[cfg(feature = "ioctl")]
libc::AF_SYSTEM => self.sctl.fmt(f),
libc::AF_UNIX => self.su.fmt(f),
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
libc::AF_VSOCK => self.vsock.fmt(f),
_ => "<Address family unspecified>".fmt(f),
}
@@ -1911,7 +1685,7 @@ impl Hash for SockaddrStorage {
#[cfg(feature = "ioctl")]
libc::AF_SYSTEM => self.sctl.hash(s),
libc::AF_UNIX => self.su.hash(s),
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
libc::AF_VSOCK => self.vsock.hash(s),
_ => self.ss.hash(s),
}
@@ -1953,7 +1727,7 @@ impl PartialEq for SockaddrStorage {
#[cfg(feature = "ioctl")]
(libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl,
(libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su,
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
(libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock,
_ => false,
}
@@ -1961,7 +1735,7 @@ impl PartialEq for SockaddrStorage {
}
}
-mod private {
+pub(super) mod private {
pub trait SockaddrLikePriv {
/// Returns a mutable raw pointer to the inner structure.
///
@@ -1977,358 +1751,6 @@ mod private {
}
}
-/// Represents a socket address
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-#[deprecated(
- since = "0.24.0",
- note = "use SockaddrLike or SockaddrStorage instead"
-)]
-#[allow(missing_docs)] // Since they're all deprecated anyway
-#[allow(deprecated)]
-#[non_exhaustive]
-pub enum SockAddr {
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Inet(InetAddr),
- Unix(UnixAddr),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- Netlink(NetlinkAddr),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- Alg(AlgAddr),
- #[cfg(all(
- feature = "ioctl",
- any(target_os = "ios", target_os = "macos")
- ))]
- #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))]
- SysControl(SysControlAddr),
- /// Datalink address (MAC)
- #[cfg(any(
- target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
- target_os = "illumos",
- target_os = "netbsd",
- target_os = "openbsd"
- ))]
- #[cfg(feature = "net")]
- #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
- Link(LinkAddr),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- Vsock(VsockAddr),
-}
-
-#[allow(missing_docs)] // Since they're all deprecated anyway
-#[allow(deprecated)]
-impl SockAddr {
- feature! {
- #![feature = "net"]
- pub fn new_inet(addr: InetAddr) -> SockAddr {
- SockAddr::Inet(addr)
- }
- }
-
- pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> {
- Ok(SockAddr::Unix(UnixAddr::new(path)?))
- }
-
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- pub fn new_netlink(pid: u32, groups: u32) -> SockAddr {
- SockAddr::Netlink(NetlinkAddr::new(pid, groups))
- }
-
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr {
- SockAddr::Alg(AlgAddr::new(alg_type, alg_name))
- }
-
- feature! {
- #![feature = "ioctl"]
- #[cfg(any(target_os = "ios", target_os = "macos"))]
- pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
- SysControlAddr::from_name(sockfd, name, unit).map(SockAddr::SysControl)
- }
- }
-
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg_attr(docsrs, doc(cfg(all())))]
- pub fn new_vsock(cid: u32, port: u32) -> SockAddr {
- SockAddr::Vsock(VsockAddr::new(cid, port))
- }
-
- pub fn family(&self) -> AddressFamily {
- match *self {
- #[cfg(feature = "net")]
- SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet,
- #[cfg(feature = "net")]
- SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6,
- SockAddr::Unix(..) => AddressFamily::Unix,
- #[cfg(any(target_os = "android", target_os = "linux"))]
- SockAddr::Netlink(..) => AddressFamily::Netlink,
- #[cfg(any(target_os = "android", target_os = "linux"))]
- SockAddr::Alg(..) => AddressFamily::Alg,
- #[cfg(all(
- feature = "ioctl",
- any(target_os = "ios", target_os = "macos")
- ))]
- SockAddr::SysControl(..) => AddressFamily::System,
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg(feature = "net")]
- SockAddr::Link(..) => AddressFamily::Packet,
- #[cfg(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "illumos",
- target_os = "openbsd"
- ))]
- #[cfg(feature = "net")]
- SockAddr::Link(..) => AddressFamily::Link,
- #[cfg(any(target_os = "android", target_os = "linux"))]
- SockAddr::Vsock(..) => AddressFamily::Vsock,
- }
- }
-
- #[deprecated(since = "0.23.0", note = "use .to_string() instead")]
- pub fn to_str(&self) -> String {
- format!("{}", self)
- }
-
- /// Creates a `SockAddr` struct from libc's sockaddr.
- ///
- /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System.
- /// Returns None for unsupported families.
- ///
- /// # Safety
- ///
- /// unsafe because it takes a raw pointer as argument. The caller must
- /// ensure that the pointer is valid.
- #[cfg(not(target_os = "fuchsia"))]
- #[cfg(feature = "net")]
- pub(crate) unsafe fn from_libc_sockaddr(
- addr: *const libc::sockaddr,
- ) -> Option<SockAddr> {
- if addr.is_null() {
- None
- } else {
- match AddressFamily::from_i32(i32::from((*addr).sa_family)) {
- Some(AddressFamily::Unix) => None,
- #[cfg(feature = "net")]
- Some(AddressFamily::Inet) => Some(SockAddr::Inet(
- InetAddr::V4(ptr::read_unaligned(addr as *const _)),
- )),
- #[cfg(feature = "net")]
- Some(AddressFamily::Inet6) => Some(SockAddr::Inet(
- InetAddr::V6(ptr::read_unaligned(addr as *const _)),
- )),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- Some(AddressFamily::Netlink) => Some(SockAddr::Netlink(
- NetlinkAddr(ptr::read_unaligned(addr as *const _)),
- )),
- #[cfg(all(
- feature = "ioctl",
- any(target_os = "ios", target_os = "macos")
- ))]
- Some(AddressFamily::System) => Some(SockAddr::SysControl(
- SysControlAddr(ptr::read_unaligned(addr as *const _)),
- )),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg(feature = "net")]
- Some(AddressFamily::Packet) => Some(SockAddr::Link(LinkAddr(
- ptr::read_unaligned(addr as *const _),
- ))),
- #[cfg(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "illumos",
- target_os = "openbsd"
- ))]
- #[cfg(feature = "net")]
- Some(AddressFamily::Link) => {
- let ether_addr =
- LinkAddr(ptr::read_unaligned(addr as *const _));
- if ether_addr.is_empty() {
- None
- } else {
- Some(SockAddr::Link(ether_addr))
- }
- }
- #[cfg(any(target_os = "android", target_os = "linux"))]
- Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(VsockAddr(
- ptr::read_unaligned(addr as *const _),
- ))),
- // Other address families are currently not supported and simply yield a None
- // entry instead of a proper conversion to a `SockAddr`.
- Some(_) | None => None,
- }
- }
- }
-
- /// Conversion from nix's SockAddr type to the underlying libc sockaddr type.
- ///
- /// This is useful for interfacing with other libc functions that don't yet have nix wrappers.
- /// Returns a reference to the underlying data type (as a sockaddr reference) along
- /// with the size of the actual data type. sockaddr is commonly used as a proxy for
- /// a superclass as C doesn't support inheritance, so many functions that take
- /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back.
- pub fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
- match *self {
- #[cfg(feature = "net")]
- SockAddr::Inet(InetAddr::V4(ref addr)) => (
- // This cast is always allowed in C
- unsafe {
- &*(addr as *const libc::sockaddr_in
- as *const libc::sockaddr)
- },
- mem::size_of_val(addr) as libc::socklen_t,
- ),
- #[cfg(feature = "net")]
- SockAddr::Inet(InetAddr::V6(ref addr)) => (
- // This cast is always allowed in C
- unsafe {
- &*(addr as *const libc::sockaddr_in6
- as *const libc::sockaddr)
- },
- mem::size_of_val(addr) as libc::socklen_t,
- ),
- SockAddr::Unix(ref unix_addr) => (
- // This cast is always allowed in C
- unsafe {
- &*(&unix_addr.sun as *const libc::sockaddr_un
- as *const libc::sockaddr)
- },
- unix_addr.sun_len() as libc::socklen_t,
- ),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- SockAddr::Netlink(NetlinkAddr(ref sa)) => (
- // This cast is always allowed in C
- unsafe {
- &*(sa as *const libc::sockaddr_nl as *const libc::sockaddr)
- },
- mem::size_of_val(sa) as libc::socklen_t,
- ),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- SockAddr::Alg(AlgAddr(ref sa)) => (
- // This cast is always allowed in C
- unsafe {
- &*(sa as *const libc::sockaddr_alg as *const libc::sockaddr)
- },
- mem::size_of_val(sa) as libc::socklen_t,
- ),
- #[cfg(all(
- feature = "ioctl",
- any(target_os = "ios", target_os = "macos")
- ))]
- SockAddr::SysControl(SysControlAddr(ref sa)) => (
- // This cast is always allowed in C
- unsafe {
- &*(sa as *const libc::sockaddr_ctl as *const libc::sockaddr)
- },
- mem::size_of_val(sa) as libc::socklen_t,
- ),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg(feature = "net")]
- SockAddr::Link(LinkAddr(ref addr)) => (
- // This cast is always allowed in C
- unsafe {
- &*(addr as *const libc::sockaddr_ll
- as *const libc::sockaddr)
- },
- mem::size_of_val(addr) as libc::socklen_t,
- ),
- #[cfg(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "macos",
- target_os = "illumos",
- target_os = "netbsd",
- target_os = "openbsd"
- ))]
- #[cfg(feature = "net")]
- SockAddr::Link(LinkAddr(ref addr)) => (
- // This cast is always allowed in C
- unsafe {
- &*(addr as *const libc::sockaddr_dl
- as *const libc::sockaddr)
- },
- mem::size_of_val(addr) as libc::socklen_t,
- ),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- SockAddr::Vsock(VsockAddr(ref sa)) => (
- // This cast is always allowed in C
- unsafe {
- &*(sa as *const libc::sockaddr_vm as *const libc::sockaddr)
- },
- mem::size_of_val(sa) as libc::socklen_t,
- ),
- }
- }
-}
-
-#[allow(deprecated)]
-impl fmt::Display for SockAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- #[cfg(feature = "net")]
- SockAddr::Inet(ref inet) => inet.fmt(f),
- SockAddr::Unix(ref unix) => unix.fmt(f),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- SockAddr::Netlink(ref nl) => nl.fmt(f),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- SockAddr::Alg(ref nl) => nl.fmt(f),
- #[cfg(all(
- feature = "ioctl",
- any(target_os = "ios", target_os = "macos")
- ))]
- SockAddr::SysControl(ref sc) => sc.fmt(f),
- #[cfg(any(
- target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "ios",
- target_os = "linux",
- target_os = "macos",
- target_os = "netbsd",
- target_os = "illumos",
- target_os = "openbsd"
- ))]
- #[cfg(feature = "net")]
- SockAddr::Link(ref ether_addr) => ether_addr.fmt(f),
- #[cfg(any(target_os = "android", target_os = "linux"))]
- SockAddr::Vsock(ref svm) => svm.fmt(f),
- }
- }
-}
-
-#[cfg(not(target_os = "fuchsia"))]
-#[cfg(feature = "net")]
-#[allow(deprecated)]
-impl private::SockaddrLikePriv for SockAddr {}
-#[cfg(not(target_os = "fuchsia"))]
-#[cfg(feature = "net")]
-#[allow(deprecated)]
-impl SockaddrLike for SockAddr {
- unsafe fn from_raw(
- addr: *const libc::sockaddr,
- _len: Option<libc::socklen_t>,
- ) -> Option<Self> {
- Self::from_libc_sockaddr(addr)
- }
-}
-
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub mod netlink {
@@ -2738,6 +2160,7 @@ mod datalink {
target_os = "illumos",
target_os = "netbsd",
target_os = "haiku",
+ target_os = "aix",
target_os = "openbsd"
))]
#[cfg_attr(docsrs, doc(cfg(all())))]
@@ -2850,11 +2273,10 @@ mod datalink {
&self.0
}
}
-
}
}
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub mod vsock {
use super::*;
@@ -2900,20 +2322,33 @@ pub mod vsock {
}
impl PartialEq for VsockAddr {
+ #[cfg(any(target_os = "android", target_os = "linux"))]
fn eq(&self, other: &Self) -> bool {
let (inner, other) = (self.0, other.0);
(inner.svm_family, inner.svm_cid, inner.svm_port)
== (other.svm_family, other.svm_cid, other.svm_port)
}
+ #[cfg(target_os = "macos")]
+ fn eq(&self, other: &Self) -> bool {
+ let (inner, other) = (self.0, other.0);
+ (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len)
+ == (other.svm_family, other.svm_cid, other.svm_port, inner.svm_len)
+ }
}
impl Eq for VsockAddr {}
impl Hash for VsockAddr {
+ #[cfg(any(target_os = "android", target_os = "linux"))]
fn hash<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")]
+ 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);
+ }
}
/// VSOCK Address
@@ -2928,6 +2363,10 @@ pub mod vsock {
addr.svm_cid = cid;
addr.svm_port = port;
+ #[cfg(target_os = "macos")]
+ {
+ addr.svm_len = std::mem::size_of::<sockaddr_vm>() as u8;
+ }
VsockAddr(addr)
}
@@ -2980,6 +2419,7 @@ mod tests {
}
}
+ #[cfg(not(target_os = "redox"))]
mod link {
#![allow(clippy::cast_ptr_alignment)]
@@ -3015,7 +2455,7 @@ mod tests {
sdl_slen: 0,
..unsafe { mem::zeroed() }
});
- format!("{}", la);
+ format!("{la}");
}
#[cfg(all(
@@ -3109,6 +2549,7 @@ mod tests {
#[test]
fn size() {
#[cfg(any(
+ target_os = "aix",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
@@ -3137,7 +2578,7 @@ mod tests {
fn display() {
let s = "127.0.0.1:8080";
let addr = SockaddrIn::from_str(s).unwrap();
- assert_eq!(s, format!("{}", addr));
+ assert_eq!(s, format!("{addr}"));
}
#[test]
@@ -3157,7 +2598,7 @@ mod tests {
fn display() {
let s = "[1234:5678:90ab:cdef::1111:2222]:8080";
let addr = SockaddrIn6::from_str(s).unwrap();
- assert_eq!(s, format!("{}", addr));
+ assert_eq!(s, format!("{addr}"));
}
#[test]
@@ -3176,7 +2617,7 @@ mod tests {
nix_sin6.0.sin6_flowinfo = 0x12345678;
nix_sin6.0.sin6_scope_id = 0x9abcdef0;
- let std_sin6 : std::net::SocketAddrV6 = nix_sin6.into();
+ let std_sin6: std::net::SocketAddrV6 = nix_sin6.into();
assert_eq!(nix_sin6, std_sin6.into());
}
}
@@ -3188,9 +2629,8 @@ mod tests {
fn from_sockaddr_un_named() {
let ua = UnixAddr::new("/var/run/mysock").unwrap();
let ptr = ua.as_ptr() as *const libc::sockaddr;
- let ss = unsafe {
- SockaddrStorage::from_raw(ptr, Some(ua.len()))
- }.unwrap();
+ let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) }
+ .unwrap();
assert_eq!(ss.len(), ua.len());
}
@@ -3200,9 +2640,8 @@ mod tests {
let name = String::from("nix\0abstract\0test");
let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap();
let ptr = ua.as_ptr() as *const libc::sockaddr;
- let ss = unsafe {
- SockaddrStorage::from_raw(ptr, Some(ua.len()))
- }.unwrap();
+ let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) }
+ .unwrap();
assert_eq!(ss.len(), ua.len());
}
@@ -3211,9 +2650,8 @@ mod tests {
fn from_sockaddr_un_abstract_unnamed() {
let ua = UnixAddr::new_unnamed();
let ptr = ua.as_ptr() as *const libc::sockaddr;
- let ss = unsafe {
- SockaddrStorage::from_raw(ptr, Some(ua.len()))
- }.unwrap();
+ let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) }
+ .unwrap();
assert_eq!(ss.len(), ua.len());
}
}
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index 8513b6f..78dd617 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -1,23 +1,25 @@
//! Socket interface functions
//!
//! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html)
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg(feature = "uio")]
use crate::sys::time::TimeSpec;
+#[cfg(not(target_os = "redox"))]
#[cfg(feature = "uio")]
use crate::sys::time::TimeVal;
use crate::{errno::Errno, Result};
use cfg_if::cfg_if;
+use libc::{self, c_int, c_void, size_t, socklen_t};
+#[cfg(all(feature = "uio", not(target_os = "redox")))]
use libc::{
- self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR,
- CMSG_LEN, CMSG_NXTHDR,
+ iovec, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, CMSG_SPACE,
};
-use std::convert::{TryFrom, TryInto};
+#[cfg(not(target_os = "redox"))]
use std::io::{IoSlice, IoSliceMut};
#[cfg(feature = "net")]
use std::net;
-use std::os::unix::io::RawFd;
-use std::{mem, ptr, slice};
+use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, RawFd, OwnedFd};
+use std::{mem, ptr};
#[deny(missing_docs)]
mod addr;
@@ -32,32 +34,26 @@ pub mod sockopt;
pub use self::addr::{SockaddrLike, SockaddrStorage};
-#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
-#[allow(deprecated)]
-pub use self::addr::{AddressFamily, SockAddr, UnixAddr};
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
-#[allow(deprecated)]
-pub use self::addr::{AddressFamily, SockAddr, UnixAddr};
-#[allow(deprecated)]
+pub use self::addr::{AddressFamily, UnixAddr};
+#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
+pub use self::addr::{AddressFamily, UnixAddr};
#[cfg(not(any(
target_os = "illumos",
target_os = "solaris",
- target_os = "haiku"
+ target_os = "haiku",
+ target_os = "redox",
)))]
#[cfg(feature = "net")]
-pub use self::addr::{
- InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, LinkAddr, SockaddrIn, SockaddrIn6,
-};
-#[allow(deprecated)]
+pub use self::addr::{LinkAddr, SockaddrIn, SockaddrIn6};
#[cfg(any(
target_os = "illumos",
target_os = "solaris",
- target_os = "haiku"
+ target_os = "haiku",
+ target_os = "redox",
))]
#[cfg(feature = "net")]
-pub use self::addr::{
- InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, SockaddrIn, SockaddrIn6,
-};
+pub use self::addr::{SockaddrIn, SockaddrIn6};
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use crate::sys::socket::addr::alg::AlgAddr;
@@ -66,19 +62,15 @@ pub use crate::sys::socket::addr::netlink::NetlinkAddr;
#[cfg(any(target_os = "ios", target_os = "macos"))]
#[cfg(feature = "ioctl")]
pub use crate::sys::socket::addr::sys_control::SysControlAddr;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
pub use crate::sys::socket::addr::vsock::VsockAddr;
-#[cfg(feature = "uio")]
+#[cfg(all(feature = "uio", not(target_os = "redox")))]
pub use libc::{cmsghdr, msghdr};
pub use libc::{sa_family_t, sockaddr, sockaddr_storage, sockaddr_un};
#[cfg(feature = "net")]
pub use libc::{sockaddr_in, sockaddr_in6};
-// Needed by the cmsg_space macro
-#[doc(hidden)]
-pub use libc::{c_uint, CMSG_SPACE};
-
#[cfg(feature = "net")]
use crate::sys::socket::addr::{ipv4addr_to_libc, ipv6addr_to_libc};
@@ -101,10 +93,11 @@ pub enum SockType {
/// entire packet with each input system call.
SeqPacket = libc::SOCK_SEQPACKET,
/// Provides raw network protocol access.
+ #[cfg(not(target_os = "redox"))]
Raw = libc::SOCK_RAW,
/// Provides a reliable datagram layer that does not
/// guarantee ordering.
- #[cfg(not(any(target_os = "haiku")))]
+ #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
Rdm = libc::SOCK_RDM,
}
// The TryFrom impl could've been derived using libc_enum!. But for
@@ -118,10 +111,11 @@ impl TryFrom<i32> for SockType {
libc::SOCK_STREAM => Ok(Self::Stream),
libc::SOCK_DGRAM => Ok(Self::Datagram),
libc::SOCK_SEQPACKET => Ok(Self::SeqPacket),
+ #[cfg(not(target_os = "redox"))]
libc::SOCK_RAW => Ok(Self::Raw),
- #[cfg(not(any(target_os = "haiku")))]
+ #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
libc::SOCK_RDM => Ok(Self::Rdm),
- _ => Err(Errno::EINVAL)
+ _ => Err(Errno::EINVAL),
}
}
}
@@ -164,6 +158,11 @@ pub enum SockProtocol {
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
NetlinkSockDiag = libc::NETLINK_SOCK_DIAG,
+ /// Netfilter/iptables ULOG.
+ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ NetlinkNFLOG = libc::NETLINK_NFLOG,
/// SELinux event notifications.
/// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -214,6 +213,11 @@ pub enum SockProtocol {
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT,
+ /// Generic netlink family for simplified netlink usage.
+ /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ NetlinkGeneric = libc::NETLINK_GENERIC,
/// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow
/// configuration of the kernel crypto API.
/// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
@@ -226,28 +230,45 @@ pub enum SockProtocol {
// The protocol number is fed into the socket syscall in network byte order.
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
- EthAll = libc::ETH_P_ALL.to_be(),
+ EthAll = (libc::ETH_P_ALL as u16).to_be() as i32,
+ /// The Controller Area Network raw socket protocol
+ /// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan))
+ #[cfg(target_os = "linux")]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ CanRaw = libc::CAN_RAW,
}
-#[cfg(any(target_os = "linux"))]
+impl SockProtocol {
+ /// The Controller Area Network broadcast manager protocol
+ /// ([ref](https://docs.kernel.org/networking/can.html#how-to-use-socketcan))
+ #[cfg(target_os = "linux")]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ #[allow(non_upper_case_globals)]
+ pub const CanBcm: SockProtocol = SockProtocol::NetlinkUserSock; // Matches libc::CAN_BCM
+}
+#[cfg(any(target_os = "android", target_os = "linux"))]
libc_bitflags! {
/// Configuration flags for `SO_TIMESTAMPING` interface
///
/// For use with [`Timestamping`][sockopt::Timestamping].
/// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
- pub struct TimestampingFlag: c_uint {
+ pub struct TimestampingFlag: libc::c_uint {
/// Report any software timestamps when available.
SOF_TIMESTAMPING_SOFTWARE;
/// Report hardware timestamps as generated by SOF_TIMESTAMPING_TX_HARDWARE when available.
SOF_TIMESTAMPING_RAW_HARDWARE;
- /// Collect transmiting timestamps as reported by hardware
+ /// Collect transmitting timestamps as reported by hardware
SOF_TIMESTAMPING_TX_HARDWARE;
- /// Collect transmiting timestamps as reported by software
+ /// Collect transmitting timestamps as reported by software
SOF_TIMESTAMPING_TX_SOFTWARE;
/// Collect receiving timestamps as reported by hardware
SOF_TIMESTAMPING_RX_HARDWARE;
/// Collect receiving timestamps as reported by software
SOF_TIMESTAMPING_RX_SOFTWARE;
+ /// Generate a unique identifier along with each transmitted packet
+ SOF_TIMESTAMPING_OPT_ID;
+ /// Return transmit timestamps alongside an empty packet instead of the original packet
+ SOF_TIMESTAMPING_OPT_TSONLY;
}
}
@@ -292,17 +313,14 @@ libc_bitflags! {
/// Sends or requests out-of-band data on sockets that support this notion
/// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also
/// support out-of-band data.
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
MSG_OOB;
/// Peeks at an incoming message. The data is treated as unread and the next
/// [`recv()`](fn.recv.html)
/// or similar function shall still return this data.
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
MSG_PEEK;
/// Receive operation blocks until the full amount of data can be
/// returned. The function may return smaller amount of data if a signal
/// is caught, an error or disconnect occurs.
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
MSG_WAITALL;
/// Enables nonblocking operation; if the operation would block,
/// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar
@@ -314,10 +332,10 @@ libc_bitflags! {
/// which will affect all threads in
/// the calling process and as well as other processes that hold
/// file descriptors referring to the same open file description.
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
+ #[cfg(not(target_os = "aix"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
MSG_DONTWAIT;
/// Receive flags: Control Data was discarded (buffer too small)
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
MSG_CTRUNC;
/// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram
/// (since Linux 2.4.27/2.6.8),
@@ -327,18 +345,15 @@ libc_bitflags! {
/// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets.
///
/// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp).
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
MSG_TRUNC;
/// Terminates a record (when this notion is supported, as for
/// sockets of type [`SeqPacket`](enum.SockType.html)).
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
MSG_EOR;
/// This flag specifies that queued errors should be received from
/// the socket error queue. (For more details, see
/// [recvfrom(2)](https://linux.die.net/man/2/recvfrom))
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
MSG_ERRQUEUE;
/// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain
/// file descriptor using the `SCM_RIGHTS` operation (described in
@@ -354,7 +369,6 @@ libc_bitflags! {
target_os = "netbsd",
target_os = "openbsd"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
MSG_CMSG_CLOEXEC;
/// Requests not to send `SIGPIPE` errors when the other end breaks the connection.
/// (For more details, see [send(2)](https://linux.die.net/man/2/send)).
@@ -369,8 +383,18 @@ libc_bitflags! {
target_os = "openbsd",
target_os = "solaris"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
- #[allow(deprecated)] // Suppress useless warnings from libc PR 2963
MSG_NOSIGNAL;
+ /// Turns on [`MSG_DONTWAIT`] after the first message has been received (only for
+ /// `recvmmsg()`).
+ #[cfg(any(target_os = "android",
+ target_os = "fuchsia",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "solaris"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ MSG_WAITFORONE;
}
}
@@ -462,7 +486,7 @@ cfg_if! {
/// Returns a list group identifiers (the first one being the effective GID)
pub fn groups(&self) -> &[libc::gid_t] {
unsafe {
- slice::from_raw_parts(
+ std::slice::from_raw_parts(
self.0.cmcred_groups.as_ptr() as *const libc::gid_t,
self.0.cmcred_ngroups as _
)
@@ -555,6 +579,7 @@ impl Ipv6MembershipRequest {
}
}
+#[cfg(not(target_os = "redox"))]
feature! {
#![feature = "uio"]
@@ -584,18 +609,19 @@ feature! {
macro_rules! cmsg_space {
( $( $x:ty ),* ) => {
{
- let mut space = 0;
- $(
- // CMSG_SPACE is always safe
- space += unsafe {
- $crate::sys::socket::CMSG_SPACE(::std::mem::size_of::<$x>() as $crate::sys::socket::c_uint)
- } as usize;
- )*
+ let space = 0 $(+ $crate::sys::socket::cmsg_space::<$x>())*;
Vec::<u8>::with_capacity(space)
}
}
}
+#[inline]
+#[doc(hidden)]
+pub 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 }
+}
+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
/// Contains outcome of sending or receiving a message
///
@@ -688,6 +714,7 @@ pub enum ControlMessageOwned {
/// # use std::io::{IoSlice, IoSliceMut};
/// # use std::time::*;
/// # use std::str::FromStr;
+ /// # use std::os::unix::io::AsRawFd;
/// # fn main() {
/// // Set up
/// let message = "Ohayō!".as_bytes();
@@ -696,22 +723,22 @@ pub enum ControlMessageOwned {
/// SockType::Datagram,
/// SockFlag::empty(),
/// None).unwrap();
- /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
+ /// setsockopt(&in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
/// let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap();
- /// bind(in_socket, &localhost).unwrap();
- /// let address: SockaddrIn = getsockname(in_socket).unwrap();
+ /// bind(in_socket.as_raw_fd(), &localhost).unwrap();
+ /// let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap();
/// // Get initial time
/// let time0 = SystemTime::now();
/// // Send the message
/// let iov = [IoSlice::new(message)];
/// let flags = MsgFlags::empty();
- /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap();
+ /// let l = sendmsg(in_socket.as_raw_fd(), &iov, &[], flags, Some(&address)).unwrap();
/// assert_eq!(message.len(), l);
/// // Receive the message
/// let mut buffer = vec![0u8; message.len()];
/// let mut cmsgspace = cmsg_space!(TimeVal);
/// let mut iov = [IoSliceMut::new(&mut buffer)];
- /// let r = recvmsg::<SockaddrIn>(in_socket, &mut iov, Some(&mut cmsgspace), flags)
+ /// let r = recvmsg::<SockaddrIn>(in_socket.as_raw_fd(), &mut iov, Some(&mut cmsgspace), flags)
/// .unwrap();
/// let rtime = match r.cmsgs().next() {
/// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime,
@@ -727,19 +754,18 @@ pub enum ControlMessageOwned {
/// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
/// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
/// // Close socket
- /// nix::unistd::close(in_socket).unwrap();
/// # }
/// ```
ScmTimestamp(TimeVal),
/// A set of nanosecond resolution timestamps
///
/// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
- #[cfg(all(target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
ScmTimestampsns(Timestamps),
/// Nanoseconds resolution timestamp
///
/// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
- #[cfg(all(target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
ScmTimestampns(TimeSpec),
#[cfg(any(
@@ -836,7 +862,7 @@ pub enum ControlMessageOwned {
}
/// For representing packet timestamps via `SO_TIMESTAMPING` interface
-#[cfg(all(target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux"))]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Timestamps {
/// software based timestamp, usually one containing data
@@ -884,17 +910,17 @@ impl ControlMessageOwned {
let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _);
ControlMessageOwned::ScmCreds(cred.into())
}
- #[cfg(not(target_os = "haiku"))]
+ #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
(libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
let tv: libc::timeval = ptr::read_unaligned(p as *const _);
ControlMessageOwned::ScmTimestamp(TimeVal::from(tv))
},
- #[cfg(all(target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
(libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => {
let ts: libc::timespec = ptr::read_unaligned(p as *const _);
ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts))
}
- #[cfg(all(target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
(libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => {
let tp = p as *const libc::timespec;
let ts: libc::timespec = ptr::read_unaligned(tp);
@@ -990,7 +1016,7 @@ impl ControlMessageOwned {
ControlMessageOwned::Ipv6OrigDstAddr(dl)
},
(_, _) => {
- let sl = slice::from_raw_parts(p, len);
+ let sl = std::slice::from_raw_parts(p, len);
let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl));
ControlMessageOwned::Unknown(ucmsg)
}
@@ -1446,6 +1472,7 @@ impl<'a> ControlMessage<'a> {
/// # use nix::sys::socket::*;
/// # use nix::unistd::pipe;
/// # use std::io::IoSlice;
+/// # use std::os::unix::io::AsRawFd;
/// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None,
/// SockFlag::empty())
/// .unwrap();
@@ -1454,7 +1481,7 @@ impl<'a> ControlMessage<'a> {
/// let iov = [IoSlice::new(b"hello")];
/// let fds = [r];
/// let cmsg = ControlMessage::ScmRights(&fds);
-/// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap();
+/// sendmsg::<()>(fd1.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), None).unwrap();
/// ```
/// When directing to a specific address, the generic type will be inferred.
/// ```
@@ -1462,6 +1489,7 @@ impl<'a> ControlMessage<'a> {
/// # use nix::unistd::pipe;
/// # use std::io::IoSlice;
/// # use std::str::FromStr;
+/// # use std::os::unix::io::AsRawFd;
/// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap();
/// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(),
/// None).unwrap();
@@ -1470,7 +1498,7 @@ impl<'a> ControlMessage<'a> {
/// let iov = [IoSlice::new(b"hello")];
/// let fds = [r];
/// let cmsg = ControlMessage::ScmRights(&fds);
-/// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap();
+/// sendmsg(fd.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap();
/// ```
pub fn sendmsg<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage],
flags: MsgFlags, addr: Option<&S>) -> Result<usize>
@@ -1535,7 +1563,7 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>(
for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() {
- let mut p = &mut mmsghdr.msg_hdr;
+ let p = &mut mmsghdr.msg_hdr;
p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec;
p.msg_iovlen = slice.as_ref().len() as _;
@@ -1590,8 +1618,7 @@ pub struct MultiHeaders<S> {
addresses: Box<[mem::MaybeUninit<S>]>,
// while we are not using it directly - this is used to store control messages
// and we retain pointers to them inside items array
- #[allow(dead_code)]
- cmsg_buffers: Option<Box<[u8]>>,
+ _cmsg_buffers: Option<Box<[u8]>>,
msg_controllen: usize,
}
@@ -1611,24 +1638,24 @@ impl<S> MultiHeaders<S> {
{
// we will be storing pointers to addresses inside mhdr - convert it into boxed
// slice so it can'be changed later by pushing anything into self.addresses
- let mut addresses = vec![std::mem::MaybeUninit::uninit(); num_slices].into_boxed_slice();
+ let mut addresses = vec![std::mem::MaybeUninit::<S>::uninit(); num_slices].into_boxed_slice();
let msg_controllen = cmsg_buffer.as_ref().map_or(0, |v| v.capacity());
// we'll need a cmsg_buffer for each slice, we preallocate a vector and split
// it into "slices" parts
- let cmsg_buffers =
+ let mut cmsg_buffers =
cmsg_buffer.map(|v| vec![0u8; v.capacity() * num_slices].into_boxed_slice());
let items = addresses
.iter_mut()
.enumerate()
.map(|(ix, address)| {
- let (ptr, cap) = match &cmsg_buffers {
- Some(v) => ((&v[ix * msg_controllen] as *const u8), msg_controllen),
- None => (std::ptr::null(), 0),
+ let (ptr, cap) = match &mut cmsg_buffers {
+ Some(v) => ((&mut v[ix * msg_controllen] as *mut u8), msg_controllen),
+ None => (std::ptr::null_mut(), 0),
};
- let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.as_mut_ptr()) };
+ let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null_mut(), 0, ptr, cap, address.as_mut_ptr()) };
libc::mmsghdr {
msg_hdr,
msg_len: 0,
@@ -1639,7 +1666,7 @@ impl<S> MultiHeaders<S> {
Self {
items: items.into_boxed_slice(),
addresses,
- cmsg_buffers,
+ _cmsg_buffers: cmsg_buffers,
msg_controllen,
}
}
@@ -1689,7 +1716,7 @@ where
{
let mut count = 0;
for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() {
- let mut p = &mut mmsghdr.msg_hdr;
+ let p = &mut mmsghdr.msg_hdr;
p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec;
p.msg_iovlen = slice.as_ref().len() as _;
count = i + 1;
@@ -1819,6 +1846,7 @@ mod test {
use crate::sys::socket::{AddressFamily, ControlMessageOwned};
use crate::*;
use std::str::FromStr;
+ use std::os::unix::io::AsRawFd;
#[cfg_attr(qemu, ignore)]
#[test]
@@ -1845,9 +1873,9 @@ mod test {
None,
)?;
- crate::sys::socket::bind(rsock, &sock_addr)?;
+ crate::sys::socket::bind(rsock.as_raw_fd(), &sock_addr)?;
- setsockopt(rsock, Timestamping, &TimestampingFlag::all())?;
+ setsockopt(&rsock, Timestamping, &TimestampingFlag::all())?;
let sbuf = (0..400).map(|i| i as u8).collect::<Vec<_>>();
@@ -1869,13 +1897,13 @@ mod test {
let iov1 = [IoSlice::new(&sbuf)];
let cmsg = cmsg_space!(crate::sys::socket::Timestamps);
- sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap();
+ sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
let mut data = super::MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg));
let t = sys::time::TimeSpec::from_duration(std::time::Duration::from_secs(10));
- let recv = super::recvmmsg(rsock, &mut data, recv_iovs.iter(), flags, Some(t))?;
+ let recv = super::recvmmsg(rsock.as_raw_fd(), &mut data, recv_iovs.iter(), flags, Some(t))?;
for rmsg in recv {
#[cfg(not(any(qemu, target_arch = "aarch64")))]
@@ -1916,7 +1944,7 @@ unsafe fn read_mhdr<'a, 'i, S>(
mhdr: msghdr,
r: isize,
msg_controllen: usize,
- address: S,
+ mut address: S,
) -> RecvMsg<'a, 'i, S>
where S: SockaddrLike
{
@@ -1932,6 +1960,11 @@ unsafe fn read_mhdr<'a, 'i, S>(
}.as_ref()
};
+ // Ignore errors if this socket address has statically-known length
+ //
+ // This is to ensure that unix socket addresses have their length set appropriately.
+ let _ = address.set_length(mhdr.msg_namelen as usize);
+
RecvMsg {
bytes: r as usize,
cmsghdr,
@@ -1954,9 +1987,9 @@ unsafe fn read_mhdr<'a, 'i, S>(
///
/// Buffers must remain valid for the whole lifetime of msghdr
unsafe fn pack_mhdr_to_receive<S>(
- iov_buffer: *const IoSliceMut,
+ iov_buffer: *mut IoSliceMut,
iov_buffer_len: usize,
- cmsg_buffer: *const u8,
+ cmsg_buffer: *mut u8,
cmsg_capacity: usize,
address: *mut S,
) -> msghdr
@@ -1967,7 +2000,7 @@ 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_ptr() as *mut c_void;
+ (*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 _;
@@ -1992,7 +2025,7 @@ fn pack_mhdr_to_send<'a, I, C, S>(
// The message header must be initialized before the individual cmsgs.
let cmsg_ptr = if capacity > 0 {
- cmsg_buffer.as_ptr() as *mut c_void
+ cmsg_buffer.as_mut_ptr() as *mut c_void
} else {
ptr::null_mut()
};
@@ -2046,7 +2079,7 @@ fn pack_mhdr_to_send<'a, I, C, S>(
/// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html)
pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>],
mut cmsg_buffer: Option<&'a mut Vec<u8>>,
- flags: MsgFlags) -> Result<RecvMsg<'a, 'inner, S>>
+ flags: MsgFlags) -> Result<RecvMsg<'a, 'outer, S>>
where S: SockaddrLike + 'a,
'inner: 'outer
{
@@ -2056,7 +2089,7 @@ pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'i
.map(|v| (v.as_mut_ptr(), v.capacity()))
.unwrap_or((ptr::null_mut(), 0));
let mut mhdr = unsafe {
- pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr())
+ pack_mhdr_to_receive(iov.as_mut().as_mut_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr())
};
let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
@@ -2082,7 +2115,7 @@ pub fn socket<T: Into<Option<SockProtocol>>>(
ty: SockType,
flags: SockFlag,
protocol: T,
-) -> Result<RawFd> {
+) -> Result<OwnedFd> {
let protocol = match protocol.into() {
None => 0,
Some(p) => p as c_int,
@@ -2096,7 +2129,13 @@ pub fn socket<T: Into<Option<SockProtocol>>>(
let res = unsafe { libc::socket(domain as c_int, ty, protocol) };
- Errno::result(res)
+ match res {
+ -1 => Err(Errno::last()),
+ fd => {
+ // Safe because libc::socket returned success
+ unsafe { Ok(OwnedFd::from_raw_fd(fd)) }
+ }
+ }
}
/// Create a pair of connected sockets
@@ -2107,7 +2146,7 @@ pub fn socketpair<T: Into<Option<SockProtocol>>>(
ty: SockType,
protocol: T,
flags: SockFlag,
-) -> Result<(RawFd, RawFd)> {
+) -> Result<(OwnedFd, OwnedFd)> {
let protocol = match protocol.into() {
None => 0,
Some(p) => p as c_int,
@@ -2126,14 +2165,18 @@ pub fn socketpair<T: Into<Option<SockProtocol>>>(
};
Errno::result(res)?;
- Ok((fds[0], fds[1]))
+ // Safe because socketpair returned success.
+ unsafe {
+ Ok((OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1])))
+ }
}
/// Listen for connections on a socket
///
/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html)
-pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> {
- let res = unsafe { libc::listen(sockfd, backlog as c_int) };
+pub fn listen<F: AsFd>(sock: &F, backlog: usize) -> Result<()> {
+ let fd = sock.as_fd().as_raw_fd();
+ let res = unsafe { libc::listen(fd, backlog as c_int) };
Errno::result(res).map(drop)
}
@@ -2202,7 +2245,7 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
unsafe {
let ret = libc::recv(
sockfd,
- buf.as_ptr() as *mut c_void,
+ buf.as_mut_ptr() as *mut c_void,
buf.len() as size_t,
flags.bits(),
);
@@ -2226,17 +2269,17 @@ pub fn recvfrom<T: SockaddrLike>(
let ret = Errno::result(libc::recvfrom(
sockfd,
- buf.as_ptr() as *mut c_void,
+ buf.as_mut_ptr() as *mut c_void,
buf.len() as size_t,
0,
- addr.as_mut_ptr() as *mut libc::sockaddr,
+ addr.as_mut_ptr() as *mut sockaddr,
&mut len as *mut socklen_t,
))? as usize;
Ok((
ret,
T::from_raw(
- addr.assume_init().as_ptr() as *const libc::sockaddr,
+ addr.assume_init().as_ptr(),
Some(len),
),
))
@@ -2293,7 +2336,7 @@ pub trait GetSockOpt: Copy {
type Val;
/// Look up the value of this socket option on the given socket.
- fn get(&self, fd: RawFd) -> Result<Self::Val>;
+ fn get<F: AsFd>(&self, fd: &F) -> Result<Self::Val>;
}
/// Represents a socket option that can be set.
@@ -2301,13 +2344,13 @@ pub trait SetSockOpt: Clone {
type Val;
/// Set the value of this socket option on the given socket.
- fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>;
+ fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()>;
}
/// Get the current value for the requested socket option
///
/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html)
-pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
+pub fn getsockopt<F: AsFd, O: GetSockOpt>(fd: &F, opt: O) -> Result<O::Val> {
opt.get(fd)
}
@@ -2321,15 +2364,14 @@ pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
/// use nix::sys::socket::setsockopt;
/// use nix::sys::socket::sockopt::KeepAlive;
/// use std::net::TcpListener;
-/// use std::os::unix::io::AsRawFd;
///
/// let listener = TcpListener::bind("0.0.0.0:0").unwrap();
-/// let fd = listener.as_raw_fd();
-/// let res = setsockopt(fd, KeepAlive, &true);
+/// let fd = listener;
+/// let res = setsockopt(&fd, KeepAlive, &true);
/// assert!(res.is_ok());
/// ```
-pub fn setsockopt<O: SetSockOpt>(
- fd: RawFd,
+pub fn setsockopt<F: AsFd, O: SetSockOpt>(
+ fd: &F,
opt: O,
val: &O::Val,
) -> Result<()> {
@@ -2344,11 +2386,8 @@ 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 libc::sockaddr,
- &mut len,
- );
+ let ret =
+ libc::getpeername(fd, addr.as_mut_ptr() as *mut sockaddr, &mut len);
Errno::result(ret)?;
@@ -2364,11 +2403,8 @@ 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 libc::sockaddr,
- &mut len,
- );
+ let ret =
+ libc::getsockname(fd, addr.as_mut_ptr() as *mut sockaddr, &mut len);
Errno::result(ret)?;
@@ -2376,81 +2412,6 @@ pub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> {
}
}
-/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a
-/// certain size.
-///
-/// In C this would usually be done by casting. The `len` argument
-/// should be the number of bytes in the `sockaddr_storage` that are actually
-/// allocated and valid. It must be at least as large as all the useful parts
-/// of the structure. Note that in the case of a `sockaddr_un`, `len` need not
-/// include the terminating null.
-#[deprecated(
- since = "0.24.0",
- note = "use SockaddrLike or SockaddrStorage instead"
-)]
-#[allow(deprecated)]
-pub fn sockaddr_storage_to_addr(
- addr: &sockaddr_storage,
- len: usize,
-) -> Result<SockAddr> {
- assert!(len <= mem::size_of::<sockaddr_storage>());
- if len < mem::size_of_val(&addr.ss_family) {
- return Err(Errno::ENOTCONN);
- }
-
- match c_int::from(addr.ss_family) {
- #[cfg(feature = "net")]
- libc::AF_INET => {
- assert!(len >= mem::size_of::<sockaddr_in>());
- let sin = unsafe {
- *(addr as *const sockaddr_storage as *const sockaddr_in)
- };
- Ok(SockAddr::Inet(InetAddr::V4(sin)))
- }
- #[cfg(feature = "net")]
- libc::AF_INET6 => {
- assert!(len >= mem::size_of::<sockaddr_in6>());
- let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) };
- Ok(SockAddr::Inet(InetAddr::V6(sin6)))
- }
- libc::AF_UNIX => unsafe {
- let sun = *(addr as *const _ as *const sockaddr_un);
- let sun_len = len.try_into().unwrap();
- Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len)))
- },
- #[cfg(any(target_os = "android", target_os = "linux"))]
- #[cfg(feature = "net")]
- libc::AF_PACKET => {
- use libc::sockaddr_ll;
- // Don't assert anything about the size.
- // Apparently the Linux kernel can return smaller sizes when
- // the value in the last element of sockaddr_ll (`sll_addr`) is
- // smaller than the declared size of that field
- let sll = unsafe { *(addr as *const _ as *const sockaddr_ll) };
- Ok(SockAddr::Link(LinkAddr(sll)))
- }
- #[cfg(any(target_os = "android", target_os = "linux"))]
- libc::AF_NETLINK => {
- use libc::sockaddr_nl;
- let snl = unsafe { *(addr as *const _ as *const sockaddr_nl) };
- Ok(SockAddr::Netlink(NetlinkAddr(snl)))
- }
- #[cfg(any(target_os = "android", target_os = "linux"))]
- libc::AF_ALG => {
- use libc::sockaddr_alg;
- let salg = unsafe { *(addr as *const _ as *const sockaddr_alg) };
- Ok(SockAddr::Alg(AlgAddr(salg)))
- }
- #[cfg(any(target_os = "android", target_os = "linux"))]
- libc::AF_VSOCK => {
- use libc::sockaddr_vm;
- let svm = unsafe { *(addr as *const _ as *const sockaddr_vm) };
- Ok(SockAddr::Vsock(VsockAddr(svm)))
- }
- af => panic!("unexpected address family {}", af),
- }
-}
-
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Shutdown {
/// Further receptions will be disallowed.
@@ -2480,8 +2441,25 @@ 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 06e9ee4..44f3ebb 100644
--- a/src/sys/socket/sockopt.rs
+++ b/src/sys/socket/sockopt.rs
@@ -6,13 +6,10 @@ use crate::Result;
use cfg_if::cfg_if;
use libc::{self, c_int, c_void, socklen_t};
use std::ffi::{OsStr, OsString};
-use std::{
- convert::TryFrom,
- mem::{self, MaybeUninit}
-};
+use std::mem::{self, MaybeUninit};
#[cfg(target_family = "unix")]
use std::os::unix::ffi::OsStrExt;
-use std::os::unix::io::RawFd;
+use std::os::unix::io::{AsFd, AsRawFd};
// Constants
// TCP_CA_NAME_MAX isn't defined in user space include files
@@ -47,12 +44,12 @@ macro_rules! setsockopt_impl {
impl SetSockOpt for $name {
type Val = $ty;
- fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
+ fn set<F: AsFd>(&self, fd: &F, val: &$ty) -> Result<()> {
unsafe {
let setter: $setter = Set::new(val);
let res = libc::setsockopt(
- fd,
+ fd.as_fd().as_raw_fd(),
$level,
$flag,
setter.ffi_ptr(),
@@ -92,12 +89,12 @@ macro_rules! getsockopt_impl {
impl GetSockOpt for $name {
type Val = $ty;
- fn get(&self, fd: RawFd) -> Result<$ty> {
+ fn get<F: AsFd>(&self, fd: &F) -> Result<$ty> {
unsafe {
let mut getter: $getter = Get::uninit();
let res = libc::getsockopt(
- fd,
+ fd.as_fd().as_raw_fd(),
$level,
$flag,
getter.ffi_ptr(),
@@ -107,7 +104,7 @@ macro_rules! getsockopt_impl {
match <$ty>::try_from(getter.assume_init()) {
Err(_) => Err(Errno::EINVAL),
- Ok(r) => Ok(r)
+ Ok(r) => Ok(r),
}
}
}
@@ -141,7 +138,6 @@ macro_rules! getsockopt_impl {
/// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`.
/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
// Some targets don't use all rules.
-#[allow(unknown_lints)]
#[allow(unused_macro_rules)]
macro_rules! sockopt_impl {
($(#[$attr:meta])* $name:ident, GetOnly, $level:expr, $flag:path, bool) => {
@@ -496,6 +492,15 @@ sockopt_impl!(
libc::LOCAL_PEERCRED,
super::XuCred
);
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+sockopt_impl!(
+ /// Get the PID of the peer process of a connected unix domain socket.
+ LocalPeerPid,
+ GetOnly,
+ 0,
+ libc::LOCAL_PEERPID,
+ libc::c_int
+);
#[cfg(any(target_os = "android", target_os = "linux"))]
sockopt_impl!(
/// Return the credentials of the foreign process connected to this socket.
@@ -539,13 +544,13 @@ cfg_if! {
sockopt_impl!(
/// The maximum segment size for outgoing TCP packets.
TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
- } else {
+ } else if #[cfg(not(target_os = "redox"))] {
sockopt_impl!(
/// The maximum segment size for outgoing TCP packets.
TcpMaxSeg, GetOnly, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
}
}
-#[cfg(not(any(target_os = "openbsd", target_os = "haiku")))]
+#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "redox")))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -567,7 +572,7 @@ sockopt_impl!(
libc::TCP_REPAIR,
u32
);
-#[cfg(not(any(target_os = "openbsd", target_os = "haiku")))]
+#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "redox")))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
@@ -678,7 +683,7 @@ sockopt_impl!(
libc::IP6T_SO_ORIGINAL_DST,
libc::sockaddr_in6
);
-#[cfg(any(target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux"))]
sockopt_impl!(
/// Specifies exact type of timestamping information collected by the kernel
/// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
@@ -688,7 +693,7 @@ sockopt_impl!(
libc::SO_TIMESTAMPING,
super::TimestampingFlag
);
-#[cfg(not(target_os = "haiku"))]
+#[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "redox")))]
sockopt_impl!(
/// Enable or disable the receiving of the `SO_TIMESTAMP` control message.
ReceiveTimestamp,
@@ -697,7 +702,7 @@ sockopt_impl!(
libc::SO_TIMESTAMP,
bool
);
-#[cfg(all(target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux"))]
sockopt_impl!(
/// Enable or disable the receiving of the `SO_TIMESTAMPNS` control message.
ReceiveTimestampns,
@@ -706,6 +711,16 @@ sockopt_impl!(
libc::SO_TIMESTAMPNS,
bool
);
+#[cfg(target_os = "freebsd")]
+sockopt_impl!(
+ /// Sets a specific timestamp format instead of the classic `SCM_TIMESTAMP`,
+ /// to follow up after `SO_TIMESTAMP` is set.
+ TsClock,
+ Both,
+ libc::SOL_SOCKET,
+ libc::SO_TS_CLOCK,
+ i32
+);
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg(feature = "net")]
sockopt_impl!(
@@ -741,6 +756,46 @@ sockopt_impl!(
libc::IP_BINDANY,
bool
);
+#[cfg(target_os = "freebsd")]
+sockopt_impl!(
+ /// Set the route table (FIB) for this socket up to the `net.fibs` OID limit
+ /// (more specific than the setfib command line/call which are process based).
+ Fib,
+ SetOnly,
+ libc::SOL_SOCKET,
+ libc::SO_SETFIB,
+ i32
+);
+#[cfg(target_os = "freebsd")]
+sockopt_impl!(
+ /// Set `so_user_cookie` for this socket allowing network traffic based
+ /// upon it, similar to Linux's netfilter MARK.
+ UserCookie,
+ SetOnly,
+ libc::SOL_SOCKET,
+ libc::SO_USER_COOKIE,
+ u32
+);
+#[cfg(target_os = "openbsd")]
+sockopt_impl!(
+ /// Set the route table for this socket, needs a privileged user if
+ /// the process/socket had been set to the non default route.
+ Rtable,
+ SetOnly,
+ libc::SOL_SOCKET,
+ libc::SO_RTABLE,
+ i32
+);
+#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
+sockopt_impl!(
+ /// Get/set a filter on this socket before accepting connections similarly
+ /// to Linux's TCP_DEFER_ACCEPT but after the listen's call.
+ AcceptFilter,
+ Both,
+ libc::SOL_SOCKET,
+ libc::SO_ACCEPTFILTER,
+ libc::accept_filter_arg
+);
#[cfg(target_os = "linux")]
sockopt_impl!(
/// Set the mark for each packet sent through this socket (similar to the
@@ -1008,10 +1063,10 @@ pub struct AlgSetAeadAuthSize;
impl SetSockOpt for AlgSetAeadAuthSize {
type Val = usize;
- fn set(&self, fd: RawFd, val: &usize) -> Result<()> {
+ fn set<F: AsFd>(&self, fd: &F, val: &usize) -> Result<()> {
unsafe {
let res = libc::setsockopt(
- fd,
+ fd.as_fd().as_raw_fd(),
libc::SOL_ALG,
libc::ALG_SET_AEAD_AUTHSIZE,
::std::ptr::null(),
@@ -1042,10 +1097,10 @@ where
{
type Val = T;
- fn set(&self, fd: RawFd, val: &T) -> Result<()> {
+ fn set<F: AsFd>(&self, fd: &F, val: &T) -> Result<()> {
unsafe {
let res = libc::setsockopt(
- fd,
+ fd.as_fd().as_raw_fd(),
libc::SOL_ALG,
libc::ALG_SET_KEY,
val.as_ref().as_ptr() as *const _,
@@ -1358,8 +1413,8 @@ mod test {
SockFlag::empty(),
)
.unwrap();
- let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
- let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
+ let a_cred = getsockopt(&a, super::PeerCredentials).unwrap();
+ let b_cred = getsockopt(&b, super::PeerCredentials).unwrap();
assert_eq!(a_cred, b_cred);
assert_ne!(a_cred.pid(), 0);
}
@@ -1367,25 +1422,21 @@ mod test {
#[test]
fn is_socket_type_unix() {
use super::super::*;
- use crate::unistd::close;
- let (a, b) = socketpair(
+ let (a, _b) = socketpair(
AddressFamily::Unix,
SockType::Stream,
None,
SockFlag::empty(),
)
.unwrap();
- let a_type = getsockopt(a, super::SockType).unwrap();
+ let a_type = getsockopt(&a, super::SockType).unwrap();
assert_eq!(a_type, SockType::Stream);
- close(a).unwrap();
- close(b).unwrap();
}
#[test]
fn is_socket_type_dgram() {
use super::super::*;
- use crate::unistd::close;
let s = socket(
AddressFamily::Inet,
@@ -1394,16 +1445,14 @@ mod test {
None,
)
.unwrap();
- let s_type = getsockopt(s, super::SockType).unwrap();
+ let s_type = getsockopt(&s, super::SockType).unwrap();
assert_eq!(s_type, SockType::Datagram);
- close(s).unwrap();
}
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
#[test]
fn can_get_listen_on_tcp_socket() {
use super::super::*;
- use crate::unistd::close;
let s = socket(
AddressFamily::Inet,
@@ -1412,11 +1461,10 @@ mod test {
None,
)
.unwrap();
- let s_listening = getsockopt(s, super::AcceptConn).unwrap();
+ let s_listening = getsockopt(&s, super::AcceptConn).unwrap();
assert!(!s_listening);
- listen(s, 10).unwrap();
- let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
+ listen(&s, 10).unwrap();
+ let s_listening2 = getsockopt(&s, super::AcceptConn).unwrap();
assert!(s_listening2);
- close(s).unwrap();
}
}
diff --git a/src/sys/stat.rs b/src/sys/stat.rs
index 78203bf..7e51c03 100644
--- a/src/sys/stat.rs
+++ b/src/sys/stat.rs
@@ -177,7 +177,7 @@ pub fn mknod<P: ?Sized + NixPath>(
dev: dev_t,
) -> Result<()> {
let res = path.with_nix_path(|cstr| unsafe {
- libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
+ libc::mknod(cstr.as_ptr(), kind.bits() | perm.bits() as mode_t, dev)
})?;
Errno::result(res).map(drop)
@@ -202,7 +202,7 @@ pub fn mknodat<P: ?Sized + NixPath>(
libc::mknodat(
dirfd,
cstr.as_ptr(),
- kind.bits | perm.bits() as mode_t,
+ kind.bits() | perm.bits() as mode_t,
dev,
)
})?;
diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs
index 9be8ca6..5111df2 100644
--- a/src/sys/statfs.rs
+++ b/src/sys/statfs.rs
@@ -5,7 +5,7 @@
use std::ffi::CStr;
use std::fmt::{self, Debug};
use std::mem;
-use std::os::unix::io::AsRawFd;
+use std::os::unix::io::{AsFd, AsRawFd};
use cfg_if::cfg_if;
@@ -740,10 +740,10 @@ pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> {
/// # Arguments
///
/// `fd` - File descriptor of any open file within the file system to describe
-pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> {
+pub fn fstatfs<Fd: AsFd>(fd: Fd) -> Result<Statfs> {
unsafe {
let mut stat = mem::MaybeUninit::<type_of_statfs>::uninit();
- Errno::result(LIBC_FSTATFS(fd.as_raw_fd(), stat.as_mut_ptr()))
+ Errno::result(LIBC_FSTATFS(fd.as_fd().as_raw_fd(), stat.as_mut_ptr()))
.map(|_| Statfs(stat.assume_init()))
}
}
diff --git a/src/sys/statvfs.rs b/src/sys/statvfs.rs
index 8de369f..35424e5 100644
--- a/src/sys/statvfs.rs
+++ b/src/sys/statvfs.rs
@@ -3,7 +3,7 @@
//! See [the man pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html)
//! for more details.
use std::mem;
-use std::os::unix::io::AsRawFd;
+use std::os::unix::io::{AsFd, AsRawFd};
use libc::{self, c_ulong};
@@ -12,7 +12,6 @@ use crate::{errno::Errno, NixPath, Result};
#[cfg(not(target_os = "redox"))]
libc_bitflags!(
/// File system mount Flags
- #[repr(C)]
#[derive(Default)]
pub struct FsFlags: c_ulong {
/// Read Only
@@ -146,11 +145,11 @@ pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> {
}
/// Return a `Statvfs` object with information about `fd`
-pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> {
+pub fn fstatvfs<Fd: AsFd>(fd: Fd) -> Result<Statvfs> {
unsafe {
Errno::clear();
let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit();
- Errno::result(libc::fstatvfs(fd.as_raw_fd(), stat.as_mut_ptr()))
+ Errno::result(libc::fstatvfs(fd.as_fd().as_raw_fd(), stat.as_mut_ptr()))
.map(|_| Statvfs(stat.assume_init()))
}
}
diff --git a/src/sys/termios.rs b/src/sys/termios.rs
index fba2cd8..74c5fc5 100644
--- a/src/sys/termios.rs
+++ b/src/sys/termios.rs
@@ -222,7 +222,7 @@ use libc::{self, c_int, tcflag_t};
use std::cell::{Ref, RefCell};
use std::convert::From;
use std::mem;
-use std::os::unix::io::RawFd;
+use std::os::unix::io::{AsFd, AsRawFd};
#[cfg(feature = "process")]
use crate::unistd::Pid;
@@ -307,10 +307,10 @@ 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_truncate(termios.c_iflag);
- self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag);
- self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag);
- self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag);
+ self.input_flags = InputFlags::from_bits_retain(termios.c_iflag);
+ self.output_flags = OutputFlags::from_bits_retain(termios.c_oflag);
+ self.control_flags = ControlFlags::from_bits_retain(termios.c_cflag);
+ self.local_flags = LocalFlags::from_bits_retain(termios.c_lflag);
self.control_chars = termios.c_cc;
#[cfg(any(
target_os = "linux",
@@ -327,10 +327,10 @@ impl From<libc::termios> for Termios {
fn from(termios: libc::termios) -> Self {
Termios {
inner: RefCell::new(termios),
- 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),
+ 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),
control_chars: termios.c_cc,
#[cfg(any(
target_os = "linux",
@@ -355,9 +355,9 @@ libc_enum! {
/// enum.
///
/// B0 is special and will disable the port.
- #[cfg_attr(all(any(target_os = "haiku"), target_pointer_width = "64"), repr(u8))]
+ #[cfg_attr(target_os = "haiku", repr(u8))]
#[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))]
- #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos", target_os = "haiku"), target_pointer_width = "64")), repr(u32))]
+ #[cfg_attr(all(not(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64")), not(target_os = "haiku")), repr(u32))]
#[non_exhaustive]
pub enum BaudRate {
B0,
@@ -397,6 +397,8 @@ libc_enum! {
#[cfg_attr(docsrs, doc(cfg(all())))]
B28800,
B38400,
+ #[cfg(not(target_os = "aix"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
B57600,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
@@ -405,10 +407,14 @@ libc_enum! {
target_os = "openbsd"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
B76800,
+ #[cfg(not(target_os = "aix"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
B115200,
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
B153600,
+ #[cfg(not(target_os = "aix"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
B230400,
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
@@ -542,6 +548,8 @@ libc_enum! {
#[repr(usize)]
#[non_exhaustive]
pub enum SpecialCharacterIndices {
+ #[cfg(not(target_os = "aix"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
VDISCARD,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
@@ -549,6 +557,7 @@ libc_enum! {
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
+ target_os = "aix",
target_os = "solaris"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
VDSUSP,
@@ -566,7 +575,7 @@ libc_enum! {
VKILL,
VLNEXT,
#[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"),
- target_os = "illumos", target_os = "solaris")))]
+ target_os = "illumos", target_os = "solaris", target_os = "aix")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
VMIN,
VQUIT,
@@ -590,9 +599,11 @@ libc_enum! {
#[cfg_attr(docsrs, doc(cfg(all())))]
VSWTCH,
#[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"),
- target_os = "illumos", target_os = "solaris")))]
+ target_os = "illumos", target_os = "solaris", target_os = "aix")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
VTIME,
+ #[cfg(not(target_os = "aix"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
VWERASE,
#[cfg(target_os = "dragonfly")]
#[cfg_attr(docsrs, doc(cfg(all())))]
@@ -603,7 +614,8 @@ libc_enum! {
#[cfg(any(
all(target_os = "linux", target_arch = "sparc64"),
target_os = "illumos",
- target_os = "solaris"
+ target_os = "solaris",
+ target_os = "aix",
))]
impl SpecialCharacterIndices {
pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF;
@@ -616,6 +628,7 @@ pub use libc::NCCS;
target_os = "dragonfly",
target_os = "freebsd",
target_os = "linux",
+ target_os = "aix",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
@@ -881,7 +894,7 @@ libc_bitflags! {
PARODD;
HUPCL;
CLOCAL;
- #[cfg(not(target_os = "redox"))]
+ #[cfg(not(any(target_os = "redox", target_os = "aix")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
CRTSCTS;
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -967,7 +980,7 @@ libc_bitflags! {
#[cfg_attr(docsrs, doc(cfg(all())))]
ALTWERASE;
IEXTEN;
- #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
+ #[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "aix")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
EXTPROC;
TOSTOP;
@@ -1143,10 +1156,12 @@ pub fn cfmakesane(termios: &mut Termios) {
/// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying
/// this structure *will not* reconfigure the port, instead the modifications should be done to
/// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`.
-pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
+pub fn tcgetattr<Fd: AsFd>(fd: Fd) -> Result<Termios> {
let mut termios = mem::MaybeUninit::uninit();
- let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) };
+ let res = unsafe {
+ libc::tcgetattr(fd.as_fd().as_raw_fd(), termios.as_mut_ptr())
+ };
Errno::result(res)?;
@@ -1159,18 +1174,26 @@ pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
/// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change
/// takes affect at a time specified by `actions`. Note that this function may return success if
/// *any* of the parameters were successfully set, not only if all were set successfully.
-pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> {
+pub fn tcsetattr<Fd: AsFd>(
+ fd: Fd,
+ actions: SetArg,
+ termios: &Termios,
+) -> Result<()> {
let inner_termios = termios.get_libc_termios();
Errno::result(unsafe {
- libc::tcsetattr(fd, actions as c_int, &*inner_termios)
+ libc::tcsetattr(
+ fd.as_fd().as_raw_fd(),
+ actions as c_int,
+ &*inner_termios,
+ )
})
.map(drop)
}
/// Block until all output data is written (see
/// [tcdrain(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)).
-pub fn tcdrain(fd: RawFd) -> Result<()> {
- Errno::result(unsafe { libc::tcdrain(fd) }).map(drop)
+pub fn tcdrain<Fd: AsFd>(fd: Fd) -> Result<()> {
+ Errno::result(unsafe { libc::tcdrain(fd.as_fd().as_raw_fd()) }).map(drop)
}
/// Suspend or resume the transmission or reception of data (see
@@ -1178,8 +1201,11 @@ pub fn tcdrain(fd: RawFd) -> Result<()> {
///
/// `tcflow()` suspends of resumes the transmission or reception of data for the given port
/// depending on the value of `action`.
-pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> {
- Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop)
+pub fn tcflow<Fd: AsFd>(fd: Fd, action: FlowArg) -> Result<()> {
+ Errno::result(unsafe {
+ libc::tcflow(fd.as_fd().as_raw_fd(), action as c_int)
+ })
+ .map(drop)
}
/// Discard data in the output or input queue (see
@@ -1187,8 +1213,11 @@ pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> {
///
/// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both
/// depending on the value of `action`.
-pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> {
- Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop)
+pub fn tcflush<Fd: AsFd>(fd: Fd, action: FlushArg) -> Result<()> {
+ Errno::result(unsafe {
+ libc::tcflush(fd.as_fd().as_raw_fd(), action as c_int)
+ })
+ .map(drop)
}
/// Send a break for a specific duration (see
@@ -1196,16 +1225,19 @@ pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> {
///
/// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream
/// of zero-valued bits for an implementation-defined duration.
-pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> {
- Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop)
+pub fn tcsendbreak<Fd: AsFd>(fd: Fd, duration: c_int) -> Result<()> {
+ Errno::result(unsafe {
+ libc::tcsendbreak(fd.as_fd().as_raw_fd(), duration)
+ })
+ .map(drop)
}
feature! {
#![feature = "process"]
/// Get the session controlled by the given terminal (see
/// [tcgetsid(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)).
-pub fn tcgetsid(fd: RawFd) -> Result<Pid> {
- let res = unsafe { libc::tcgetsid(fd) };
+pub fn tcgetsid<Fd: AsFd>(fd: Fd) -> Result<Pid> {
+ let res = unsafe { libc::tcgetsid(fd.as_fd().as_raw_fd()) };
Errno::result(res).map(Pid::from_raw)
}
diff --git a/src/sys/time.rs b/src/sys/time.rs
index 0042c45..a0160e2 100644
--- a/src/sys/time.rs
+++ b/src/sys/time.rs
@@ -91,8 +91,10 @@ pub(crate) mod timer {
#[cfg(any(target_os = "android", target_os = "linux"))]
bitflags! {
/// Flags that are used for arming the timer.
+ #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct TimerSetTimeFlags: libc::c_int {
const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME;
+ const TFD_TIMER_CANCEL_ON_SET = libc::TFD_TIMER_CANCEL_ON_SET;
}
}
#[cfg(any(
@@ -103,6 +105,7 @@ pub(crate) mod timer {
))]
bitflags! {
/// Flags that are used for arming the timer.
+ #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct TimerSetTimeFlags: libc::c_int {
const TFD_TIMER_ABSTIME = libc::TIMER_ABSTIME;
}
@@ -261,8 +264,7 @@ impl TimeValLike for TimeSpec {
fn seconds(seconds: i64) -> TimeSpec {
assert!(
(TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds),
- "TimeSpec out of bounds; seconds={}",
- seconds
+ "TimeSpec out of bounds; seconds={seconds}",
);
let mut ts = zero_init_timespec();
ts.tv_sec = seconds as time_t;
@@ -428,20 +430,20 @@ impl fmt::Display for TimeSpec {
let sec = abs.tv_sec();
- write!(f, "{}", sign)?;
+ write!(f, "{sign}")?;
if abs.tv_nsec() == 0 {
- if abs.tv_sec() == 1 {
- write!(f, "{} second", sec)?;
+ if sec == 1 {
+ write!(f, "1 second")?;
} else {
- write!(f, "{} seconds", sec)?;
+ write!(f, "{sec} seconds")?;
}
} else if abs.tv_nsec() % 1_000_000 == 0 {
- write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?;
+ write!(f, "{sec}.{:03} seconds", abs.tv_nsec() / 1_000_000)?;
} else if abs.tv_nsec() % 1_000 == 0 {
- write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?;
+ write!(f, "{sec}.{:06} seconds", abs.tv_nsec() / 1_000)?;
} else {
- write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?;
+ write!(f, "{sec}.{:09} seconds", abs.tv_nsec())?;
}
Ok(())
@@ -497,8 +499,7 @@ impl TimeValLike for TimeVal {
fn seconds(seconds: i64) -> TimeVal {
assert!(
(TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds),
- "TimeVal out of bounds; seconds={}",
- seconds
+ "TimeVal out of bounds; seconds={seconds}"
);
#[cfg_attr(target_env = "musl", allow(deprecated))]
// https://github.com/rust-lang/libc/issues/1848
@@ -662,18 +663,18 @@ impl fmt::Display for TimeVal {
let sec = abs.tv_sec();
- write!(f, "{}", sign)?;
+ write!(f, "{sign}")?;
if abs.tv_usec() == 0 {
- if abs.tv_sec() == 1 {
- write!(f, "{} second", sec)?;
+ if sec == 1 {
+ write!(f, "1 second")?;
} else {
- write!(f, "{} seconds", sec)?;
+ write!(f, "{sec} seconds")?;
}
} else if abs.tv_usec() % 1000 == 0 {
- write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?;
+ write!(f, "{sec}.{:03} seconds", abs.tv_usec() / 1000)?;
} else {
- write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?;
+ write!(f, "{sec}.{:06} seconds", abs.tv_usec())?;
}
Ok(())
diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs
index a35fc92..c4337c9 100644
--- a/src/sys/timerfd.rs
+++ b/src/sys/timerfd.rs
@@ -33,24 +33,28 @@ pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags};
use crate::unistd::read;
use crate::{errno::Errno, Result};
use libc::c_int;
-use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
/// A timerfd instance. This is also a file descriptor, you can feed it to
-/// other interfaces consuming file descriptors, epoll for example.
+/// other interfaces taking file descriptors as arguments, [`epoll`] for example.
+///
+/// [`epoll`]: crate::sys::epoll
#[derive(Debug)]
pub struct TimerFd {
- fd: RawFd,
+ fd: OwnedFd,
}
-impl AsRawFd for TimerFd {
- fn as_raw_fd(&self) -> RawFd {
- self.fd
+impl AsFd for TimerFd {
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.fd.as_fd()
}
}
impl FromRawFd for TimerFd {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
- TimerFd { fd }
+ TimerFd {
+ fd: OwnedFd::from_raw_fd(fd),
+ }
}
}
@@ -97,7 +101,9 @@ impl TimerFd {
Errno::result(unsafe {
libc::timerfd_create(clockid as i32, flags.bits())
})
- .map(|fd| Self { fd })
+ .map(|fd| Self {
+ fd: unsafe { OwnedFd::from_raw_fd(fd) },
+ })
}
/// Sets a new alarm on the timer.
@@ -129,6 +135,13 @@ impl TimerFd {
/// Then the one shot TimeSpec and the delay TimeSpec of the delayed
/// interval are going to be interpreted as absolute.
///
+ /// # Cancel on a clock change
+ ///
+ /// If you set a `TFD_TIMER_CANCEL_ON_SET` alongside `TFD_TIMER_ABSTIME`
+ /// and the clock for this timer is `CLOCK_REALTIME` or `CLOCK_REALTIME_ALARM`,
+ /// then this timer is marked as cancelable if the real-time clock undergoes
+ /// a discontinuous change.
+ ///
/// # Disabling alarms
///
/// Note: Only one alarm can be set for any given timer. Setting a new alarm
@@ -145,7 +158,7 @@ impl TimerFd {
let timerspec: TimerSpec = expiration.into();
Errno::result(unsafe {
libc::timerfd_settime(
- self.fd,
+ self.fd.as_fd().as_raw_fd(),
flags.bits(),
timerspec.as_ref(),
std::ptr::null_mut(),
@@ -159,7 +172,10 @@ impl TimerFd {
pub fn get(&self) -> Result<Option<Expiration>> {
let mut timerspec = TimerSpec::none();
Errno::result(unsafe {
- libc::timerfd_gettime(self.fd, timerspec.as_mut())
+ libc::timerfd_gettime(
+ self.fd.as_fd().as_raw_fd(),
+ timerspec.as_mut(),
+ )
})
.map(|_| {
if timerspec.as_ref().it_interval.tv_sec == 0
@@ -179,7 +195,7 @@ impl TimerFd {
pub fn unset(&self) -> Result<()> {
Errno::result(unsafe {
libc::timerfd_settime(
- self.fd,
+ self.fd.as_fd().as_raw_fd(),
TimerSetTimeFlags::empty().bits(),
TimerSpec::none().as_ref(),
std::ptr::null_mut(),
@@ -192,7 +208,10 @@ impl TimerFd {
///
/// Note: If the alarm is unset, then you will wait forever.
pub fn wait(&self) -> Result<()> {
- while let Err(e) = read(self.fd, &mut [0u8; 8]) {
+ while let Err(e) = read(self.fd.as_fd().as_raw_fd(), &mut [0u8; 8]) {
+ if e == Errno::ECANCELED {
+ break;
+ }
if e != Errno::EINTR {
return Err(e);
}
@@ -201,14 +220,3 @@ impl TimerFd {
Ok(())
}
}
-
-impl Drop for TimerFd {
- fn drop(&mut self) {
- if !std::thread::panicking() {
- let result = Errno::result(unsafe { libc::close(self.fd) });
- if let Err(Errno::EBADF) = result {
- panic!("close of TimerFd encountered EBADF");
- }
- }
- }
-}
diff --git a/src/sys/uio.rs b/src/sys/uio.rs
index b31c306..eaf61ed 100644
--- a/src/sys/uio.rs
+++ b/src/sys/uio.rs
@@ -4,13 +4,12 @@ use crate::errno::Errno;
use crate::Result;
use libc::{self, c_int, c_void, off_t, size_t};
use std::io::{IoSlice, IoSliceMut};
-use std::marker::PhantomData;
-use std::os::unix::io::RawFd;
+use std::os::unix::io::{AsFd, AsRawFd};
/// Low-level vectored write to a raw file descriptor
///
/// See also [writev(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html)
-pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result<usize> {
+pub fn writev<Fd: AsFd>(fd: Fd, iov: &[IoSlice<'_>]) -> Result<usize> {
// SAFETY: to quote the documentation for `IoSlice`:
//
// [IoSlice] is semantically a wrapper around a &[u8], but is
@@ -19,7 +18,7 @@ pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result<usize> {
//
// Because it is ABI compatible, a pointer cast here is valid
let res = unsafe {
- libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int)
+ libc::writev(fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len() as c_int)
};
Errno::result(res).map(|r| r as usize)
@@ -28,10 +27,13 @@ pub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result<usize> {
/// Low-level vectored read from a raw file descriptor
///
/// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html)
-pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> {
+// Clippy doesn't know that we need to pass iov mutably only because the
+// mutation happens after converting iov to a pointer
+#[allow(clippy::needless_pass_by_ref_mut)]
+pub fn readv<Fd: 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, iov.as_ptr() as *const libc::iovec, iov.len() as c_int)
+ libc::readv(fd.as_fd().as_raw_fd(), iov.as_ptr() as *const libc::iovec, iov.len() as c_int)
};
Errno::result(res).map(|r| r as usize)
@@ -45,14 +47,14 @@ pub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> {
/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html)
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
-pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result<usize> {
+pub fn pwritev<Fd: 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
// SAFETY: same as in writev()
let res = unsafe {
libc::pwritev(
- fd,
+ fd.as_fd().as_raw_fd(),
iov.as_ptr() as *const libc::iovec,
iov.len() as c_int,
offset,
@@ -71,8 +73,11 @@ pub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result<usize> {
/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html)
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
-pub fn preadv(
- fd: RawFd,
+// Clippy doesn't know that we need to pass iov mutably only because the
+// mutation happens after converting iov to a pointer
+#[allow(clippy::needless_pass_by_ref_mut)]
+pub fn preadv<Fd: AsFd>(
+ fd: Fd,
iov: &mut [IoSliceMut<'_>],
offset: off_t,
) -> Result<usize> {
@@ -82,7 +87,7 @@ pub fn preadv(
// SAFETY: same as in readv()
let res = unsafe {
libc::preadv(
- fd,
+ fd.as_fd().as_raw_fd(),
iov.as_ptr() as *const libc::iovec,
iov.len() as c_int,
offset,
@@ -96,10 +101,10 @@ pub fn preadv(
///
/// See also [pwrite(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html)
// TODO: move to unistd
-pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> {
+pub fn pwrite<Fd: AsFd>(fd: Fd, buf: &[u8], offset: off_t) -> Result<usize> {
let res = unsafe {
libc::pwrite(
- fd,
+ fd.as_fd().as_raw_fd(),
buf.as_ptr() as *const c_void,
buf.len() as size_t,
offset,
@@ -113,10 +118,10 @@ pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> {
///
/// See also [pread(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html)
// TODO: move to unistd
-pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize> {
+pub fn pread<Fd: AsFd>(fd: Fd, buf: &mut [u8], offset: off_t) -> Result<usize> {
let res = unsafe {
libc::pread(
- fd,
+ fd.as_fd().as_raw_fd(),
buf.as_mut_ptr() as *mut c_void,
buf.len() as size_t,
offset,
@@ -145,77 +150,6 @@ pub struct RemoteIoVec {
pub len: usize,
}
-/// A vector of buffers.
-///
-/// Vectored I/O methods like [`writev`] and [`readv`] use this structure for
-/// both reading and writing. Each `IoVec` specifies the base address and
-/// length of an area in memory.
-#[deprecated(
- since = "0.24.0",
- note = "`IoVec` is no longer used in the public interface, use `IoSlice` or `IoSliceMut` instead"
-)]
-#[repr(transparent)]
-#[allow(renamed_and_removed_lints)]
-#[allow(clippy::unknown_clippy_lints)]
-// Clippy false positive: https://github.com/rust-lang/rust-clippy/issues/8867
-#[allow(clippy::derive_partial_eq_without_eq)]
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-pub struct IoVec<T>(pub(crate) libc::iovec, PhantomData<T>);
-
-#[allow(deprecated)]
-impl<T> IoVec<T> {
- /// View the `IoVec` as a Rust slice.
- #[deprecated(
- since = "0.24.0",
- note = "Use the `Deref` impl of `IoSlice` or `IoSliceMut` instead"
- )]
- #[inline]
- pub fn as_slice(&self) -> &[u8] {
- use std::slice;
-
- unsafe {
- slice::from_raw_parts(self.0.iov_base as *const u8, self.0.iov_len)
- }
- }
-}
-
-#[allow(deprecated)]
-impl<'a> IoVec<&'a [u8]> {
- /// Create an `IoVec` from a Rust slice.
- #[deprecated(since = "0.24.0", note = "Use `IoSlice::new` instead")]
- pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> {
- IoVec(
- libc::iovec {
- iov_base: buf.as_ptr() as *mut c_void,
- iov_len: buf.len() as size_t,
- },
- PhantomData,
- )
- }
-}
-
-#[allow(deprecated)]
-impl<'a> IoVec<&'a mut [u8]> {
- /// Create an `IoVec` from a mutable Rust slice.
- #[deprecated(since = "0.24.0", note = "Use `IoSliceMut::new` instead")]
- pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> {
- IoVec(
- libc::iovec {
- iov_base: buf.as_ptr() as *mut c_void,
- iov_len: buf.len() as size_t,
- },
- PhantomData,
- )
- }
-}
-
-// The only reason IoVec isn't automatically Send+Sync is because libc::iovec
-// contains raw pointers.
-#[allow(deprecated)]
-unsafe impl<T> Send for IoVec<T> where T: Send {}
-#[allow(deprecated)]
-unsafe impl<T> Sync for IoVec<T> where T: Sync {}
-
feature! {
#![feature = "process"]
diff --git a/src/sys/wait.rs b/src/sys/wait.rs
index b6524e8..f7a63ff 100644
--- a/src/sys/wait.rs
+++ b/src/sys/wait.rs
@@ -10,7 +10,7 @@ use std::convert::TryFrom;
target_os = "android",
all(target_os = "linux", not(target_env = "uclibc")),
))]
-use std::os::unix::io::RawFd;
+use std::os::unix::io::{AsRawFd, BorrowedFd};
libc_bitflags!(
/// Controls the behavior of [`waitpid`].
@@ -343,8 +343,8 @@ pub fn wait() -> Result<WaitStatus> {
target_os = "haiku",
all(target_os = "linux", not(target_env = "uclibc")),
))]
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum Id {
+#[derive(Debug)]
+pub enum Id<'fd> {
/// Wait for any child
All,
/// Wait for the child whose process ID matches the given PID
@@ -355,7 +355,11 @@ pub enum Id {
PGid(Pid),
/// Wait for the child referred to by the given PID file descriptor
#[cfg(any(target_os = "android", target_os = "linux"))]
- PIDFd(RawFd),
+ PIDFd(BorrowedFd<'fd>),
+ /// A helper variant to resolve the unused parameter (`'fd`) problem on platforms
+ /// other than Linux and Android.
+ #[doc(hidden)]
+ _Unreachable(std::marker::PhantomData<&'fd std::convert::Infallible>),
}
/// Wait for a process to change status
@@ -373,7 +377,8 @@ pub fn waitid(id: Id, flags: WaitPidFlag) -> Result<WaitStatus> {
Id::Pid(pid) => (libc::P_PID, pid.as_raw() as libc::id_t),
Id::PGid(pid) => (libc::P_PGID, pid.as_raw() as libc::id_t),
#[cfg(any(target_os = "android", target_os = "linux"))]
- Id::PIDFd(fd) => (libc::P_PIDFD, fd as libc::id_t),
+ Id::PIDFd(fd) => (libc::P_PIDFD, fd.as_raw_fd() as libc::id_t),
+ Id::_Unreachable(_) => unreachable!("This variant could never be constructed"),
};
let siginfo = unsafe {
diff --git a/src/unistd.rs b/src/unistd.rs
index ca07b34..bb9f1c1 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -35,6 +35,7 @@ use std::ffi::{CString, OsStr};
use std::os::unix::ffi::OsStrExt;
use std::os::unix::ffi::OsStringExt;
use std::os::unix::io::RawFd;
+use std::os::unix::io::{AsFd, AsRawFd};
use std::path::PathBuf;
use std::{fmt, mem, ptr};
@@ -217,7 +218,6 @@ impl fmt::Display for Pid {
}
}
-
/// Represents the successful result of calling `fork`
///
/// When `fork` is called, the process continues execution in the parent process
@@ -230,7 +230,6 @@ pub enum ForkResult {
}
impl ForkResult {
-
/// Return `true` if this is the child process of the `fork()`
#[inline]
pub fn is_child(self) -> bool {
@@ -478,9 +477,8 @@ fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
/// pages for additional details on possible failure cases.
#[inline]
pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
- let res = path.with_nix_path(|cstr| {
- unsafe { libc::chdir(cstr.as_ptr()) }
- })?;
+ let res =
+ path.with_nix_path(|cstr| unsafe { libc::chdir(cstr.as_ptr()) })?;
Errno::result(res).map(drop)
}
@@ -527,8 +525,8 @@ pub fn fchdir(dirfd: RawFd) -> Result<()> {
/// ```
#[inline]
pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
- let res = path.with_nix_path(|cstr| {
- unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) }
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t)
})?;
Errno::result(res).map(drop)
@@ -566,8 +564,8 @@ pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
#[inline]
#[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet
pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
- let res = path.with_nix_path(|cstr| {
- unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) }
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t)
})?;
Errno::result(res).map(drop)
@@ -585,9 +583,17 @@ 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", target_os = "haiku",
- target_os = "android", target_os = "redox")))]
-pub fn mkfifoat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Mode) -> Result<()> {
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "haiku",
+ target_os = "android",
+ target_os = "redox"
+)))]
+pub fn mkfifoat<P: ?Sized + NixPath>(
+ dirfd: Option<RawFd>,
+ path: &P,
+ mode: Mode,
+) -> Result<()> {
let res = path.with_nix_path(|cstr| unsafe {
libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t)
})?;
@@ -608,19 +614,17 @@ pub fn mkfifoat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Mode)
pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
path1: &P1,
dirfd: Option<RawFd>,
- path2: &P2) -> Result<()> {
- let res =
- path1.with_nix_path(|path1| {
- path2.with_nix_path(|path2| {
- unsafe {
- libc::symlinkat(
- path1.as_ptr(),
- dirfd.unwrap_or(libc::AT_FDCWD),
- path2.as_ptr()
- )
- }
- })
- })??;
+ path2: &P2,
+) -> Result<()> {
+ let res = path1.with_nix_path(|path1| {
+ path2.with_nix_path(|path2| unsafe {
+ libc::symlinkat(
+ path1.as_ptr(),
+ dirfd.unwrap_or(libc::AT_FDCWD),
+ path2.as_ptr(),
+ )
+ })
+ })??;
Errno::result(res).map(drop)
}
}
@@ -670,7 +674,9 @@ pub fn getcwd() -> Result<PathBuf> {
// To safely handle this we start with a reasonable size (512 bytes)
// and double the buffer size upon every error
if !libc::getcwd(ptr, buf.capacity()).is_null() {
- let len = CStr::from_ptr(buf.as_ptr() as *const c_char).to_bytes().len();
+ let len = CStr::from_ptr(buf.as_ptr() as *const c_char)
+ .to_bytes()
+ .len();
buf.set_len(len);
buf.shrink_to_fit();
return Ok(PathBuf::from(OsString::from_vec(buf)));
@@ -680,7 +686,7 @@ pub fn getcwd() -> Result<PathBuf> {
if error != Errno::ERANGE {
return Err(error);
}
- }
+ }
// Trigger the internal buffer resizing logic.
reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?;
@@ -695,13 +701,15 @@ feature! {
/// Computes the raw UID and GID values to pass to a `*chown` call.
// The cast is not unnecessary on all platforms.
#[allow(clippy::unnecessary_cast)]
-fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t) {
+fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (uid_t, gid_t) {
// According to the POSIX specification, -1 is used to indicate that owner and group
// are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap
// around to get -1.
- let uid = owner.map(Into::into)
+ let uid = owner
+ .map(Into::into)
.unwrap_or_else(|| (0 as uid_t).wrapping_sub(1));
- let gid = group.map(Into::into)
+ let gid = group
+ .map(Into::into)
.unwrap_or_else(|| (0 as gid_t).wrapping_sub(1));
(uid, gid)
}
@@ -714,7 +722,11 @@ fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::
/// provided for that argument. Ownership change will be attempted for the path
/// only if `Some` owner/group is provided.
#[inline]
-pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
+pub fn chown<P: ?Sized + NixPath>(
+ path: &P,
+ owner: Option<Uid>,
+ group: Option<Gid>,
+) -> Result<()> {
let res = path.with_nix_path(|cstr| {
let (uid, gid) = chown_raw_ids(owner, group);
unsafe { libc::chown(cstr.as_ptr(), uid, gid) }
@@ -773,15 +785,19 @@ pub fn fchownat<P: ?Sized + NixPath>(
group: Option<Gid>,
flag: FchownatFlags,
) -> Result<()> {
- let atflag =
- match flag {
- FchownatFlags::FollowSymlink => AtFlags::empty(),
- FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
- };
+ let atflag = match flag {
+ FchownatFlags::FollowSymlink => AtFlags::empty(),
+ FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
+ };
let res = path.with_nix_path(|cstr| unsafe {
let (uid, gid) = chown_raw_ids(owner, group);
- libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid,
- atflag.bits() as libc::c_int)
+ libc::fchownat(
+ at_rawfd(dirfd),
+ cstr.as_ptr(),
+ uid,
+ gid,
+ atflag.bits() as libc::c_int,
+ )
})?;
Errno::result(res).map(drop)
@@ -808,14 +824,11 @@ fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char> {
pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> {
let args_p = to_exec_array(argv);
- unsafe {
- libc::execv(path.as_ptr(), args_p.as_ptr())
- };
+ unsafe { libc::execv(path.as_ptr(), args_p.as_ptr()) };
Err(Errno::last())
}
-
/// Replace the current process image with a new one (see
/// [execve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
///
@@ -829,13 +842,15 @@ pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> {
/// in the `args` list is an argument to the new process. Each element in the
/// `env` list should be a string in the form "key=value".
#[inline]
-pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> {
+pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(
+ path: &CStr,
+ args: &[SA],
+ env: &[SE],
+) -> Result<Infallible> {
let args_p = to_exec_array(args);
let env_p = to_exec_array(env);
- unsafe {
- libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
- };
+ unsafe { libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) };
Err(Errno::last())
}
@@ -850,12 +865,13 @@ pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &
/// would not work if "bash" was specified for the path argument, but `execvp`
/// would assuming that a bash executable was on the system `PATH`.
#[inline]
-pub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible> {
+pub fn execvp<S: AsRef<CStr>>(
+ filename: &CStr,
+ args: &[S],
+) -> Result<Infallible> {
let args_p = to_exec_array(args);
- unsafe {
- libc::execvp(filename.as_ptr(), args_p.as_ptr())
- };
+ unsafe { libc::execvp(filename.as_ptr(), args_p.as_ptr()) };
Err(Errno::last())
}
@@ -867,10 +883,12 @@ pub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible>
/// This functions like a combination of `execvp(2)` and `execve(2)` to pass an
/// environment and have a search path. See these two for additional
/// information.
-#[cfg(any(target_os = "haiku",
- target_os = "linux",
- target_os = "openbsd"))]
-pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> {
+#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))]
+pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(
+ filename: &CStr,
+ args: &[SA],
+ env: &[SE],
+) -> Result<Infallible> {
let args_p = to_exec_array(args);
let env_p = to_exec_array(env);
@@ -891,18 +909,22 @@ pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], e
///
/// This function is similar to `execve`, except that the program to be executed
/// is referenced as a file descriptor instead of a path.
-#[cfg(any(target_os = "android",
- target_os = "linux",
- target_os = "dragonfly",
- target_os = "freebsd"))]
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd"
+))]
#[inline]
-pub fn fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[SE]) -> Result<Infallible> {
+pub fn fexecve<SA: AsRef<CStr>, SE: AsRef<CStr>>(
+ fd: RawFd,
+ args: &[SA],
+ env: &[SE],
+) -> Result<Infallible> {
let args_p = to_exec_array(args);
let env_p = to_exec_array(env);
- unsafe {
- libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr())
- };
+ unsafe { libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr()) };
Err(Errno::last())
}
@@ -919,14 +941,25 @@ pub fn fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[
/// is referenced as a file descriptor to the base directory plus a path.
#[cfg(any(target_os = "android", target_os = "linux"))]
#[inline]
-pub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, args: &[SA],
- env: &[SE], flags: super::fcntl::AtFlags) -> Result<Infallible> {
+pub fn execveat<SA: AsRef<CStr>, SE: AsRef<CStr>>(
+ dirfd: RawFd,
+ pathname: &CStr,
+ args: &[SA],
+ env: &[SE],
+ flags: super::fcntl::AtFlags,
+) -> Result<Infallible> {
let args_p = to_exec_array(args);
let env_p = to_exec_array(env);
unsafe {
- libc::syscall(libc::SYS_execveat, dirfd, pathname.as_ptr(),
- args_p.as_ptr(), env_p.as_ptr(), flags);
+ libc::syscall(
+ libc::SYS_execveat,
+ dirfd,
+ pathname.as_ptr(),
+ args_p.as_ptr(),
+ env_p.as_ptr(),
+ flags,
+ );
};
Err(Errno::last())
@@ -957,14 +990,16 @@ pub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr,
/// descriptors will remain identical after daemonizing.
/// * `noclose = false`: The process' stdin, stdout, and stderr will point to
/// `/dev/null` after daemonizing.
-#[cfg(any(target_os = "android",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "illumos",
- target_os = "linux",
- target_os = "netbsd",
- target_os = "openbsd",
- target_os = "solaris"))]
+#[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris"
+))]
pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) };
Errno::result(res).map(drop)
@@ -990,6 +1025,7 @@ pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
target_os = "illumos",
target_os = "ios",
target_os = "macos",
+ target_os = "aix",
target_os = "solaris", ))] {
type sethostname_len_t = c_int;
} else {
@@ -1106,23 +1142,27 @@ pub enum Whence {
/// Specify an offset relative to the next location in the file greater than or
/// equal to offset that contains some data. If offset points to
/// some data, then the file offset is set to offset.
- #[cfg(any(target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "illumos",
- target_os = "linux",
- target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "solaris"
+ ))]
SeekData = libc::SEEK_DATA,
/// Specify an offset relative to the next hole in the file greater than
/// or equal to offset. If offset points into the middle of a hole, then
/// the file offset should be set to offset. If there is no hole past offset,
/// then the file offset should be adjusted to the end of the file (i.e., there
/// is an implicit hole at the end of any file).
- #[cfg(any(target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "illumos",
- target_os = "linux",
- target_os = "solaris"))]
- SeekHole = libc::SEEK_HOLE
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "solaris"
+ ))]
+ SeekHole = libc::SEEK_HOLE,
}
/// Move the read/write file offset.
@@ -1135,7 +1175,11 @@ pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> {
}
#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc::off64_t> {
+pub fn lseek64(
+ fd: RawFd,
+ offset: libc::off64_t,
+ whence: Whence,
+) -> Result<libc::off64_t> {
let res = unsafe { libc::lseek64(fd, offset, whence as i32) };
Errno::result(res).map(|r| r as libc::off64_t)
@@ -1163,27 +1207,34 @@ feature! {
/// created:
///
/// - `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors.
-#[cfg_attr(target_os = "linux", doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode.")]
-#[cfg_attr(target_os = "netbsd", doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`.")]
+#[cfg_attr(
+ target_os = "linux",
+ doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode."
+)]
+#[cfg_attr(
+ target_os = "netbsd",
+ doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`."
+)]
/// - `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe.
///
/// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html)
-#[cfg(any(target_os = "android",
- target_os = "dragonfly",
- target_os = "emscripten",
- target_os = "freebsd",
- target_os = "illumos",
- target_os = "linux",
- target_os = "redox",
- target_os = "netbsd",
- target_os = "openbsd",
- target_os = "solaris"))]
+#[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "redox",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris"
+))]
pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
- let res = unsafe {
- libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits())
- };
+ let res =
+ unsafe { libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) };
Errno::result(res)?;
@@ -1196,11 +1247,8 @@ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
/// [truncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html)
#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> {
- let res = path.with_nix_path(|cstr| {
- unsafe {
- libc::truncate(cstr.as_ptr(), len)
- }
- })?;
+ let res = path
+ .with_nix_path(|cstr| unsafe { libc::truncate(cstr.as_ptr(), len) })?;
Errno::result(res).map(drop)
}
@@ -1209,8 +1257,8 @@ pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> {
///
/// See also
/// [ftruncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html)
-pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> {
- Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop)
+pub fn ftruncate<Fd: AsFd>(fd: Fd, len: off_t) -> Result<()> {
+ Errno::result(unsafe { libc::ftruncate(fd.as_fd().as_raw_fd(), len) }).map(drop)
}
pub fn isatty(fd: RawFd) -> Result<bool> {
@@ -1224,7 +1272,7 @@ pub fn isatty(fd: RawFd) -> Result<bool> {
Errno::ENOTTY => Ok(false),
err => Err(err),
}
- }
+ }
}
}
@@ -1256,40 +1304,31 @@ pub fn linkat<P: ?Sized + NixPath>(
newpath: &P,
flag: LinkatFlags,
) -> Result<()> {
+ let atflag = match flag {
+ LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW,
+ LinkatFlags::NoSymlinkFollow => AtFlags::empty(),
+ };
- let atflag =
- match flag {
- LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW,
- LinkatFlags::NoSymlinkFollow => AtFlags::empty(),
- };
-
- let res =
- oldpath.with_nix_path(|oldcstr| {
- newpath.with_nix_path(|newcstr| {
- unsafe {
- libc::linkat(
- at_rawfd(olddirfd),
- oldcstr.as_ptr(),
- at_rawfd(newdirfd),
- newcstr.as_ptr(),
- atflag.bits() as libc::c_int
- )
- }
- })
- })??;
+ let res = oldpath.with_nix_path(|oldcstr| {
+ newpath.with_nix_path(|newcstr| unsafe {
+ libc::linkat(
+ at_rawfd(olddirfd),
+ oldcstr.as_ptr(),
+ at_rawfd(newdirfd),
+ newcstr.as_ptr(),
+ atflag.bits() as libc::c_int,
+ )
+ })
+ })??;
Errno::result(res).map(drop)
}
-
/// Remove a directory entry
///
/// See also [unlink(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html)
pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> {
- let res = path.with_nix_path(|cstr| {
- unsafe {
- libc::unlink(cstr.as_ptr())
- }
- })?;
+ let res =
+ path.with_nix_path(|cstr| unsafe { libc::unlink(cstr.as_ptr()) })?;
Errno::result(res).map(drop)
}
@@ -1316,26 +1355,25 @@ pub fn unlinkat<P: ?Sized + NixPath>(
path: &P,
flag: UnlinkatFlags,
) -> Result<()> {
- let atflag =
- match flag {
- UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR,
- UnlinkatFlags::NoRemoveDir => AtFlags::empty(),
- };
- let res = path.with_nix_path(|cstr| {
- unsafe {
- libc::unlinkat(at_rawfd(dirfd), cstr.as_ptr(), atflag.bits() as libc::c_int)
- }
+ let atflag = match flag {
+ UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR,
+ UnlinkatFlags::NoRemoveDir => AtFlags::empty(),
+ };
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::unlinkat(
+ at_rawfd(dirfd),
+ cstr.as_ptr(),
+ atflag.bits() as libc::c_int,
+ )
})?;
Errno::result(res).map(drop)
}
-
#[inline]
#[cfg(not(target_os = "fuchsia"))]
pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
- let res = path.with_nix_path(|cstr| {
- unsafe { libc::chroot(cstr.as_ptr()) }
- })?;
+ let res =
+ path.with_nix_path(|cstr| unsafe { libc::chroot(cstr.as_ptr()) })?;
Errno::result(res).map(drop)
}
@@ -1379,15 +1417,17 @@ pub fn fsync(fd: RawFd) -> Result<()> {
///
/// See also
/// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html)
-#[cfg(any(target_os = "linux",
- target_os = "android",
- target_os = "emscripten",
- target_os = "freebsd",
- target_os = "fuchsia",
- target_os = "netbsd",
- target_os = "openbsd",
- target_os = "illumos",
- target_os = "solaris"))]
+#[cfg(any(
+ target_os = "linux",
+ target_os = "android",
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "fuchsia",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "illumos",
+ target_os = "solaris"
+))]
#[inline]
pub fn fdatasync(fd: RawFd) -> Result<()> {
let res = unsafe { libc::fdatasync(fd) };
@@ -1539,27 +1579,31 @@ pub fn getgroups() -> Result<Vec<Gid>> {
// Now actually get the groups. We try multiple times in case the number of
// groups has changed since the first call to getgroups() and the buffer is
// now too small.
- let mut groups = Vec::<Gid>::with_capacity(Errno::result(ngroups)? as usize);
+ let mut groups =
+ Vec::<Gid>::with_capacity(Errno::result(ngroups)? as usize);
loop {
// FIXME: On the platforms we currently support, the `Gid` struct has
// the same representation in memory as a bare `gid_t`. This is not
// necessarily the case on all Rust platforms, though. See RFC 1785.
let ngroups = unsafe {
- libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t)
+ libc::getgroups(
+ groups.capacity() as c_int,
+ groups.as_mut_ptr() as *mut gid_t,
+ )
};
match Errno::result(ngroups) {
Ok(s) => {
unsafe { groups.set_len(s as usize) };
return Ok(groups);
- },
+ }
Err(Errno::EINVAL) => {
// EINVAL indicates that the buffer size was too
// small, resize it up to ngroups_max as limit.
reserve_double_buffer_size(&mut groups, ngroups_max)
.or(Err(Errno::EINVAL))?;
- },
- Err(e) => return Err(e)
+ }
+ Err(e) => return Err(e),
}
}
}
@@ -1595,17 +1639,23 @@ pub fn getgroups() -> Result<Vec<Gid>> {
/// #
/// # try_main().unwrap();
/// ```
-#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))]
+#[cfg(not(any(
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "redox",
+ target_os = "haiku"
+)))]
pub fn setgroups(groups: &[Gid]) -> Result<()> {
cfg_if! {
- if #[cfg(any(target_os = "dragonfly",
+ 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 = "illumos",
- target_os = "openbsd"))] {
+ target_os = "openbsd",
+ target_os = "solaris"))] {
type setgroups_ngroups_t = c_int;
} else {
type setgroups_ngroups_t = size_t;
@@ -1615,7 +1665,10 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> {
// same representation in memory as a bare `gid_t`. This is not necessarily
// the case on all Rust platforms, though. See RFC 1785.
let res = unsafe {
- libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t)
+ libc::setgroups(
+ groups.len() as setgroups_ngroups_t,
+ groups.as_ptr() as *const gid_t,
+ )
};
Errno::result(res).map(drop)
@@ -1641,10 +1694,13 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> {
/// and `setgroups()`. Additionally, while some implementations will return a
/// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation
/// will only ever return the complete list or else an error.
-#[cfg(not(any(target_os = "illumos",
- target_os = "ios",
- target_os = "macos",
- target_os = "redox")))]
+#[cfg(not(any(
+ target_os = "aix",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "macos",
+ 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,
@@ -1663,10 +1719,12 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
loop {
let mut ngroups = groups.capacity() as i32;
let ret = unsafe {
- libc::getgrouplist(user.as_ptr(),
- gid as getgrouplist_group_t,
- groups.as_mut_ptr() as *mut getgrouplist_group_t,
- &mut ngroups)
+ libc::getgrouplist(
+ user.as_ptr(),
+ gid as getgrouplist_group_t,
+ groups.as_mut_ptr() as *mut getgrouplist_group_t,
+ &mut ngroups,
+ )
};
// BSD systems only return 0 or -1, Linux returns ngroups on success.
@@ -1722,7 +1780,12 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
/// #
/// # try_main().unwrap();
/// ```
-#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))]
+#[cfg(not(any(
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "redox",
+ target_os = "haiku"
+)))]
pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
cfg_if! {
if #[cfg(any(target_os = "ios", target_os = "macos"))] {
@@ -1732,7 +1795,8 @@ pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
}
}
let gid: gid_t = group.into();
- let res = unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) };
+ let res =
+ unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) };
Errno::result(res).map(drop)
}
@@ -1776,8 +1840,8 @@ pub mod alarm {
//!
//! Scheduling an alarm and waiting for the signal:
//!
-#![cfg_attr(target_os = "redox", doc = " ```rust,ignore")]
-#![cfg_attr(not(target_os = "redox"), doc = " ```rust")]
+ #![cfg_attr(target_os = "redox", doc = " ```rust,ignore")]
+ #![cfg_attr(not(target_os = "redox"), doc = " ```rust")]
//! use std::time::{Duration, Instant};
//!
//! use nix::unistd::{alarm, pause};
@@ -1853,17 +1917,16 @@ feature! {
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
pub mod acct {
- use crate::{Result, NixPath};
use crate::errno::Errno;
+ use crate::{NixPath, Result};
use std::ptr;
/// Enable process accounting
///
/// See also [acct(2)](https://linux.die.net/man/2/acct)
pub fn enable<P: ?Sized + NixPath>(filename: &P) -> Result<()> {
- let res = filename.with_nix_path(|cstr| {
- unsafe { libc::acct(cstr.as_ptr()) }
- })?;
+ let res = filename
+ .with_nix_path(|cstr| unsafe { libc::acct(cstr.as_ptr()) })?;
Errno::result(res).map(drop)
}
@@ -1905,7 +1968,8 @@ feature! {
/// ```
#[inline]
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 mut path =
+ template.with_nix_path(|path| path.to_bytes_with_nul().to_owned())?;
let p = path.as_mut_ptr() as *mut _;
let fd = unsafe { libc::mkstemp(p) };
let last = path.pop(); // drop the trailing nul
@@ -1939,8 +2003,14 @@ feature! {
#[repr(i32)]
#[non_exhaustive]
pub enum PathconfVar {
- #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux",
- target_os = "netbsd", target_os = "openbsd", target_os = "redox"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "redox"
+ ))]
/// Minimum number of bits needed to represent, as a signed integer value,
/// the maximum size of a regular file allowed in the specified directory.
#[cfg_attr(docsrs, doc(cfg(all())))]
@@ -1964,42 +2034,86 @@ pub enum PathconfVar {
/// Maximum number of bytes that is guaranteed to be atomic when writing to
/// a pipe.
PIPE_BUF = libc::_PC_PIPE_BUF,
- #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "illumos",
- target_os = "linux", target_os = "netbsd", target_os = "openbsd",
- target_os = "redox", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "redox",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Symbolic links can be created.
POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS,
- #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
- target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "openbsd",
+ target_os = "redox"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Minimum number of bytes of storage actually allocated for any portion of
/// a file.
POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN,
- #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
- target_os = "linux", target_os = "openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Recommended increment for file transfer sizes between the
/// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values.
POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE,
- #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
- target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "openbsd",
+ target_os = "redox"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Maximum recommended file transfer size.
POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE,
- #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
- target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "openbsd",
+ target_os = "redox"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Minimum recommended file transfer size.
POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE,
- #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
- target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "openbsd",
+ target_os = "redox"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Recommended file transfer buffer alignment.
POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN,
- #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
- target_os = "illumos", target_os = "linux", target_os = "netbsd",
- target_os = "openbsd", target_os = "redox", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "redox",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Maximum number of bytes in a symbolic link.
SYMLINK_MAX = libc::_PC_SYMLINK_MAX,
@@ -2013,23 +2127,45 @@ pub enum PathconfVar {
/// This symbol shall be defined to be the value of a character that shall
/// disable terminal special character handling.
_POSIX_VDISABLE = libc::_PC_VDISABLE,
- #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
- target_os = "illumos", target_os = "linux", target_os = "openbsd",
- target_os = "redox", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "openbsd",
+ target_os = "redox",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Asynchronous input or output operations may be performed for the
/// associated file.
_POSIX_ASYNC_IO = libc::_PC_ASYNC_IO,
- #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
- target_os = "illumos", target_os = "linux", target_os = "openbsd",
- target_os = "redox", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "openbsd",
+ target_os = "redox",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Prioritized input or output operations may be performed for the
/// associated file.
_POSIX_PRIO_IO = libc::_PC_PRIO_IO,
- #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
- target_os = "illumos", target_os = "linux", target_os = "netbsd",
- target_os = "openbsd", target_os = "redox", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "redox",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Synchronized input or output operations may be performed for the
/// associated file.
@@ -2037,7 +2173,7 @@ pub enum PathconfVar {
#[cfg(any(target_os = "dragonfly", target_os = "openbsd"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The resolution in nanoseconds for all file timestamps.
- _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION
+ _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION,
}
/// Like `pathconf`, but works with file descriptors instead of paths (see
@@ -2093,12 +2229,13 @@ pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> {
/// - `Ok(None)`: the variable has no limit (for limit variables) or is
/// unsupported (for option variables)
/// - `Err(x)`: an error occurred
-pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Option<c_long>> {
- let raw = path.with_nix_path(|cstr| {
- unsafe {
- Errno::clear();
- libc::pathconf(cstr.as_ptr(), var as c_int)
- }
+pub fn pathconf<P: ?Sized + NixPath>(
+ path: &P,
+ var: PathconfVar,
+) -> Result<Option<c_long>> {
+ let raw = path.with_nix_path(|cstr| unsafe {
+ Errno::clear();
+ libc::pathconf(cstr.as_ptr(), var as c_int)
})?;
if raw == -1 {
if errno::errno() == 0 {
@@ -2145,9 +2282,15 @@ pub enum SysconfVar {
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
AIO_MAX = libc::_SC_AIO_MAX,
- #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The maximum amount by which a process can decrease its asynchronous I/O
/// priority level from its own scheduling priority.
@@ -2192,9 +2335,17 @@ pub enum SysconfVar {
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Maximum length of a host name (not including the terminating null) as
/// returned from the `gethostname` function
@@ -2235,14 +2386,28 @@ pub enum SysconfVar {
/// A value one greater than the maximum value that the system may assign to
/// a newly-created file descriptor.
OPEN_MAX = libc::_SC_OPEN_MAX,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Advisory Information option.
_POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports barriers.
_POSIX_BARRIERS = libc::_SC_BARRIERS,
@@ -2250,15 +2415,31 @@ pub enum SysconfVar {
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports clock selection.
_POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Process CPU-Time Clocks option.
_POSIX_CPUTIME = libc::_SC_CPUTIME,
@@ -2266,9 +2447,16 @@ pub enum SysconfVar {
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_FSYNC = libc::_SC_FSYNC,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the IPv6 option.
_POSIX_IPV6 = libc::_SC_IPV6,
@@ -2300,9 +2488,17 @@ pub enum SysconfVar {
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK,
- #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
- target_os = "illumos", target_os = "ios", target_os="linux",
- target_os = "macos", target_os="openbsd", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Prioritized Input and Output option.
_POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO,
@@ -2310,27 +2506,56 @@ pub enum SysconfVar {
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Raw Sockets option.
_POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports read-write locks.
_POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS,
- #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os = "openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports realtime signals.
_POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "solaris"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Regular Expression Handling option.
_POSIX_REGEXP = libc::_SC_REGEXP,
@@ -2346,31 +2571,59 @@ pub enum SysconfVar {
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the POSIX shell.
_POSIX_SHELL = libc::_SC_SHELL,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Spawn option.
_POSIX_SPAWN = libc::_SC_SPAWN,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports spin locks.
_POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Process Sporadic Server option.
_POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER,
- #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX,
/// The implementation supports the Synchronized Input and Output option.
@@ -2385,8 +2638,13 @@ pub enum SysconfVar {
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE,
- #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
- target_os="netbsd", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Thread CPU-Time Clocks option.
_POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME,
@@ -2403,18 +2661,32 @@ pub enum SysconfVar {
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Thread Process-Shared Synchronization
/// option.
_POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED,
- #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "linux",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Robust Mutex Priority Inheritance option.
_POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT,
- #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "linux",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Robust Mutex Priority Protection option.
_POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT,
@@ -2422,8 +2694,14 @@ pub enum SysconfVar {
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Thread Sporadic Server option.
_POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER,
@@ -2431,8 +2709,14 @@ pub enum SysconfVar {
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_THREADS = libc::_SC_THREADS,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports timeouts.
_POSIX_TIMEOUTS = libc::_SC_TIMEOUTS,
@@ -2440,44 +2724,90 @@ pub enum SysconfVar {
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_TIMERS = libc::_SC_TIMERS,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Trace option.
_POSIX_TRACE = libc::_SC_TRACE,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Trace Event Filter option.
_POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER,
- #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Trace Inherit option.
_POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Trace Log option.
_POSIX_TRACE_LOG = libc::_SC_TRACE_LOG,
- #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX,
- #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX,
- #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Typed Memory Objects option.
_POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS,
@@ -2485,31 +2815,55 @@ pub enum SysconfVar {
/// to which the implementation conforms. For implementations conforming to
/// POSIX.1-2008, the value shall be 200809L.
_POSIX_VERSION = libc::_SC_VERSION,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation provides a C-language compilation environment with
/// 32-bit `int`, `long`, `pointer`, and `off_t` types.
_POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation provides a C-language compilation environment with
/// 32-bit `int`, `long`, and pointer types and an `off_t` type using at
/// least 64 bits.
_POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation provides a C-language compilation environment with
/// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types.
_POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation provides a C-language compilation environment with an
/// `int` type using at least 32 bits and `long`, pointer, and `off_t` types
@@ -2540,40 +2894,76 @@ pub enum SysconfVar {
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Batch Environment Services and Utilities
/// option.
_POSIX2_PBS = libc::_SC_2_PBS,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Batch Accounting option.
_POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Batch Checkpoint/Restart option.
_POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Locate Batch Job Request option.
_POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Batch Job Message Request option.
_POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Track Batch Job Request option.
_POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK,
@@ -2609,28 +2999,52 @@ pub enum SysconfVar {
PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX,
#[cfg(not(target_os = "haiku"))]
RE_DUP_MAX = libc::_SC_RE_DUP_MAX,
- #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
RTSIG_MAX = libc::_SC_RTSIG_MAX,
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX,
- #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX,
- #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os = "openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX,
STREAM_MAX = libc::_SC_STREAM_MAX,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="netbsd",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX,
#[cfg(not(target_os = "redox"))]
@@ -2638,33 +3052,63 @@ pub enum SysconfVar {
TIMER_MAX = libc::_SC_TIMER_MAX,
TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX,
TZNAME_MAX = libc::_SC_TZNAME_MAX,
- #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the X/Open Encryption Option Group.
_XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT,
- #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the Issue 4, Version 2 Enhanced
/// Internationalization Option Group.
_XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N,
- #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY,
- #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the X/Open Realtime Option Group.
_XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME,
- #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the X/Open Realtime Threads Option Group.
_XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS,
@@ -2673,36 +3117,54 @@ pub enum SysconfVar {
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
_XOPEN_SHM = libc::_SC_XOPEN_SHM,
- #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
- target_os="linux", target_os = "macos", target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the XSI STREAMS Option Group.
_XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS,
- #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// The implementation supports the XSI option
_XOPEN_UNIX = libc::_SC_XOPEN_UNIX,
- #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
- target_os = "ios", target_os="linux", target_os = "macos",
- target_os="openbsd"))]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
#[cfg_attr(docsrs, doc(cfg(all())))]
/// Integer value indicating version of the X/Open Portability Guide to
/// which the implementation conforms.
_XOPEN_VERSION = libc::_SC_XOPEN_VERSION,
/// The number of pages of physical memory. Note that it is possible for
/// the product of this value to overflow.
- #[cfg(any(target_os="android", target_os="linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
_PHYS_PAGES = libc::_SC_PHYS_PAGES,
/// The number of currently available pages of physical memory.
- #[cfg(any(target_os="android", target_os="linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
_AVPHYS_PAGES = libc::_SC_AVPHYS_PAGES,
/// The number of processors configured.
- #[cfg(any(target_os="android", target_os="linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
_NPROCESSORS_CONF = libc::_SC_NPROCESSORS_CONF,
/// The number of processors currently online (available).
- #[cfg(any(target_os="android", target_os="linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
_NPROCESSORS_ONLN = libc::_SC_NPROCESSORS_ONLN,
}
@@ -2739,28 +3201,29 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> {
}
}
-feature! {
-#![feature = "fs"]
-
#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(feature = "fs")]
mod pivot_root {
- use crate::{Result, NixPath};
use crate::errno::Errno;
+ use crate::{NixPath, Result};
pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
- new_root: &P1, put_old: &P2) -> Result<()> {
+ new_root: &P1,
+ put_old: &P2,
+ ) -> Result<()> {
let res = new_root.with_nix_path(|new_root| {
- put_old.with_nix_path(|put_old| {
- unsafe {
- libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr())
- }
+ put_old.with_nix_path(|put_old| unsafe {
+ libc::syscall(
+ libc::SYS_pivot_root,
+ new_root.as_ptr(),
+ put_old.as_ptr(),
+ )
})
})??;
Errno::result(res).map(drop)
}
}
-}
#[cfg(any(
target_os = "android",
@@ -2773,9 +3236,9 @@ mod setres {
feature! {
#![feature = "user"]
- use crate::Result;
+ use super::{Gid, Uid};
use crate::errno::Errno;
- use super::{Uid, Gid};
+ use crate::Result;
/// Sets the real, effective, and saved uid.
/// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html))
@@ -2788,7 +3251,8 @@ mod setres {
/// Err is returned if the user doesn't have permission to set this UID.
#[inline]
pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> {
- let res = unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) };
+ let res =
+ unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) };
Errno::result(res).map(drop)
}
@@ -2804,7 +3268,8 @@ mod setres {
/// Err is returned if the user doesn't have permission to set this GID.
#[inline]
pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> {
- let res = unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) };
+ let res =
+ unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) };
Errno::result(res).map(drop)
}
@@ -2822,16 +3287,16 @@ mod getres {
feature! {
#![feature = "user"]
- use crate::Result;
+ use super::{Gid, Uid};
use crate::errno::Errno;
- use super::{Uid, Gid};
+ use crate::Result;
/// Real, effective and saved user IDs.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ResUid {
pub real: Uid,
pub effective: Uid,
- pub saved: Uid
+ pub saved: Uid,
}
/// Real, effective and saved group IDs.
@@ -2839,7 +3304,7 @@ mod getres {
pub struct ResGid {
pub real: Gid,
pub effective: Gid,
- pub saved: Gid
+ pub saved: Gid,
}
/// Gets the real, effective, and saved user IDs.
@@ -2858,7 +3323,11 @@ mod getres {
let mut suid = libc::uid_t::max_value();
let res = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) };
- Errno::result(res).map(|_| ResUid{ real: Uid(ruid), effective: Uid(euid), saved: Uid(suid) })
+ Errno::result(res).map(|_| ResUid {
+ real: Uid(ruid),
+ effective: Uid(euid),
+ saved: Uid(suid),
+ })
}
/// Gets the real, effective, and saved group IDs.
@@ -2877,7 +3346,11 @@ mod getres {
let mut sgid = libc::gid_t::max_value();
let res = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) };
- Errno::result(res).map(|_| ResGid { real: Gid(rgid), effective: Gid(egid), saved: Gid(sgid) } )
+ Errno::result(res).map(|_| ResGid {
+ real: Gid(rgid),
+ effective: Gid(egid),
+ saved: Gid(sgid),
+ })
}
}
}
@@ -2904,10 +3377,8 @@ feature! {
/// Checks the file named by `path` for accessibility according to the flags given by `amode`
/// See [access(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html)
pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> {
- let res = path.with_nix_path(|cstr| {
- unsafe {
- libc::access(cstr.as_ptr(), amode.bits)
- }
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::access(cstr.as_ptr(), amode.bits())
})?;
Errno::result(res).map(drop)
}
@@ -2923,11 +3394,19 @@ pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> {
/// [faccessat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html)
// redox: does not appear to support the *at family of syscalls.
#[cfg(not(target_os = "redox"))]
-pub fn faccessat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: AccessFlags, flags: AtFlags) -> Result<()> {
- let res = path.with_nix_path(|cstr| {
- unsafe {
- libc::faccessat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits(), flags.bits())
- }
+pub fn faccessat<P: ?Sized + NixPath>(
+ dirfd: Option<RawFd>,
+ path: &P,
+ mode: AccessFlags,
+ flags: AtFlags,
+) -> Result<()> {
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::faccessat(
+ at_rawfd(dirfd),
+ cstr.as_ptr(),
+ mode.bits(),
+ flags.bits(),
+ )
})?;
Errno::result(res).map(drop)
}
@@ -2945,10 +3424,8 @@ pub fn faccessat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Acce
target_os = "dragonfly"
))]
pub fn eaccess<P: ?Sized + NixPath>(path: &P, mode: AccessFlags) -> Result<()> {
- let res = path.with_nix_path(|cstr| {
- unsafe {
- libc::eaccess(cstr.as_ptr(), mode.bits)
- }
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::eaccess(cstr.as_ptr(), mode.bits())
})?;
Errno::result(res).map(drop)
}
@@ -2982,32 +3459,41 @@ pub struct User {
/// Path to shell
pub shell: PathBuf,
/// Login class
- #[cfg(not(any(target_os = "android",
- target_os = "fuchsia",
- target_os = "haiku",
- target_os = "illumos",
- target_os = "linux",
- target_os = "solaris")))]
+ #[cfg(not(any(
+ target_os = "aix",
+ target_os = "android",
+ target_os = "fuchsia",
+ target_os = "haiku",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "solaris"
+ )))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub class: CString,
/// Last password change
- #[cfg(not(any(target_os = "android",
- target_os = "fuchsia",
- target_os = "haiku",
- target_os = "illumos",
- target_os = "linux",
- target_os = "solaris")))]
+ #[cfg(not(any(
+ target_os = "aix",
+ target_os = "android",
+ target_os = "fuchsia",
+ target_os = "haiku",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "solaris"
+ )))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub change: libc::time_t,
/// Expiration time of account
- #[cfg(not(any(target_os = "android",
- target_os = "fuchsia",
- target_os = "haiku",
- target_os = "illumos",
- target_os = "linux",
- target_os = "solaris")))]
+ #[cfg(not(any(
+ target_os = "aix",
+ target_os = "android",
+ target_os = "fuchsia",
+ target_os = "haiku",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "solaris"
+ )))]
#[cfg_attr(docsrs, doc(cfg(all())))]
- pub expire: libc::time_t
+ pub expire: libc::time_t,
}
#[cfg(not(target_os = "redox"))] //RedoxFS does not support passwd
@@ -3015,35 +3501,74 @@ impl From<&libc::passwd> for User {
fn from(pw: &libc::passwd) -> User {
unsafe {
User {
- name: if pw.pw_name.is_null() { Default::default() } else { CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned() },
- passwd: if pw.pw_passwd.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes()).unwrap() },
- #[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
- gecos: if pw.pw_gecos.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes()).unwrap() },
- dir: if pw.pw_dir.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_dir).to_bytes())) },
- shell: if pw.pw_shell.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_shell).to_bytes())) },
+ name: if pw.pw_name.is_null() {
+ Default::default()
+ } else {
+ CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned()
+ },
+ passwd: if pw.pw_passwd.is_null() {
+ Default::default()
+ } else {
+ CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes())
+ .unwrap()
+ },
+ #[cfg(not(all(
+ target_os = "android",
+ target_pointer_width = "32"
+ )))]
+ gecos: if pw.pw_gecos.is_null() {
+ Default::default()
+ } else {
+ CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes())
+ .unwrap()
+ },
+ dir: if pw.pw_dir.is_null() {
+ Default::default()
+ } else {
+ PathBuf::from(OsStr::from_bytes(
+ CStr::from_ptr(pw.pw_dir).to_bytes(),
+ ))
+ },
+ shell: if pw.pw_shell.is_null() {
+ Default::default()
+ } else {
+ PathBuf::from(OsStr::from_bytes(
+ CStr::from_ptr(pw.pw_shell).to_bytes(),
+ ))
+ },
uid: Uid::from_raw(pw.pw_uid),
gid: Gid::from_raw(pw.pw_gid),
- #[cfg(not(any(target_os = "android",
- target_os = "fuchsia",
- target_os = "haiku",
- target_os = "illumos",
- target_os = "linux",
- target_os = "solaris")))]
- class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes()).unwrap(),
- #[cfg(not(any(target_os = "android",
- target_os = "fuchsia",
- target_os = "haiku",
- target_os = "illumos",
- target_os = "linux",
- target_os = "solaris")))]
+ #[cfg(not(any(
+ target_os = "aix",
+ target_os = "android",
+ target_os = "fuchsia",
+ target_os = "haiku",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "solaris"
+ )))]
+ class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes())
+ .unwrap(),
+ #[cfg(not(any(
+ target_os = "aix",
+ target_os = "android",
+ target_os = "fuchsia",
+ target_os = "haiku",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "solaris"
+ )))]
change: pw.pw_change,
- #[cfg(not(any(target_os = "android",
- target_os = "fuchsia",
- target_os = "haiku",
- target_os = "illumos",
- target_os = "linux",
- target_os = "solaris")))]
- expire: pw.pw_expire
+ #[cfg(not(any(
+ target_os = "aix",
+ target_os = "android",
+ target_os = "fuchsia",
+ target_os = "haiku",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "solaris"
+ )))]
+ expire: pw.pw_expire,
}
}
}
@@ -3067,32 +3592,44 @@ impl From<User> for libc::passwd {
Self {
pw_name: name,
pw_passwd: u.passwd.into_raw(),
- #[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
+ #[cfg(not(all(
+ target_os = "android",
+ target_pointer_width = "32"
+ )))]
pw_gecos: u.gecos.into_raw(),
pw_dir: dir,
pw_shell: shell,
pw_uid: u.uid.0,
pw_gid: u.gid.0,
- #[cfg(not(any(target_os = "android",
- target_os = "fuchsia",
- target_os = "haiku",
- target_os = "illumos",
- target_os = "linux",
- target_os = "solaris")))]
+ #[cfg(not(any(
+ target_os = "aix",
+ target_os = "android",
+ target_os = "fuchsia",
+ target_os = "haiku",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "solaris"
+ )))]
pw_class: u.class.into_raw(),
- #[cfg(not(any(target_os = "android",
- target_os = "fuchsia",
- target_os = "haiku",
- target_os = "illumos",
- target_os = "linux",
- target_os = "solaris")))]
+ #[cfg(not(any(
+ target_os = "aix",
+ target_os = "android",
+ target_os = "fuchsia",
+ target_os = "haiku",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "solaris"
+ )))]
pw_change: u.change,
- #[cfg(not(any(target_os = "android",
- target_os = "fuchsia",
- target_os = "haiku",
- target_os = "illumos",
- target_os = "linux",
- target_os = "solaris")))]
+ #[cfg(not(any(
+ target_os = "aix",
+ target_os = "android",
+ target_os = "fuchsia",
+ target_os = "haiku",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "solaris"
+ )))]
pw_expire: u.expire,
#[cfg(target_os = "illumos")]
pw_age: CString::new("").unwrap().into_raw(),
@@ -3106,12 +3643,19 @@ impl From<User> for libc::passwd {
#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
impl User {
- fn from_anything<F>(f: F) -> Result<Option<Self>>
+ /// # Safety
+ ///
+ /// If `f` writes to its `*mut *mut libc::passwd` parameter, then it must
+ /// also initialize the value pointed to by its `*mut libc::group`
+ /// parameter.
+ unsafe fn from_anything<F>(f: F) -> Result<Option<Self>>
where
- F: Fn(*mut libc::passwd,
- *mut c_char,
- libc::size_t,
- *mut *mut libc::passwd) -> libc::c_int
+ F: Fn(
+ *mut libc::passwd,
+ *mut c_char,
+ libc::size_t,
+ *mut *mut libc::passwd,
+ ) -> libc::c_int,
{
let buflimit = 1048576;
let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) {
@@ -3124,12 +3668,19 @@ impl User {
let mut res = ptr::null_mut();
loop {
- let error = f(pwd.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res);
+ let error = f(
+ pwd.as_mut_ptr(),
+ cbuf.as_mut_ptr(),
+ cbuf.capacity(),
+ &mut res,
+ );
if error == 0 {
if res.is_null() {
return Ok(None);
} else {
- let pwd = unsafe { pwd.assume_init() };
+ // SAFETY: `f` guarantees that `pwd` is initialized if `res`
+ // is not null.
+ let pwd = pwd.assume_init();
return Ok(Some(User::from(&pwd)));
}
} else if Errno::last() == Errno::ERANGE {
@@ -3155,15 +3706,19 @@ impl User {
/// assert_eq!(res.name, "root");
/// ```
pub fn from_uid(uid: Uid) -> Result<Option<Self>> {
- User::from_anything(|pwd, cbuf, cap, res| {
- unsafe { libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) }
- })
+ // SAFETY: `getpwuid_r` will write to `res` if it initializes the value
+ // at `pwd`.
+ unsafe {
+ User::from_anything(|pwd, cbuf, cap, res| {
+ libc::getpwuid_r(uid.0, pwd, cbuf, cap, res)
+ })
+ }
}
/// Get a user by name.
///
/// Internally, this function calls
- /// [getpwnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
+ /// [getpwnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwnam_r.html)
///
/// # Examples
///
@@ -3178,9 +3733,13 @@ impl User {
Ok(c_str) => c_str,
Err(_nul_error) => return Ok(None),
};
- User::from_anything(|pwd, cbuf, cap, res| {
- unsafe { libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) }
- })
+ // SAFETY: `getpwnam_r` will write to `res` if it initializes the value
+ // at `pwd`.
+ unsafe {
+ User::from_anything(|pwd, cbuf, cap, res| {
+ libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res)
+ })
+ }
}
}
@@ -3195,7 +3754,7 @@ pub struct Group {
/// Group ID
pub gid: Gid,
/// List of Group members
- pub mem: Vec<String>
+ pub mem: Vec<String>,
}
#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
@@ -3203,10 +3762,23 @@ impl From<&libc::group> for Group {
fn from(gr: &libc::group) -> Group {
unsafe {
Group {
- name: CStr::from_ptr(gr.gr_name).to_string_lossy().into_owned(),
- passwd: CString::new(CStr::from_ptr(gr.gr_passwd).to_bytes()).unwrap(),
+ name: if gr.gr_name.is_null() {
+ Default::default()
+ } else {
+ CStr::from_ptr(gr.gr_name).to_string_lossy().into_owned()
+ },
+ passwd: if gr.gr_passwd.is_null() {
+ Default::default()
+ } else {
+ CString::new(CStr::from_ptr(gr.gr_passwd).to_bytes())
+ .unwrap()
+ },
gid: Gid::from_raw(gr.gr_gid),
- mem: Group::members(gr.gr_mem)
+ mem: if gr.gr_mem.is_null() {
+ Default::default()
+ } else {
+ Group::members(gr.gr_mem)
+ },
}
}
}
@@ -3230,12 +3802,19 @@ impl Group {
ret
}
- fn from_anything<F>(f: F) -> Result<Option<Self>>
+ /// # Safety
+ ///
+ /// If `f` writes to its `*mut *mut libc::group` parameter, then it must
+ /// also initialize the value pointed to by its `*mut libc::group`
+ /// parameter.
+ unsafe fn from_anything<F>(f: F) -> Result<Option<Self>>
where
- F: Fn(*mut libc::group,
- *mut c_char,
- libc::size_t,
- *mut *mut libc::group) -> libc::c_int
+ F: Fn(
+ *mut libc::group,
+ *mut c_char,
+ libc::size_t,
+ *mut *mut libc::group,
+ ) -> libc::c_int,
{
let buflimit = 1048576;
let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) {
@@ -3248,12 +3827,19 @@ impl Group {
let mut res = ptr::null_mut();
loop {
- let error = f(grp.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res);
+ let error = f(
+ grp.as_mut_ptr(),
+ cbuf.as_mut_ptr(),
+ cbuf.capacity(),
+ &mut res,
+ );
if error == 0 {
if res.is_null() {
return Ok(None);
} else {
- let grp = unsafe { grp.assume_init() };
+ // SAFETY: `f` guarantees that `grp` is initialized if `res`
+ // is not null.
+ let grp = grp.assume_init();
return Ok(Some(Group::from(&grp)));
}
} else if Errno::last() == Errno::ERANGE {
@@ -3281,9 +3867,13 @@ impl Group {
/// assert!(res.name == "root");
/// ```
pub fn from_gid(gid: Gid) -> Result<Option<Self>> {
- Group::from_anything(|grp, cbuf, cap, res| {
- unsafe { libc::getgrgid_r(gid.0, grp, cbuf, cap, res) }
- })
+ // SAFETY: `getgrgid_r` will write to `res` if it initializes the value
+ // at `grp`.
+ unsafe {
+ Group::from_anything(|grp, cbuf, cap, res| {
+ libc::getgrgid_r(gid.0, grp, cbuf, cap, res)
+ })
+ }
}
/// Get a group by name.
@@ -3306,9 +3896,13 @@ impl Group {
Ok(c_str) => c_str,
Err(_nul_error) => return Ok(None),
};
- Group::from_anything(|grp, cbuf, cap, res| {
- unsafe { libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) }
- })
+ // SAFETY: `getgrnam_r` will write to `res` if it initializes the value
+ // at `grp`.
+ unsafe {
+ Group::from_anything(|grp, cbuf, cap, res| {
+ libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res)
+ })
+ }
}
}
}
diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs
index 84086f8..5035b5a 100644
--- a/test/sys/test_aio.rs
+++ b/test/sys/test_aio.rs
@@ -21,9 +21,7 @@ use nix::{
};
use tempfile::tempfile;
-lazy_static! {
- pub static ref SIGNALED: AtomicBool = AtomicBool::new(false);
-}
+pub static SIGNALED: AtomicBool = AtomicBool::new(false);
extern "C" fn sigfunc(_: c_int) {
SIGNALED.store(true, Ordering::Relaxed);
@@ -200,7 +198,7 @@ mod aio_read {
assert_eq!(err, Ok(()));
assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len());
}
- assert_eq!(EXPECT, rbuf.deref().deref());
+ assert_eq!(EXPECT, rbuf.deref());
}
// Like ok, but allocates the structure on the stack.
@@ -223,7 +221,7 @@ mod aio_read {
assert_eq!(err, Ok(()));
assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len());
}
- assert_eq!(EXPECT, rbuf.deref().deref());
+ assert_eq!(EXPECT, rbuf.deref());
}
}
@@ -610,7 +608,7 @@ fn test_aio_suspend() {
let r = aio_suspend(&cbbuf[..], Some(timeout));
match r {
Err(Errno::EINTR) => continue,
- Err(e) => panic!("aio_suspend returned {:?}", e),
+ Err(e) => panic!("aio_suspend returned {e:?}"),
Ok(_) => (),
};
}
diff --git a/test/sys/test_epoll.rs b/test/sys/test_epoll.rs
index 9156915..84b100c 100644
--- a/test/sys/test_epoll.rs
+++ b/test/sys/test_epoll.rs
@@ -1,3 +1,5 @@
+#![allow(deprecated)]
+
use nix::errno::Errno;
use nix::sys::epoll::{epoll_create1, epoll_ctl};
use nix::sys::epoll::{EpollCreateFlags, EpollEvent, EpollFlags, EpollOp};
diff --git a/test/sys/test_mman.rs b/test/sys/test_mman.rs
index e748427..b4674e5 100644
--- a/test/sys/test_mman.rs
+++ b/test/sys/test_mman.rs
@@ -1,15 +1,15 @@
use nix::sys::mman::{mmap, MapFlags, ProtFlags};
-use std::num::NonZeroUsize;
+use std::{num::NonZeroUsize, os::unix::io::BorrowedFd};
#[test]
fn test_mmap_anonymous() {
unsafe {
- let ptr = mmap(
+ let ptr = mmap::<BorrowedFd>(
None,
NonZeroUsize::new(1).unwrap(),
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
- -1,
+ None,
0,
)
.unwrap() as *mut u8;
@@ -29,12 +29,12 @@ fn test_mremap_grow() {
let one_k_non_zero = NonZeroUsize::new(ONE_K).unwrap();
let slice: &mut [u8] = unsafe {
- let mem = mmap(
+ let mem = mmap::<BorrowedFd>(
None,
one_k_non_zero,
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE,
- -1,
+ None,
0,
)
.unwrap();
@@ -87,12 +87,12 @@ fn test_mremap_shrink() {
const ONE_K: size_t = 1024;
let ten_one_k = NonZeroUsize::new(10 * ONE_K).unwrap();
let slice: &mut [u8] = unsafe {
- let mem = mmap(
+ let mem = mmap::<BorrowedFd>(
None,
ten_one_k,
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE,
- -1,
+ None,
0,
)
.unwrap();
diff --git a/test/sys/test_prctl.rs b/test/sys/test_prctl.rs
new file mode 100644
index 0000000..351213b
--- /dev/null
+++ b/test/sys/test_prctl.rs
@@ -0,0 +1,125 @@
+#[cfg(target_os = "linux")]
+#[cfg(feature = "process")]
+mod test_prctl {
+ use std::ffi::CStr;
+
+ use nix::sys::prctl;
+
+ #[cfg_attr(qemu, ignore)]
+ #[test]
+ fn test_get_set_subreaper() {
+ let original = prctl::get_child_subreaper().unwrap();
+
+ prctl::set_child_subreaper(true).unwrap();
+ let subreaper = prctl::get_child_subreaper().unwrap();
+ assert!(subreaper);
+
+ prctl::set_child_subreaper(original).unwrap();
+ }
+
+ #[test]
+ fn test_get_set_dumpable() {
+ let original = prctl::get_dumpable().unwrap();
+
+ prctl::set_dumpable(false).unwrap();
+ let dumpable = prctl::get_dumpable().unwrap();
+ assert!(!dumpable);
+
+ prctl::set_dumpable(original).unwrap();
+ }
+
+ #[test]
+ fn test_get_set_keepcaps() {
+ let original = prctl::get_keepcaps().unwrap();
+
+ prctl::set_keepcaps(true).unwrap();
+ let keepcaps = prctl::get_keepcaps().unwrap();
+ assert!(keepcaps);
+
+ prctl::set_keepcaps(original).unwrap();
+ }
+
+ #[test]
+ fn test_get_set_clear_mce_kill() {
+ use prctl::PrctlMCEKillPolicy::*;
+
+ prctl::set_mce_kill(PR_MCE_KILL_LATE).unwrap();
+ let mce = prctl::get_mce_kill().unwrap();
+ assert_eq!(mce, PR_MCE_KILL_LATE);
+
+ prctl::clear_mce_kill().unwrap();
+ let mce = prctl::get_mce_kill().unwrap();
+ assert_eq!(mce, PR_MCE_KILL_DEFAULT);
+ }
+
+ #[cfg_attr(qemu, ignore)]
+ #[test]
+ fn test_get_set_pdeathsig() {
+ use nix::sys::signal::Signal;
+
+ let original = prctl::get_pdeathsig().unwrap();
+
+ prctl::set_pdeathsig(Signal::SIGUSR1).unwrap();
+ let sig = prctl::get_pdeathsig().unwrap();
+ assert_eq!(sig, Some(Signal::SIGUSR1));
+
+ prctl::set_pdeathsig(original).unwrap();
+ }
+
+ #[test]
+ fn test_get_set_name() {
+ let original = prctl::get_name().unwrap();
+
+ let long_name =
+ CStr::from_bytes_with_nul(b"0123456789abcdefghijklmn\0").unwrap();
+ prctl::set_name(long_name).unwrap();
+ let res = prctl::get_name().unwrap();
+
+ // name truncated by kernel to TASK_COMM_LEN
+ assert_eq!(&long_name.to_str().unwrap()[..15], res.to_str().unwrap());
+
+ let short_name = CStr::from_bytes_with_nul(b"01234567\0").unwrap();
+ prctl::set_name(short_name).unwrap();
+ let res = prctl::get_name().unwrap();
+ assert_eq!(short_name.to_str().unwrap(), res.to_str().unwrap());
+
+ prctl::set_name(&original).unwrap();
+ }
+
+ #[cfg_attr(qemu, ignore)]
+ #[test]
+ fn test_get_set_timerslack() {
+ let original = prctl::get_timerslack().unwrap();
+
+ let slack = 60_000;
+ prctl::set_timerslack(slack).unwrap();
+ let res = prctl::get_timerslack().unwrap();
+ assert_eq!(slack, res as u64);
+
+ prctl::set_timerslack(original as u64).unwrap();
+ }
+
+ #[test]
+ fn test_disable_enable_perf_events() {
+ prctl::task_perf_events_disable().unwrap();
+ prctl::task_perf_events_enable().unwrap();
+ }
+
+ #[test]
+ fn test_get_set_no_new_privs() {
+ prctl::set_no_new_privs().unwrap();
+ let no_new_privs = prctl::get_no_new_privs().unwrap();
+ assert!(no_new_privs);
+ }
+
+ #[test]
+ fn test_get_set_thp_disable() {
+ let original = prctl::get_thp_disable().unwrap();
+
+ prctl::set_thp_disable(true).unwrap();
+ let thp_disable = prctl::get_thp_disable().unwrap();
+ assert!(thp_disable);
+
+ prctl::set_thp_disable(original).unwrap();
+ }
+}
diff --git a/test/sys/test_select.rs b/test/sys/test_select.rs
index 40bda4d..79f75de 100644
--- a/test/sys/test_select.rs
+++ b/test/sys/test_select.rs
@@ -2,6 +2,7 @@ use nix::sys::select::*;
use nix::sys::signal::SigSet;
use nix::sys::time::{TimeSpec, TimeValLike};
use nix::unistd::{pipe, write};
+use std::os::unix::io::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd};
#[test]
pub fn test_pselect() {
@@ -9,11 +10,13 @@ pub fn test_pselect() {
let (r1, w1) = pipe().unwrap();
write(w1, b"hi!").unwrap();
+ let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
let (r2, _w2) = pipe().unwrap();
+ let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
let mut fd_set = FdSet::new();
- fd_set.insert(r1);
- fd_set.insert(r2);
+ fd_set.insert(&r1);
+ fd_set.insert(&r2);
let timeout = TimeSpec::seconds(10);
let sigmask = SigSet::empty();
@@ -21,25 +24,27 @@ pub fn test_pselect() {
1,
pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap()
);
- assert!(fd_set.contains(r1));
- assert!(!fd_set.contains(r2));
+ assert!(fd_set.contains(&r1));
+ assert!(!fd_set.contains(&r2));
}
#[test]
pub fn test_pselect_nfds2() {
let (r1, w1) = pipe().unwrap();
write(w1, b"hi!").unwrap();
+ let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
let (r2, _w2) = pipe().unwrap();
+ let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
let mut fd_set = FdSet::new();
- fd_set.insert(r1);
- fd_set.insert(r2);
+ fd_set.insert(&r1);
+ fd_set.insert(&r2);
let timeout = TimeSpec::seconds(10);
assert_eq!(
1,
pselect(
- ::std::cmp::max(r1, r2) + 1,
+ std::cmp::max(r1.as_raw_fd(), r2.as_raw_fd()) + 1,
&mut fd_set,
None,
None,
@@ -48,8 +53,8 @@ pub fn test_pselect_nfds2() {
)
.unwrap()
);
- assert!(fd_set.contains(r1));
- assert!(!fd_set.contains(r2));
+ assert!(fd_set.contains(&r1));
+ assert!(!fd_set.contains(&r2));
}
macro_rules! generate_fdset_bad_fd_tests {
@@ -58,17 +63,13 @@ macro_rules! generate_fdset_bad_fd_tests {
#[test]
#[should_panic]
fn $method() {
- FdSet::new().$method($fd);
+ let bad_fd = unsafe{BorrowedFd::borrow_raw($fd)};
+ FdSet::new().$method(&bad_fd);
}
)*
}
}
-mod test_fdset_negative_fd {
- use super::*;
- generate_fdset_bad_fd_tests!(-1, insert, remove, contains);
-}
-
mod test_fdset_too_large_fd {
use super::*;
use std::convert::TryInto;
diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs
index 3ad14f4..ca25ff9 100644
--- a/test/sys/test_signal.rs
+++ b/test/sys/test_signal.rs
@@ -54,9 +54,8 @@ fn test_sigprocmask() {
// test don't make sense.
assert!(
!old_signal_set.contains(SIGNAL),
- "the {:?} signal is already blocked, please change to a \
- different one",
- SIGNAL
+ "the {SIGNAL:?} signal is already blocked, please change to a \
+ different one"
);
// Now block the signal.
@@ -71,8 +70,7 @@ fn test_sigprocmask() {
.expect("expect to be able to retrieve old signals");
assert!(
old_signal_set.contains(SIGNAL),
- "expected the {:?} to be blocked",
- SIGNAL
+ "expected the {SIGNAL:?} to be blocked"
);
// Reset the signal.
@@ -80,9 +78,7 @@ fn test_sigprocmask() {
.expect("expect to be able to block signals");
}
-lazy_static! {
- static ref SIGNALED: AtomicBool = AtomicBool::new(false);
-}
+static SIGNALED: AtomicBool = AtomicBool::new(false);
extern "C" fn test_sigaction_handler(signal: libc::c_int) {
let signal = Signal::try_from(signal).unwrap();
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs
index 5adc77e..ed1686e 100644
--- a/test/sys/test_socket.rs
+++ b/test/sys/test_socket.rs
@@ -1,74 +1,16 @@
#[cfg(any(target_os = "linux", target_os = "android"))]
use crate::*;
-use libc::{c_char, sockaddr_storage};
-#[allow(deprecated)]
-use nix::sys::socket::InetAddr;
-use nix::sys::socket::{
- getsockname, sockaddr, sockaddr_in6, AddressFamily, UnixAddr,
-};
+use libc::c_char;
+use nix::sys::socket::{getsockname, AddressFamily, UnixAddr};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
-use std::mem::{self, MaybeUninit};
-use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
-use std::os::unix::io::RawFd;
+use std::net::{SocketAddrV4, SocketAddrV6};
+use std::os::unix::io::{AsRawFd, RawFd};
use std::path::Path;
use std::slice;
use std::str::FromStr;
-#[allow(deprecated)]
-#[test]
-pub fn test_inetv4_addr_to_sock_addr() {
- let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap();
- let addr = InetAddr::from_std(&actual);
-
- match addr {
- InetAddr::V4(addr) => {
- let ip: u32 = 0x7f00_0001;
- let port: u16 = 3000;
- let saddr = addr.sin_addr.s_addr;
-
- assert_eq!(saddr, ip.to_be());
- assert_eq!(addr.sin_port, port.to_be());
- }
- _ => panic!("nope"),
- }
-
- assert_eq!(addr.to_string(), "127.0.0.1:3000");
-
- let inet = addr.to_std();
- assert_eq!(actual, inet);
-}
-
-#[allow(deprecated)]
-#[test]
-pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() {
- use nix::sys::socket::{sockaddr_storage_to_addr, SockAddr};
-
- let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap();
- let addr = InetAddr::from_std(&actual);
- let sockaddr = SockAddr::new_inet(addr);
-
- let (storage, ffi_size) = {
- let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
- let storage_ptr = storage.as_mut_ptr().cast::<sockaddr>();
- let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair();
- assert_eq!(mem::size_of::<sockaddr>(), ffi_size as usize);
- unsafe {
- storage_ptr.copy_from_nonoverlapping(ffi_ptr as *const sockaddr, 1);
- (storage.assume_init(), ffi_size)
- }
- };
-
- let from_storage =
- sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap();
- assert_eq!(from_storage, sockaddr);
- let from_storage =
- sockaddr_storage_to_addr(&storage, mem::size_of::<sockaddr_storage>())
- .unwrap();
- assert_eq!(from_storage, sockaddr);
-}
-
-#[cfg(any(target_os = "linux"))]
+#[cfg(target_os = "linux")]
#[cfg_attr(qemu, ignore)]
#[test]
pub fn test_timestamping() {
@@ -96,9 +38,9 @@ pub fn test_timestamping() {
None,
)
.unwrap();
- nix::sys::socket::bind(rsock, &sock_addr).unwrap();
+ nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap();
- setsockopt(rsock, Timestamping, &TimestampingFlag::all()).unwrap();
+ setsockopt(&rsock, Timestamping, &TimestampingFlag::all()).unwrap();
let sbuf = [0u8; 2048];
let mut rbuf = [0u8; 2048];
@@ -107,8 +49,10 @@ pub fn test_timestamping() {
let mut iov2 = [IoSliceMut::new(&mut rbuf)];
let mut cmsg = cmsg_space!(nix::sys::socket::Timestamps);
- sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap();
- let recv = recvmsg::<()>(rsock, &mut iov2, Some(&mut cmsg), flags).unwrap();
+ sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
+ let recv =
+ recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags)
+ .unwrap();
let mut ts = None;
for c in recv.cmsgs() {
@@ -128,44 +72,6 @@ pub fn test_timestamping() {
assert!(std::time::Duration::from(diff).as_secs() < 60);
}
-#[allow(deprecated)]
-#[test]
-pub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr() {
- use nix::sys::socket::{sockaddr_storage_to_addr, SockAddr};
-
- let port: u16 = 3000;
- let flowinfo: u32 = 1;
- let scope_id: u32 = 2;
- let ip: Ipv6Addr = "fe80::1".parse().unwrap();
-
- let actual =
- SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id));
- let addr = InetAddr::from_std(&actual);
- let sockaddr = SockAddr::new_inet(addr);
-
- let (storage, ffi_size) = {
- let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
- let storage_ptr = storage.as_mut_ptr().cast::<sockaddr_in6>();
- let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair();
- assert_eq!(mem::size_of::<sockaddr_in6>(), ffi_size as usize);
- unsafe {
- storage_ptr.copy_from_nonoverlapping(
- (ffi_ptr as *const sockaddr).cast::<sockaddr_in6>(),
- 1,
- );
- (storage.assume_init(), ffi_size)
- }
- };
-
- let from_storage =
- sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap();
- assert_eq!(from_storage, sockaddr);
- let from_storage =
- sockaddr_storage_to_addr(&storage, mem::size_of::<sockaddr_storage>())
- .unwrap();
- assert_eq!(from_storage, sockaddr);
-}
-
#[test]
pub fn test_path_to_sock_addr() {
let path = "/foo/bar";
@@ -275,8 +181,11 @@ pub fn test_getsockname() {
)
.expect("socket failed");
let sockaddr = UnixAddr::new(&sockname).unwrap();
- bind(sock, &sockaddr).expect("bind failed");
- assert_eq!(sockaddr, getsockname(sock).expect("getsockname failed"));
+ bind(sock.as_raw_fd(), &sockaddr).expect("bind failed");
+ assert_eq!(
+ sockaddr,
+ getsockname(sock.as_raw_fd()).expect("getsockname failed")
+ );
}
#[test]
@@ -291,14 +200,54 @@ pub fn test_socketpair() {
SockFlag::empty(),
)
.unwrap();
- write(fd1, b"hello").unwrap();
+ write(fd1.as_raw_fd(), b"hello").unwrap();
let mut buf = [0; 5];
- read(fd2, &mut buf).unwrap();
+ read(fd2.as_raw_fd(), &mut buf).unwrap();
assert_eq!(&buf[..], b"hello");
}
#[test]
+pub fn test_recvmsg_sockaddr_un() {
+ use nix::sys::socket::{
+ self, bind, socket, AddressFamily, MsgFlags, SockFlag, SockType,
+ };
+
+ let tempdir = tempfile::tempdir().unwrap();
+ let sockname = tempdir.path().join("sock");
+ let sock = socket(
+ AddressFamily::Unix,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .expect("socket failed");
+ let sockaddr = UnixAddr::new(&sockname).unwrap();
+ bind(sock.as_raw_fd(), &sockaddr).expect("bind failed");
+
+ // Send a message
+ let send_buffer = "hello".as_bytes();
+ if let Err(e) = socket::sendmsg(
+ sock.as_raw_fd(),
+ &[std::io::IoSlice::new(send_buffer)],
+ &[],
+ MsgFlags::empty(),
+ Some(&sockaddr),
+ ) {
+ crate::skip!("Couldn't send ({e:?}), so skipping test");
+ }
+
+ // Receive the message
+ let mut recv_buffer = [0u8; 32];
+ let mut iov = [std::io::IoSliceMut::new(&mut recv_buffer)];
+ let received =
+ socket::recvmsg(sock.as_raw_fd(), &mut iov, None, MsgFlags::empty())
+ .unwrap();
+ // Check the address in the received message
+ assert_eq!(sockaddr, received.address.unwrap());
+}
+
+#[test]
pub fn test_std_conversions() {
use nix::sys::socket::*;
@@ -361,7 +310,7 @@ mod recvfrom {
)
.unwrap();
// Ignore from for stream sockets
- let _ = sendrecv(fd1, fd2, send, |_, _| {});
+ let _ = sendrecv(fd1.as_raw_fd(), fd2.as_raw_fd(), send, |_, _| {});
}
#[test]
@@ -375,7 +324,7 @@ mod recvfrom {
None,
)
.unwrap();
- bind(rsock, &sock_addr).unwrap();
+ bind(rsock.as_raw_fd(), &sock_addr).unwrap();
let ssock = socket(
AddressFamily::Inet,
SockType::Datagram,
@@ -384,9 +333,9 @@ mod recvfrom {
)
.expect("send socket failed");
let from = sendrecv(
- rsock,
- ssock,
- move |s, m, flags| sendto(s, m, &sock_addr, flags),
+ rsock.as_raw_fd(),
+ ssock.as_raw_fd(),
+ move |s, m, flags| sendto(s.as_raw_fd(), m, &sock_addr, flags),
|_, _| {},
);
// UDP sockets should set the from address
@@ -420,10 +369,10 @@ mod recvfrom {
)
.unwrap();
- setsockopt(rsock, UdpGsoSegment, &(segment_size as _))
+ setsockopt(&rsock, UdpGsoSegment, &(segment_size as _))
.expect("setsockopt UDP_SEGMENT failed");
- bind(rsock, &sock_addr).unwrap();
+ bind(rsock.as_raw_fd(), &sock_addr).unwrap();
let ssock = socket(
AddressFamily::Inet,
SockType::Datagram,
@@ -435,12 +384,18 @@ mod recvfrom {
let mut num_packets_received: i32 = 0;
sendrecv(
- rsock,
- ssock,
+ rsock.as_raw_fd(),
+ ssock.as_raw_fd(),
move |s, m, flags| {
let iov = [IoSlice::new(m)];
let cmsg = ControlMessage::UdpGsoSegments(&segment_size);
- sendmsg(s, &iov, &[cmsg], flags, Some(&sock_addr))
+ sendmsg(
+ s.as_raw_fd(),
+ &iov,
+ &[cmsg],
+ flags,
+ Some(&sock_addr),
+ )
},
{
let num_packets_received_ref = &mut num_packets_received;
@@ -477,7 +432,7 @@ mod recvfrom {
)
.unwrap();
- setsockopt(rsock, UdpGroSegment, &true)
+ setsockopt(&rsock, UdpGroSegment, &true)
.expect("setsockopt UDP_GRO failed");
}
}
@@ -504,7 +459,7 @@ mod recvfrom {
None,
)
.unwrap();
- bind(rsock, &sock_addr).unwrap();
+ bind(rsock.as_raw_fd(), &sock_addr).unwrap();
let ssock = socket(
AddressFamily::Inet,
SockType::Datagram,
@@ -514,8 +469,8 @@ mod recvfrom {
.expect("send socket failed");
let from = sendrecv(
- rsock,
- ssock,
+ rsock.as_raw_fd(),
+ ssock.as_raw_fd(),
move |s, m, flags| {
let batch_size = 15;
let mut iovs = Vec::with_capacity(1 + batch_size);
@@ -573,7 +528,7 @@ mod recvfrom {
None,
)
.unwrap();
- bind(rsock, &sock_addr).unwrap();
+ bind(rsock.as_raw_fd(), &sock_addr).unwrap();
let ssock = socket(
AddressFamily::Inet,
SockType::Datagram,
@@ -584,8 +539,13 @@ mod recvfrom {
let send_thread = thread::spawn(move || {
for _ in 0..NUM_MESSAGES_SENT {
- sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty())
- .unwrap();
+ sendto(
+ ssock.as_raw_fd(),
+ &DATA[..],
+ &sock_addr,
+ MsgFlags::empty(),
+ )
+ .unwrap();
}
});
@@ -602,10 +562,15 @@ mod recvfrom {
let mut data =
MultiHeaders::<SockaddrIn>::preallocate(msgs.len(), None);
- let res: Vec<RecvMsg<SockaddrIn>> =
- recvmmsg(rsock, &mut data, msgs.iter(), MsgFlags::empty(), None)
- .expect("recvmmsg")
- .collect();
+ let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
+ rsock.as_raw_fd(),
+ &mut data,
+ msgs.iter(),
+ MsgFlags::empty(),
+ None,
+ )
+ .expect("recvmmsg")
+ .collect();
assert_eq!(res.len(), DATA.len());
for RecvMsg { address, bytes, .. } in res.into_iter() {
@@ -644,7 +609,7 @@ mod recvfrom {
None,
)
.unwrap();
- bind(rsock, &sock_addr).unwrap();
+ bind(rsock.as_raw_fd(), &sock_addr).unwrap();
let ssock = socket(
AddressFamily::Inet,
SockType::Datagram,
@@ -655,8 +620,13 @@ mod recvfrom {
let send_thread = thread::spawn(move || {
for _ in 0..NUM_MESSAGES_SENT {
- sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty())
- .unwrap();
+ sendto(
+ ssock.as_raw_fd(),
+ &DATA[..],
+ &sock_addr,
+ MsgFlags::empty(),
+ )
+ .unwrap();
}
});
// Ensure we've sent all the messages before continuing so `recvmmsg`
@@ -681,7 +651,7 @@ mod recvfrom {
);
let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
- rsock,
+ rsock.as_raw_fd(),
&mut data,
msgs.iter(),
MsgFlags::MSG_DONTWAIT,
@@ -717,12 +687,12 @@ mod recvfrom {
None,
)
.expect("receive socket failed");
- match bind(rsock, &raddr) {
+ match bind(rsock.as_raw_fd(), &raddr) {
Err(Errno::EADDRNOTAVAIL) => {
println!("IPv6 not available, skipping test.");
return;
}
- Err(e) => panic!("bind: {}", e),
+ Err(e) => panic!("bind: {e}"),
Ok(()) => (),
}
let ssock = socket(
@@ -732,11 +702,11 @@ mod recvfrom {
None,
)
.expect("send socket failed");
- bind(ssock, &saddr).unwrap();
+ bind(ssock.as_raw_fd(), &saddr).unwrap();
let from = sendrecv(
- rsock,
- ssock,
- move |s, m, flags| sendto(s, m, &raddr, flags),
+ rsock.as_raw_fd(),
+ ssock.as_raw_fd(),
+ move |s, m, flags| sendto(s.as_raw_fd(), m, &raddr, flags),
|_, _| {},
);
assert_eq!(AddressFamily::Inet6, from.unwrap().family().unwrap());
@@ -758,7 +728,7 @@ pub fn test_recvmsg_ebadf() {
let mut iov = [IoSliceMut::new(&mut buf[..])];
let fd = -1; // Bad file descriptor
- let r = recvmsg::<()>(fd, &mut iov, None, MsgFlags::empty());
+ let r = recvmsg::<()>(fd.as_raw_fd(), &mut iov, None, MsgFlags::empty());
assert_eq!(r.err().unwrap(), Errno::EBADF);
}
@@ -790,11 +760,17 @@ pub fn test_scm_rights() {
let fds = [r];
let cmsg = ControlMessage::ScmRights(&fds);
assert_eq!(
- sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(),
+ sendmsg::<()>(
+ fd1.as_raw_fd(),
+ &iov,
+ &[cmsg],
+ MsgFlags::empty(),
+ None
+ )
+ .unwrap(),
5
);
close(r).unwrap();
- close(fd1).unwrap();
}
{
@@ -803,7 +779,7 @@ pub fn test_scm_rights() {
let mut iov = [IoSliceMut::new(&mut buf[..])];
let mut cmsgspace = cmsg_space!([RawFd; 1]);
let msg = recvmsg::<()>(
- fd2,
+ fd2.as_raw_fd(),
&mut iov,
Some(&mut cmsgspace),
MsgFlags::empty(),
@@ -823,14 +799,13 @@ pub fn test_scm_rights() {
assert!(!msg
.flags
.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
- close(fd2).unwrap();
}
let received_r = received_r.expect("Did not receive passed fd");
// Ensure that the received file descriptor works
- write(w, b"world").unwrap();
+ write(w.as_raw_fd(), b"world").unwrap();
let mut buf = [0u8; 5];
- read(received_r, &mut buf).unwrap();
+ read(received_r.as_raw_fd(), &mut buf).unwrap();
assert_eq!(&buf[..], b"world");
close(received_r).unwrap();
close(w).unwrap();
@@ -874,25 +849,32 @@ pub fn test_af_alg_cipher() {
.expect("socket failed");
let sockaddr = AlgAddr::new(alg_type, alg_name);
- bind(sock, &sockaddr).expect("bind failed");
+ bind(sock.as_raw_fd(), &sockaddr).expect("bind failed");
assert_eq!(sockaddr.alg_name().to_string_lossy(), alg_name);
assert_eq!(sockaddr.alg_type().to_string_lossy(), alg_type);
- setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt");
- let session_socket = accept(sock).expect("accept failed");
+ setsockopt(&sock, AlgSetKey::default(), &key).expect("setsockopt");
+ let session_socket = accept(sock.as_raw_fd()).expect("accept failed");
let msgs = [
ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT),
ControlMessage::AlgSetIv(iv.as_slice()),
];
let iov = IoSlice::new(&payload);
- sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None)
- .expect("sendmsg encrypt");
+ sendmsg::<()>(
+ session_socket.as_raw_fd(),
+ &[iov],
+ &msgs,
+ MsgFlags::empty(),
+ None,
+ )
+ .expect("sendmsg encrypt");
// allocate buffer for encrypted data
let mut encrypted = vec![0u8; payload_len];
- let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt");
+ let num_bytes =
+ read(session_socket.as_raw_fd(), &mut encrypted).expect("read encrypt");
assert_eq!(num_bytes, payload_len);
let iov = IoSlice::new(&encrypted);
@@ -903,12 +885,19 @@ pub fn test_af_alg_cipher() {
ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT),
ControlMessage::AlgSetIv(iv.as_slice()),
];
- sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None)
- .expect("sendmsg decrypt");
+ sendmsg::<()>(
+ session_socket.as_raw_fd(),
+ &[iov],
+ &msgs,
+ MsgFlags::empty(),
+ None,
+ )
+ .expect("sendmsg decrypt");
// allocate buffer for decrypted data
let mut decrypted = vec![0u8; payload_len];
- let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt");
+ let num_bytes =
+ read(session_socket.as_raw_fd(), &mut decrypted).expect("read decrypt");
assert_eq!(num_bytes, payload_len);
assert_eq!(decrypted, payload);
@@ -927,7 +916,7 @@ pub fn test_af_alg_aead() {
accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr,
ControlMessage, MsgFlags, SockFlag, SockType,
};
- use nix::unistd::{close, read};
+ use nix::unistd::read;
use std::io::IoSlice;
skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352");
@@ -969,12 +958,13 @@ pub fn test_af_alg_aead() {
.expect("socket failed");
let sockaddr = AlgAddr::new(alg_type, alg_name);
- bind(sock, &sockaddr).expect("bind failed");
+ bind(sock.as_raw_fd(), &sockaddr).expect("bind failed");
- setsockopt(sock, AlgSetAeadAuthSize, &auth_size)
+ setsockopt(&sock, AlgSetAeadAuthSize, &auth_size)
.expect("setsockopt AlgSetAeadAuthSize");
- setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt AlgSetKey");
- let session_socket = accept(sock).expect("accept failed");
+ setsockopt(&sock, AlgSetKey::default(), &key)
+ .expect("setsockopt AlgSetKey");
+ let session_socket = accept(sock.as_raw_fd()).expect("accept failed");
let msgs = [
ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT),
@@ -983,15 +973,21 @@ pub fn test_af_alg_aead() {
];
let iov = IoSlice::new(&payload);
- sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None)
- .expect("sendmsg encrypt");
+ sendmsg::<()>(
+ session_socket.as_raw_fd(),
+ &[iov],
+ &msgs,
+ MsgFlags::empty(),
+ None,
+ )
+ .expect("sendmsg encrypt");
// allocate buffer for encrypted data
let mut encrypted =
vec![0u8; (assoc_size as usize) + payload_len + auth_size];
- let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt");
+ let num_bytes =
+ read(session_socket.as_raw_fd(), &mut encrypted).expect("read encrypt");
assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize));
- close(session_socket).expect("close");
for i in 0..assoc_size {
encrypted[i as usize] = 10;
@@ -1001,15 +997,21 @@ pub fn test_af_alg_aead() {
let iv = vec![1u8; iv_len];
- let session_socket = accept(sock).expect("accept failed");
+ let session_socket = accept(sock.as_raw_fd()).expect("accept failed");
let msgs = [
ControlMessage::AlgSetOp(&ALG_OP_DECRYPT),
ControlMessage::AlgSetIv(iv.as_slice()),
ControlMessage::AlgSetAeadAssoclen(&assoc_size),
];
- sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None)
- .expect("sendmsg decrypt");
+ sendmsg::<()>(
+ session_socket.as_raw_fd(),
+ &[iov],
+ &msgs,
+ MsgFlags::empty(),
+ None,
+ )
+ .expect("sendmsg decrypt");
// allocate buffer for decrypted data
let mut decrypted =
@@ -1020,7 +1022,8 @@ pub fn test_af_alg_aead() {
// Do not block on read, as we may have fewer bytes than buffer size
fcntl(session_socket, FcntlArg::F_SETFL(OFlag::O_NONBLOCK))
.expect("fcntl non_blocking");
- let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt");
+ let num_bytes =
+ read(session_socket.as_raw_fd(), &mut decrypted).expect("read decrypt");
assert!(num_bytes >= payload_len + (assoc_size as usize));
assert_eq!(
@@ -1056,7 +1059,7 @@ pub fn test_sendmsg_ipv4packetinfo() {
let sock_addr = SockaddrIn::new(127, 0, 0, 1, 4000);
- bind(sock, &sock_addr).expect("bind failed");
+ bind(sock.as_raw_fd(), &sock_addr).expect("bind failed");
let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
let iov = [IoSlice::new(&slice)];
@@ -1078,8 +1081,14 @@ pub fn test_sendmsg_ipv4packetinfo() {
let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)];
- sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr))
- .expect("sendmsg");
+ sendmsg(
+ sock.as_raw_fd(),
+ &iov,
+ &cmsg,
+ MsgFlags::empty(),
+ Some(&sock_addr),
+ )
+ .expect("sendmsg");
}
// Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`.
@@ -1116,7 +1125,7 @@ pub fn test_sendmsg_ipv6packetinfo() {
let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap();
let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa);
- if let Err(Errno::EADDRNOTAVAIL) = bind(sock, &sock_addr) {
+ if let Err(Errno::EADDRNOTAVAIL) = bind(sock.as_raw_fd(), &sock_addr) {
println!("IPv6 not available, skipping test.");
return;
}
@@ -1132,7 +1141,7 @@ pub fn test_sendmsg_ipv6packetinfo() {
let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)];
sendmsg::<SockaddrIn6>(
- sock,
+ sock.as_raw_fd(),
&iov,
&cmsg,
MsgFlags::empty(),
@@ -1172,8 +1181,8 @@ pub fn test_sendmsg_ipv4sendsrcaddr() {
.expect("socket failed");
let unspec_sock_addr = SockaddrIn::new(0, 0, 0, 0, 0);
- bind(sock, &unspec_sock_addr).expect("bind failed");
- let bound_sock_addr: SockaddrIn = getsockname(sock).unwrap();
+ bind(sock.as_raw_fd(), &unspec_sock_addr).expect("bind failed");
+ let bound_sock_addr: SockaddrIn = getsockname(sock.as_raw_fd()).unwrap();
let localhost_sock_addr: SockaddrIn =
SockaddrIn::new(127, 0, 0, 1, bound_sock_addr.port());
@@ -1184,7 +1193,7 @@ pub fn test_sendmsg_ipv4sendsrcaddr() {
)];
sendmsg(
- sock,
+ sock.as_raw_fd(),
&iov,
&cmsg,
MsgFlags::empty(),
@@ -1261,7 +1270,6 @@ pub fn test_sendmsg_empty_cmsgs() {
recvmsg, sendmsg, socketpair, AddressFamily, MsgFlags, SockFlag,
SockType,
};
- use nix::unistd::close;
use std::io::{IoSlice, IoSliceMut};
let (fd1, fd2) = socketpair(
@@ -1275,10 +1283,10 @@ pub fn test_sendmsg_empty_cmsgs() {
{
let iov = [IoSlice::new(b"hello")];
assert_eq!(
- sendmsg::<()>(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(),
+ sendmsg::<()>(fd1.as_raw_fd(), &iov, &[], MsgFlags::empty(), None)
+ .unwrap(),
5
);
- close(fd1).unwrap();
}
{
@@ -1287,7 +1295,7 @@ pub fn test_sendmsg_empty_cmsgs() {
let mut cmsgspace = cmsg_space!([RawFd; 1]);
let msg = recvmsg::<()>(
- fd2,
+ fd2.as_raw_fd(),
&mut iov,
Some(&mut cmsgspace),
MsgFlags::empty(),
@@ -1301,7 +1309,6 @@ pub fn test_sendmsg_empty_cmsgs() {
.flags
.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
assert_eq!(msg.bytes, 5);
- close(fd2).unwrap();
}
}
@@ -1319,7 +1326,7 @@ fn test_scm_credentials() {
};
#[cfg(any(target_os = "android", target_os = "linux"))]
use nix::sys::socket::{setsockopt, sockopt::PassCred};
- use nix::unistd::{close, getgid, getpid, getuid};
+ use nix::unistd::{getgid, getpid, getuid};
use std::io::{IoSlice, IoSliceMut};
let (send, recv) = socketpair(
@@ -1330,7 +1337,7 @@ fn test_scm_credentials() {
)
.unwrap();
#[cfg(any(target_os = "android", target_os = "linux"))]
- setsockopt(recv, PassCred, &true).unwrap();
+ setsockopt(&recv, PassCred, &true).unwrap();
{
let iov = [IoSlice::new(b"hello")];
@@ -1341,11 +1348,16 @@ fn test_scm_credentials() {
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
let cmsg = ControlMessage::ScmCreds;
assert_eq!(
- sendmsg::<()>(send, &iov, &[cmsg], MsgFlags::empty(), None)
- .unwrap(),
+ sendmsg::<()>(
+ send.as_raw_fd(),
+ &iov,
+ &[cmsg],
+ MsgFlags::empty(),
+ None
+ )
+ .unwrap(),
5
);
- close(send).unwrap();
}
{
@@ -1354,7 +1366,7 @@ fn test_scm_credentials() {
let mut cmsgspace = cmsg_space!(UnixCredentials);
let msg = recvmsg::<()>(
- recv,
+ recv.as_raw_fd(),
&mut iov,
Some(&mut cmsgspace),
MsgFlags::empty(),
@@ -1368,7 +1380,7 @@ fn test_scm_credentials() {
ControlMessageOwned::ScmCredentials(cred) => cred,
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
ControlMessageOwned::ScmCreds(cred) => cred,
- other => panic!("unexpected cmsg {:?}", other),
+ other => panic!("unexpected cmsg {other:?}"),
};
assert!(received_cred.is_none());
assert_eq!(cred.pid(), getpid().as_raw());
@@ -1381,7 +1393,6 @@ fn test_scm_credentials() {
assert!(!msg
.flags
.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
- close(recv).unwrap();
}
}
@@ -1427,7 +1438,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
SockFlag::empty(),
)
.unwrap();
- setsockopt(recv, PassCred, &true).unwrap();
+ setsockopt(&recv, PassCred, &true).unwrap();
let (r, w) = pipe().unwrap();
let mut received_r: Option<RawFd> = None;
@@ -1446,19 +1457,29 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
ControlMessage::ScmRights(&fds),
];
assert_eq!(
- sendmsg::<()>(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(),
+ sendmsg::<()>(
+ send.as_raw_fd(),
+ &iov,
+ &cmsgs,
+ MsgFlags::empty(),
+ None
+ )
+ .unwrap(),
5
);
close(r).unwrap();
- close(send).unwrap();
}
{
let mut buf = [0u8; 5];
let mut iov = [IoSliceMut::new(&mut buf[..])];
- let msg =
- recvmsg::<()>(recv, &mut iov, Some(&mut space), MsgFlags::empty())
- .unwrap();
+ let msg = recvmsg::<()>(
+ recv.as_raw_fd(),
+ &mut iov,
+ Some(&mut space),
+ MsgFlags::empty(),
+ )
+ .unwrap();
let mut received_cred = None;
assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs");
@@ -1485,14 +1506,13 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
assert!(!msg
.flags
.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
- close(recv).unwrap();
}
let received_r = received_r.expect("Did not receive passed fd");
// Ensure that the received file descriptor works
- write(w, b"world").unwrap();
+ write(w.as_raw_fd(), b"world").unwrap();
let mut buf = [0u8; 5];
- read(received_r, &mut buf).unwrap();
+ read(received_r.as_raw_fd(), &mut buf).unwrap();
assert_eq!(&buf[..], b"world");
close(received_r).unwrap();
close(w).unwrap();
@@ -1503,7 +1523,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
pub fn test_named_unixdomain() {
use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr};
use nix::sys::socket::{SockFlag, SockType};
- use nix::unistd::{close, read, write};
+ use nix::unistd::{read, write};
use std::thread;
let tempdir = tempfile::tempdir().unwrap();
@@ -1516,8 +1536,8 @@ pub fn test_named_unixdomain() {
)
.expect("socket failed");
let sockaddr = UnixAddr::new(&sockname).unwrap();
- bind(s1, &sockaddr).expect("bind failed");
- listen(s1, 10).expect("listen failed");
+ bind(s1.as_raw_fd(), &sockaddr).expect("bind failed");
+ listen(&s1, 10).expect("listen failed");
let thr = thread::spawn(move || {
let s2 = socket(
@@ -1527,17 +1547,14 @@ pub fn test_named_unixdomain() {
None,
)
.expect("socket failed");
- connect(s2, &sockaddr).expect("connect failed");
- write(s2, b"hello").expect("write failed");
- close(s2).unwrap();
+ connect(s2.as_raw_fd(), &sockaddr).expect("connect failed");
+ write(s2.as_raw_fd(), b"hello").expect("write failed");
});
- let s3 = accept(s1).expect("accept failed");
+ let s3 = accept(s1.as_raw_fd()).expect("accept failed");
let mut buf = [0; 5];
- read(s3, &mut buf).unwrap();
- close(s3).unwrap();
- close(s1).unwrap();
+ read(s3.as_raw_fd(), &mut buf).unwrap();
thr.join().unwrap();
assert_eq!(&buf[..], b"hello");
@@ -1549,9 +1566,8 @@ pub fn test_named_unixdomain() {
pub fn test_unnamed_unixdomain() {
use nix::sys::socket::{getsockname, socketpair};
use nix::sys::socket::{SockFlag, SockType};
- use nix::unistd::close;
- let (fd_1, fd_2) = socketpair(
+ let (fd_1, _fd_2) = socketpair(
AddressFamily::Unix,
SockType::Stream,
None,
@@ -1559,11 +1575,9 @@ pub fn test_unnamed_unixdomain() {
)
.expect("socketpair failed");
- let addr_1: UnixAddr = getsockname(fd_1).expect("getsockname failed");
+ let addr_1: UnixAddr =
+ getsockname(fd_1.as_raw_fd()).expect("getsockname failed");
assert!(addr_1.is_unnamed());
-
- close(fd_1).unwrap();
- close(fd_2).unwrap();
}
// Test creating and using unnamed unix domain addresses for autobinding sockets
@@ -1572,7 +1586,6 @@ pub fn test_unnamed_unixdomain() {
pub fn test_unnamed_unixdomain_autobind() {
use nix::sys::socket::{bind, getsockname, socket};
use nix::sys::socket::{SockFlag, SockType};
- use nix::unistd::close;
let fd = socket(
AddressFamily::Unix,
@@ -1584,16 +1597,15 @@ pub fn test_unnamed_unixdomain_autobind() {
// unix(7): "If a bind(2) call specifies addrlen as `sizeof(sa_family_t)`, or [...], then the
// socket is autobound to an abstract address"
- bind(fd, &UnixAddr::new_unnamed()).expect("bind failed");
+ bind(fd.as_raw_fd(), &UnixAddr::new_unnamed()).expect("bind failed");
- let addr: UnixAddr = getsockname(fd).expect("getsockname failed");
+ let addr: UnixAddr =
+ getsockname(fd.as_raw_fd()).expect("getsockname failed");
let addr = addr.as_abstract().unwrap();
// changed from 8 to 5 bytes in Linux 2.3.15, and rust's minimum supported Linux version is 3.2
// (as of 2022-11)
assert_eq!(addr.len(), 5);
-
- close(fd).unwrap();
}
// Test creating and using named system control sockets
@@ -1612,15 +1624,15 @@ pub fn test_syscontrol() {
SockProtocol::KextControl,
)
.expect("socket failed");
- SysControlAddr::from_name(fd, "com.apple.net.utun_control", 0)
+ SysControlAddr::from_name(fd.as_raw_fd(), "com.apple.net.utun_control", 0)
.expect("resolving sys_control name failed");
assert_eq!(
- SysControlAddr::from_name(fd, "foo.bar.lol", 0).err(),
+ SysControlAddr::from_name(fd.as_raw_fd(), "foo.bar.lol", 0).err(),
Some(Errno::ENOENT)
);
// requires root privileges
- // connect(fd, &sockaddr).expect("connect failed");
+ // connect(fd.as_raw_fd(), &sockaddr).expect("connect failed");
}
#[cfg(any(
@@ -1646,7 +1658,7 @@ fn loopback_address(
Err(e) => {
let stdioerr = io::stderr();
let mut handle = stdioerr.lock();
- writeln!(handle, "getifaddrs: {:?}", e).unwrap();
+ writeln!(handle, "getifaddrs: {e:?}").unwrap();
return None;
}
};
@@ -1701,9 +1713,10 @@ pub fn test_recv_ipv4pktinfo() {
None,
)
.expect("receive socket failed");
- bind(receive, &lo).expect("bind failed");
- let sa: SockaddrIn = getsockname(receive).expect("getsockname failed");
- setsockopt(receive, Ipv4PacketInfo, &true).expect("setsockopt failed");
+ bind(receive.as_raw_fd(), &lo).expect("bind failed");
+ let sa: SockaddrIn =
+ getsockname(receive.as_raw_fd()).expect("getsockname failed");
+ setsockopt(&receive, Ipv4PacketInfo, &true).expect("setsockopt failed");
{
let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
@@ -1716,7 +1729,7 @@ pub fn test_recv_ipv4pktinfo() {
None,
)
.expect("send socket failed");
- sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa))
+ sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
.expect("sendmsg failed");
}
@@ -1726,7 +1739,7 @@ pub fn test_recv_ipv4pktinfo() {
let mut space = cmsg_space!(libc::in_pktinfo);
let msg = recvmsg::<()>(
- receive,
+ receive.as_raw_fd(),
&mut iovec,
Some(&mut space),
MsgFlags::empty(),
@@ -1795,11 +1808,12 @@ pub fn test_recvif() {
None,
)
.expect("receive socket failed");
- bind(receive, &lo).expect("bind failed");
- let sa: SockaddrIn = getsockname(receive).expect("getsockname failed");
- setsockopt(receive, Ipv4RecvIf, &true)
+ bind(receive.as_raw_fd(), &lo).expect("bind failed");
+ let sa: SockaddrIn =
+ getsockname(receive.as_raw_fd()).expect("getsockname failed");
+ setsockopt(&receive, Ipv4RecvIf, &true)
.expect("setsockopt IP_RECVIF failed");
- setsockopt(receive, Ipv4RecvDstAddr, &true)
+ setsockopt(&receive, Ipv4RecvDstAddr, &true)
.expect("setsockopt IP_RECVDSTADDR failed");
{
@@ -1813,7 +1827,7 @@ pub fn test_recvif() {
None,
)
.expect("send socket failed");
- sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa))
+ sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
.expect("sendmsg failed");
}
@@ -1822,7 +1836,7 @@ pub fn test_recvif() {
let mut iovec = [IoSliceMut::new(&mut buf)];
let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr);
let msg = recvmsg::<()>(
- receive,
+ receive.as_raw_fd(),
&mut iovec,
Some(&mut space),
MsgFlags::empty(),
@@ -1894,9 +1908,10 @@ pub fn test_recvif_ipv4() {
None,
)
.expect("receive socket failed");
- bind(receive, &lo).expect("bind failed");
- let sa: SockaddrIn = getsockname(receive).expect("getsockname failed");
- setsockopt(receive, Ipv4OrigDstAddr, &true)
+ bind(receive.as_raw_fd(), &lo).expect("bind failed");
+ let sa: SockaddrIn =
+ getsockname(receive.as_raw_fd()).expect("getsockname failed");
+ setsockopt(&receive, Ipv4OrigDstAddr, &true)
.expect("setsockopt IP_ORIGDSTADDR failed");
{
@@ -1910,7 +1925,7 @@ pub fn test_recvif_ipv4() {
None,
)
.expect("send socket failed");
- sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa))
+ sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
.expect("sendmsg failed");
}
@@ -1919,7 +1934,7 @@ pub fn test_recvif_ipv4() {
let mut iovec = [IoSliceMut::new(&mut buf)];
let mut space = cmsg_space!(libc::sockaddr_in);
let msg = recvmsg::<()>(
- receive,
+ receive.as_raw_fd(),
&mut iovec,
Some(&mut space),
MsgFlags::empty(),
@@ -1979,9 +1994,10 @@ pub fn test_recvif_ipv6() {
None,
)
.expect("receive socket failed");
- bind(receive, &lo).expect("bind failed");
- let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed");
- setsockopt(receive, Ipv6OrigDstAddr, &true)
+ bind(receive.as_raw_fd(), &lo).expect("bind failed");
+ let sa: SockaddrIn6 =
+ getsockname(receive.as_raw_fd()).expect("getsockname failed");
+ setsockopt(&receive, Ipv6OrigDstAddr, &true)
.expect("setsockopt IP_ORIGDSTADDR failed");
{
@@ -1995,7 +2011,7 @@ pub fn test_recvif_ipv6() {
None,
)
.expect("send socket failed");
- sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa))
+ sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
.expect("sendmsg failed");
}
@@ -2004,7 +2020,7 @@ pub fn test_recvif_ipv6() {
let mut iovec = [IoSliceMut::new(&mut buf)];
let mut space = cmsg_space!(libc::sockaddr_in6);
let msg = recvmsg::<()>(
- receive,
+ receive.as_raw_fd(),
&mut iovec,
Some(&mut space),
MsgFlags::empty(),
@@ -2084,9 +2100,10 @@ pub fn test_recv_ipv6pktinfo() {
None,
)
.expect("receive socket failed");
- bind(receive, &lo).expect("bind failed");
- let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed");
- setsockopt(receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed");
+ bind(receive.as_raw_fd(), &lo).expect("bind failed");
+ let sa: SockaddrIn6 =
+ getsockname(receive.as_raw_fd()).expect("getsockname failed");
+ setsockopt(&receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed");
{
let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
@@ -2099,7 +2116,7 @@ pub fn test_recv_ipv6pktinfo() {
None,
)
.expect("send socket failed");
- sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa))
+ sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
.expect("sendmsg failed");
}
@@ -2109,7 +2126,7 @@ pub fn test_recv_ipv6pktinfo() {
let mut space = cmsg_space!(libc::in6_pktinfo);
let msg = recvmsg::<()>(
- receive,
+ receive.as_raw_fd(),
&mut iovec,
Some(&mut space),
MsgFlags::empty(),
@@ -2136,63 +2153,92 @@ pub fn test_recv_ipv6pktinfo() {
}
#[cfg(any(target_os = "android", target_os = "linux"))]
-#[cfg_attr(graviton, ignore = "Not supported by the CI environment")]
#[test]
pub fn test_vsock() {
- use nix::errno::Errno;
- use nix::sys::socket::{
- bind, connect, listen, socket, AddressFamily, SockFlag, SockType,
- VsockAddr,
- };
- use nix::unistd::close;
- use std::thread;
+ use nix::sys::socket::SockaddrLike;
+ use nix::sys::socket::{AddressFamily, VsockAddr};
+ use std::mem;
let port: u32 = 3000;
- let s1 = socket(
- AddressFamily::Vsock,
- SockType::Stream,
- SockFlag::empty(),
- None,
- )
- .expect("socket failed");
+ let addr_local = VsockAddr::new(libc::VMADDR_CID_LOCAL, port);
+ assert_eq!(addr_local.cid(), libc::VMADDR_CID_LOCAL);
+ assert_eq!(addr_local.port(), port);
- // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error.
- let sockaddr_hv = VsockAddr::new(libc::VMADDR_CID_HYPERVISOR, port);
- assert_eq!(bind(s1, &sockaddr_hv).err(), Some(Errno::EADDRNOTAVAIL));
+ let addr_any = VsockAddr::new(libc::VMADDR_CID_ANY, libc::VMADDR_PORT_ANY);
+ assert_eq!(addr_any.cid(), libc::VMADDR_CID_ANY);
+ assert_eq!(addr_any.port(), libc::VMADDR_PORT_ANY);
- let sockaddr_any = VsockAddr::new(libc::VMADDR_CID_ANY, port);
- assert_eq!(bind(s1, &sockaddr_any), Ok(()));
- listen(s1, 10).expect("listen failed");
+ assert_ne!(addr_local, addr_any);
+ assert_ne!(calculate_hash(&addr_local), calculate_hash(&addr_any));
- let thr = thread::spawn(move || {
- let cid: u32 = libc::VMADDR_CID_HOST;
+ let addr1 = VsockAddr::new(libc::VMADDR_CID_HOST, port);
+ let addr2 = VsockAddr::new(libc::VMADDR_CID_HOST, port);
+ assert_eq!(addr1, addr2);
+ assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
- let s2 = socket(
- AddressFamily::Vsock,
- SockType::Stream,
- SockFlag::empty(),
- None,
+ let addr3 = unsafe {
+ VsockAddr::from_raw(
+ addr2.as_ref() as *const libc::sockaddr_vm as *const libc::sockaddr,
+ Some(mem::size_of::<libc::sockaddr_vm>().try_into().unwrap()),
)
- .expect("socket failed");
+ }
+ .unwrap();
+ assert_eq!(
+ addr3.as_ref().svm_family,
+ AddressFamily::Vsock as libc::sa_family_t
+ );
+ assert_eq!(addr3.as_ref().svm_cid, addr1.cid());
+ assert_eq!(addr3.as_ref().svm_port, addr1.port());
+}
- let sockaddr_host = VsockAddr::new(cid, port);
+#[cfg(target_os = "macos")]
+#[test]
+pub fn test_vsock() {
+ use nix::sys::socket::SockaddrLike;
+ use nix::sys::socket::{AddressFamily, VsockAddr};
+ use std::mem;
- // The current implementation does not support loopback devices, so,
- // for now, we expect a failure on the connect.
- assert_ne!(connect(s2, &sockaddr_host), Ok(()));
+ let port: u32 = 3000;
- close(s2).unwrap();
- });
+ // macOS doesn't have a VMADDR_CID_LOCAL, so test with host again
+ let addr_host = VsockAddr::new(libc::VMADDR_CID_HOST, port);
+ assert_eq!(addr_host.cid(), libc::VMADDR_CID_HOST);
+ assert_eq!(addr_host.port(), port);
- close(s1).unwrap();
- thr.join().unwrap();
+ let addr_any = VsockAddr::new(libc::VMADDR_CID_ANY, libc::VMADDR_PORT_ANY);
+ assert_eq!(addr_any.cid(), libc::VMADDR_CID_ANY);
+ assert_eq!(addr_any.port(), libc::VMADDR_PORT_ANY);
+
+ assert_ne!(addr_host, addr_any);
+ assert_ne!(calculate_hash(&addr_host), calculate_hash(&addr_any));
+
+ let addr1 = VsockAddr::new(libc::VMADDR_CID_HOST, port);
+ let addr2 = VsockAddr::new(libc::VMADDR_CID_HOST, port);
+ assert_eq!(addr1, addr2);
+ assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
+
+ let addr3 = unsafe {
+ VsockAddr::from_raw(
+ addr2.as_ref() as *const libc::sockaddr_vm as *const libc::sockaddr,
+ Some(mem::size_of::<libc::sockaddr_vm>().try_into().unwrap()),
+ )
+ }
+ .unwrap();
+ assert_eq!(
+ addr3.as_ref().svm_family,
+ AddressFamily::Vsock as libc::sa_family_t
+ );
+ let cid = addr3.as_ref().svm_cid;
+ let port = addr3.as_ref().svm_port;
+ assert_eq!(cid, addr1.cid());
+ assert_eq!(port, addr1.port());
}
// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack
// of QEMU support is suspected.
#[cfg_attr(qemu, ignore)]
-#[cfg(all(target_os = "linux"))]
+#[cfg(target_os = "linux")]
#[test]
fn test_recvmsg_timestampns() {
use nix::sys::socket::*;
@@ -2209,24 +2255,30 @@ fn test_recvmsg_timestampns() {
None,
)
.unwrap();
- setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap();
+ setsockopt(&in_socket, sockopt::ReceiveTimestampns, &true).unwrap();
let localhost = SockaddrIn::new(127, 0, 0, 1, 0);
- bind(in_socket, &localhost).unwrap();
- let address: SockaddrIn = getsockname(in_socket).unwrap();
+ bind(in_socket.as_raw_fd(), &localhost).unwrap();
+ let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap();
// Get initial time
let time0 = SystemTime::now();
// Send the message
let iov = [IoSlice::new(message)];
let flags = MsgFlags::empty();
- let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap();
+ let l = sendmsg(in_socket.as_raw_fd(), &iov, &[], flags, Some(&address))
+ .unwrap();
assert_eq!(message.len(), l);
// Receive the message
let mut buffer = vec![0u8; message.len()];
let mut cmsgspace = nix::cmsg_space!(TimeSpec);
let mut iov = [IoSliceMut::new(&mut buffer)];
- let r = recvmsg::<()>(in_socket, &mut iov, Some(&mut cmsgspace), flags)
- .unwrap();
+ let r = recvmsg::<()>(
+ in_socket.as_raw_fd(),
+ &mut iov,
+ Some(&mut cmsgspace),
+ flags,
+ )
+ .unwrap();
let rtime = match r.cmsgs().next() {
Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime,
Some(_) => panic!("Unexpected control message"),
@@ -2240,14 +2292,12 @@ fn test_recvmsg_timestampns() {
Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32);
assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
- // Close socket
- nix::unistd::close(in_socket).unwrap();
}
// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack
// of QEMU support is suspected.
#[cfg_attr(qemu, ignore)]
-#[cfg(all(target_os = "linux"))]
+#[cfg(target_os = "linux")]
#[test]
fn test_recvmmsg_timestampns() {
use nix::sys::socket::*;
@@ -2264,16 +2314,17 @@ fn test_recvmmsg_timestampns() {
None,
)
.unwrap();
- setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap();
+ setsockopt(&in_socket, sockopt::ReceiveTimestampns, &true).unwrap();
let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap();
- bind(in_socket, &localhost).unwrap();
- let address: SockaddrIn = getsockname(in_socket).unwrap();
+ bind(in_socket.as_raw_fd(), &localhost).unwrap();
+ let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap();
// Get initial time
let time0 = SystemTime::now();
// Send the message
let iov = [IoSlice::new(message)];
let flags = MsgFlags::empty();
- let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap();
+ let l = sendmsg(in_socket.as_raw_fd(), &iov, &[], flags, Some(&address))
+ .unwrap();
assert_eq!(message.len(), l);
// Receive the message
let mut buffer = vec![0u8; message.len()];
@@ -2281,7 +2332,7 @@ fn test_recvmmsg_timestampns() {
let iov = vec![[IoSliceMut::new(&mut buffer)]];
let mut data = MultiHeaders::preallocate(1, Some(cmsgspace));
let r: Vec<RecvMsg<()>> =
- recvmmsg(in_socket, &mut data, iov.iter(), flags, None)
+ recvmmsg(in_socket.as_raw_fd(), &mut data, iov.iter(), flags, None)
.unwrap()
.collect();
let rtime = match r[0].cmsgs().next() {
@@ -2297,8 +2348,6 @@ fn test_recvmmsg_timestampns() {
Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32);
assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
- // Close socket
- nix::unistd::close(in_socket).unwrap();
}
// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack
@@ -2331,16 +2380,16 @@ fn test_recvmsg_rxq_ovfl() {
.unwrap();
let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap();
- bind(in_socket, &localhost).unwrap();
+ bind(in_socket.as_raw_fd(), &localhost).unwrap();
- let address: SockaddrIn = getsockname(in_socket).unwrap();
- connect(out_socket, &address).unwrap();
+ let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap();
+ connect(out_socket.as_raw_fd(), &address).unwrap();
// Set SO_RXQ_OVFL flag.
- setsockopt(in_socket, RxqOvfl, &1).unwrap();
+ setsockopt(&in_socket, RxqOvfl, &1).unwrap();
// Set the receiver buffer size to hold only 2 messages.
- setsockopt(in_socket, RcvBuf, &bufsize).unwrap();
+ setsockopt(&in_socket, RcvBuf, &bufsize).unwrap();
let mut drop_counter = 0;
@@ -2351,8 +2400,14 @@ fn test_recvmsg_rxq_ovfl() {
// Send the 3 messages (the receiver buffer can only hold 2 messages)
// to create an overflow.
for _ in 0..3 {
- let l =
- sendmsg(out_socket, &iov, &[], flags, Some(&address)).unwrap();
+ let l = sendmsg(
+ out_socket.as_raw_fd(),
+ &iov,
+ &[],
+ flags,
+ Some(&address),
+ )
+ .unwrap();
assert_eq!(message.len(), l);
}
@@ -2364,7 +2419,7 @@ fn test_recvmsg_rxq_ovfl() {
let mut iov = [IoSliceMut::new(&mut buffer)];
match recvmsg::<()>(
- in_socket,
+ in_socket.as_raw_fd(),
&mut iov,
Some(&mut cmsgspace),
MsgFlags::MSG_DONTWAIT,
@@ -2390,16 +2445,13 @@ fn test_recvmsg_rxq_ovfl() {
// One packet lost.
assert_eq!(drop_counter, 1);
-
- // Close sockets
- nix::unistd::close(in_socket).unwrap();
- nix::unistd::close(out_socket).unwrap();
}
#[cfg(any(target_os = "linux", target_os = "android",))]
mod linux_errqueue {
use super::FromStr;
use nix::sys::socket::*;
+ use std::os::unix::io::AsRawFd;
// Send a UDP datagram to a bogus destination address and observe an ICMP error (v4).
//
@@ -2443,7 +2495,7 @@ mod linux_errqueue {
}
*ext_err
} else {
- panic!("Unexpected control message {:?}", cmsg);
+ panic!("Unexpected control message {cmsg:?}");
}
},
)
@@ -2494,7 +2546,7 @@ mod linux_errqueue {
}
*ext_err
} else {
- panic!("Unexpected control message {:?}", cmsg);
+ panic!("Unexpected control message {cmsg:?}");
}
},
)
@@ -2520,15 +2572,15 @@ mod linux_errqueue {
let sock_addr = SockaddrStorage::from(std_sa);
let sock = socket(af, SockType::Datagram, SockFlag::SOCK_CLOEXEC, None)
.unwrap();
- setsockopt(sock, opt, &true).unwrap();
+ setsockopt(&sock, opt, &true).unwrap();
if let Err(e) = sendto(
- sock,
+ sock.as_raw_fd(),
MESSAGE_CONTENTS.as_bytes(),
&sock_addr,
MsgFlags::empty(),
) {
assert_eq!(e, Errno::EADDRNOTAVAIL);
- println!("{:?} not available, skipping test.", af);
+ println!("{af:?} not available, skipping test.");
return;
}
@@ -2537,7 +2589,7 @@ mod linux_errqueue {
let mut cspace = cmsg_space!(libc::sock_extended_err, SA);
let msg = recvmsg(
- sock,
+ sock.as_raw_fd(),
&mut iovec,
Some(&mut cspace),
MsgFlags::MSG_ERRQUEUE,
@@ -2600,7 +2652,7 @@ pub fn test_txtime() {
clockid: libc::CLOCK_MONOTONIC,
flags: 0,
};
- setsockopt(ssock, sockopt::TxTime, &txtime_cfg).unwrap();
+ setsockopt(&ssock, sockopt::TxTime, &txtime_cfg).unwrap();
let rsock = socket(
AddressFamily::Inet,
@@ -2609,7 +2661,7 @@ pub fn test_txtime() {
None,
)
.unwrap();
- bind(rsock, &sock_addr).unwrap();
+ bind(rsock.as_raw_fd(), &sock_addr).unwrap();
let sbuf = [0u8; 2048];
let iov1 = [std::io::IoSlice::new(&sbuf)];
@@ -2619,10 +2671,17 @@ pub fn test_txtime() {
let txtime = (now + delay).num_nanoseconds() as u64;
let cmsg = ControlMessage::TxTime(&txtime);
- sendmsg(ssock, &iov1, &[cmsg], MsgFlags::empty(), Some(&sock_addr))
- .unwrap();
+ sendmsg(
+ ssock.as_raw_fd(),
+ &iov1,
+ &[cmsg],
+ MsgFlags::empty(),
+ Some(&sock_addr),
+ )
+ .unwrap();
let mut rbuf = [0u8; 2048];
let mut iov2 = [std::io::IoSliceMut::new(&mut rbuf)];
- recvmsg::<()>(rsock, &mut iov2, None, MsgFlags::empty()).unwrap();
+ recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, None, MsgFlags::empty())
+ .unwrap();
}
diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs
index 34bef94..0e34917 100644
--- a/test/sys/test_sockopt.rs
+++ b/test/sys/test_sockopt.rs
@@ -5,6 +5,7 @@ use nix::sys::socket::{
SockProtocol, SockType,
};
use rand::{thread_rng, Rng};
+use std::os::unix::io::AsRawFd;
// NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not.
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",))]
@@ -22,7 +23,7 @@ pub fn test_local_peercred_seqpacket() {
SockFlag::empty(),
)
.unwrap();
- let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap();
+ let xucred = getsockopt(&fd1, sockopt::LocalPeerCred).unwrap();
assert_eq!(xucred.version(), 0);
assert_eq!(Uid::from_raw(xucred.uid()), Uid::current());
assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
@@ -48,12 +49,28 @@ pub fn test_local_peercred_stream() {
SockFlag::empty(),
)
.unwrap();
- let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap();
+ let xucred = getsockopt(&fd1, sockopt::LocalPeerCred).unwrap();
assert_eq!(xucred.version(), 0);
assert_eq!(Uid::from_raw(xucred.uid()), Uid::current());
assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
}
+#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[test]
+pub fn test_local_peer_pid() {
+ use nix::sys::socket::socketpair;
+
+ let (fd1, _fd2) = socketpair(
+ AddressFamily::Unix,
+ SockType::Stream,
+ None,
+ SockFlag::empty(),
+ )
+ .unwrap();
+ let pid = getsockopt(&fd1, sockopt::LocalPeerPid).unwrap();
+ assert_eq!(pid, std::process::id() as _);
+}
+
#[cfg(target_os = "linux")]
#[test]
fn is_so_mark_functional() {
@@ -68,8 +85,8 @@ fn is_so_mark_functional() {
None,
)
.unwrap();
- setsockopt(s, sockopt::Mark, &1337).unwrap();
- let mark = getsockopt(s, sockopt::Mark).unwrap();
+ setsockopt(&s, sockopt::Mark, &1337).unwrap();
+ let mark = getsockopt(&s, sockopt::Mark).unwrap();
assert_eq!(mark, 1337);
}
@@ -83,18 +100,18 @@ fn test_so_buf() {
)
.unwrap();
let bufsize: usize = thread_rng().gen_range(4096..131_072);
- setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap();
- let actual = getsockopt(fd, sockopt::SndBuf).unwrap();
+ setsockopt(&fd, sockopt::SndBuf, &bufsize).unwrap();
+ let actual = getsockopt(&fd, sockopt::SndBuf).unwrap();
assert!(actual >= bufsize);
- setsockopt(fd, sockopt::RcvBuf, &bufsize).unwrap();
- let actual = getsockopt(fd, sockopt::RcvBuf).unwrap();
+ setsockopt(&fd, sockopt::RcvBuf, &bufsize).unwrap();
+ let actual = getsockopt(&fd, sockopt::RcvBuf).unwrap();
assert!(actual >= bufsize);
}
#[test]
fn test_so_tcp_maxseg() {
use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn};
- use nix::unistd::{close, write};
+ use nix::unistd::write;
use std::net::SocketAddrV4;
use std::str::FromStr;
@@ -108,9 +125,9 @@ fn test_so_tcp_maxseg() {
SockProtocol::Tcp,
)
.unwrap();
- bind(rsock, &sock_addr).unwrap();
- listen(rsock, 10).unwrap();
- let initial = getsockopt(rsock, sockopt::TcpMaxSeg).unwrap();
+ bind(rsock.as_raw_fd(), &sock_addr).unwrap();
+ listen(&rsock, 10).unwrap();
+ let initial = getsockopt(&rsock, sockopt::TcpMaxSeg).unwrap();
// Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some
// platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger
// than 700
@@ -118,7 +135,7 @@ fn test_so_tcp_maxseg() {
if #[cfg(any(target_os = "android", target_os = "linux"))] {
let segsize: u32 = 873;
assert!(initial < segsize);
- setsockopt(rsock, sockopt::TcpMaxSeg, &segsize).unwrap();
+ setsockopt(&rsock, sockopt::TcpMaxSeg, &segsize).unwrap();
} else {
assert!(initial < 700);
}
@@ -132,10 +149,10 @@ fn test_so_tcp_maxseg() {
SockProtocol::Tcp,
)
.unwrap();
- connect(ssock, &sock_addr).unwrap();
- let rsess = accept(rsock).unwrap();
+ connect(ssock.as_raw_fd(), &sock_addr).unwrap();
+ let rsess = accept(rsock.as_raw_fd()).unwrap();
write(rsess, b"hello").unwrap();
- let actual = getsockopt(ssock, sockopt::TcpMaxSeg).unwrap();
+ let actual = getsockopt(&ssock, sockopt::TcpMaxSeg).unwrap();
// Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max
// TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary.
cfg_if! {
@@ -147,8 +164,6 @@ fn test_so_tcp_maxseg() {
assert!(536 < actual);
}
}
- close(rsock).unwrap();
- close(ssock).unwrap();
}
#[test]
@@ -161,7 +176,7 @@ fn test_so_type() {
)
.unwrap();
- assert_eq!(Ok(SockType::Stream), getsockopt(sockfd, sockopt::SockType));
+ assert_eq!(Ok(SockType::Stream), getsockopt(&sockfd, sockopt::SockType));
}
/// getsockopt(_, sockopt::SockType) should gracefully handle unknown socket
@@ -170,12 +185,14 @@ fn test_so_type() {
#[test]
fn test_so_type_unknown() {
use nix::errno::Errno;
+ use std::os::unix::io::{FromRawFd, OwnedFd};
require_capability!("test_so_type", CAP_NET_RAW);
- let sockfd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) };
- assert!(sockfd >= 0, "Error opening socket: {}", nix::Error::last());
+ let raw_fd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) };
+ assert!(raw_fd >= 0, "Error opening socket: {}", nix::Error::last());
+ let sockfd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
- assert_eq!(Err(Errno::EINVAL), getsockopt(sockfd, sockopt::SockType));
+ assert_eq!(Err(Errno::EINVAL), getsockopt(&sockfd, sockopt::SockType));
}
// The CI doesn't supported getsockopt and setsockopt on emulated processors.
@@ -198,17 +215,17 @@ fn test_tcp_congestion() {
)
.unwrap();
- let val = getsockopt(fd, sockopt::TcpCongestion).unwrap();
- setsockopt(fd, sockopt::TcpCongestion, &val).unwrap();
+ let val = getsockopt(&fd, sockopt::TcpCongestion).unwrap();
+ setsockopt(&fd, sockopt::TcpCongestion, &val).unwrap();
setsockopt(
- fd,
+ &fd,
sockopt::TcpCongestion,
&OsString::from("tcp_congestion_does_not_exist"),
)
.unwrap_err();
- assert_eq!(getsockopt(fd, sockopt::TcpCongestion).unwrap(), val);
+ assert_eq!(getsockopt(&fd, sockopt::TcpCongestion).unwrap(), val);
}
#[test]
@@ -224,10 +241,10 @@ fn test_bindtodevice() {
)
.unwrap();
- let val = getsockopt(fd, sockopt::BindToDevice).unwrap();
- setsockopt(fd, sockopt::BindToDevice, &val).unwrap();
+ let val = getsockopt(&fd, sockopt::BindToDevice).unwrap();
+ setsockopt(&fd, sockopt::BindToDevice, &val).unwrap();
- assert_eq!(getsockopt(fd, sockopt::BindToDevice).unwrap(), val);
+ assert_eq!(getsockopt(&fd, sockopt::BindToDevice).unwrap(), val);
}
#[test]
@@ -239,8 +256,8 @@ fn test_so_tcp_keepalive() {
SockProtocol::Tcp,
)
.unwrap();
- setsockopt(fd, sockopt::KeepAlive, &true).unwrap();
- assert!(getsockopt(fd, sockopt::KeepAlive).unwrap());
+ setsockopt(&fd, sockopt::KeepAlive, &true).unwrap();
+ assert!(getsockopt(&fd, sockopt::KeepAlive).unwrap());
#[cfg(any(
target_os = "android",
@@ -249,17 +266,17 @@ fn test_so_tcp_keepalive() {
target_os = "linux"
))]
{
- let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap();
- setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap();
- assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1);
+ let x = getsockopt(&fd, sockopt::TcpKeepIdle).unwrap();
+ setsockopt(&fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap();
+ assert_eq!(getsockopt(&fd, sockopt::TcpKeepIdle).unwrap(), x + 1);
- let x = getsockopt(fd, sockopt::TcpKeepCount).unwrap();
- setsockopt(fd, sockopt::TcpKeepCount, &(x + 1)).unwrap();
- assert_eq!(getsockopt(fd, sockopt::TcpKeepCount).unwrap(), x + 1);
+ let x = getsockopt(&fd, sockopt::TcpKeepCount).unwrap();
+ setsockopt(&fd, sockopt::TcpKeepCount, &(x + 1)).unwrap();
+ assert_eq!(getsockopt(&fd, sockopt::TcpKeepCount).unwrap(), x + 1);
- let x = getsockopt(fd, sockopt::TcpKeepInterval).unwrap();
- setsockopt(fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap();
- assert_eq!(getsockopt(fd, sockopt::TcpKeepInterval).unwrap(), x + 1);
+ let x = getsockopt(&fd, sockopt::TcpKeepInterval).unwrap();
+ setsockopt(&fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap();
+ assert_eq!(getsockopt(&fd, sockopt::TcpKeepInterval).unwrap(), x + 1);
}
}
@@ -283,11 +300,11 @@ fn test_get_mtu() {
.unwrap();
// Bind and initiate connection
- bind(usock, &SockaddrIn::from(std_sa)).unwrap();
- connect(usock, &SockaddrIn::from(std_sb)).unwrap();
+ bind(usock.as_raw_fd(), &SockaddrIn::from(std_sa)).unwrap();
+ connect(usock.as_raw_fd(), &SockaddrIn::from(std_sb)).unwrap();
// Loopback connections have 2^16 - the maximum - MTU
- assert_eq!(getsockopt(usock, sockopt::IpMtu), Ok(u16::MAX as i32))
+ assert_eq!(getsockopt(&usock, sockopt::IpMtu), Ok(u16::MAX as i32))
}
#[test]
@@ -300,7 +317,7 @@ fn test_ttl_opts() {
None,
)
.unwrap();
- setsockopt(fd4, sockopt::Ipv4Ttl, &1)
+ setsockopt(&fd4, sockopt::Ipv4Ttl, &1)
.expect("setting ipv4ttl on an inet socket should succeed");
let fd6 = socket(
AddressFamily::Inet6,
@@ -309,7 +326,7 @@ fn test_ttl_opts() {
None,
)
.unwrap();
- setsockopt(fd6, sockopt::Ipv6Ttl, &1)
+ setsockopt(&fd6, sockopt::Ipv6Ttl, &1)
.expect("setting ipv6ttl on an inet6 socket should succeed");
}
@@ -323,9 +340,9 @@ fn test_dontfrag_opts() {
SockProtocol::Tcp,
)
.unwrap();
- setsockopt(fd4, sockopt::IpDontFrag, &true)
+ setsockopt(&fd4, sockopt::IpDontFrag, &true)
.expect("setting IP_DONTFRAG on an inet stream socket should succeed");
- setsockopt(fd4, sockopt::IpDontFrag, &false).expect(
+ setsockopt(&fd4, sockopt::IpDontFrag, &false).expect(
"unsetting IP_DONTFRAG on an inet stream socket should succeed",
);
let fd4d = socket(
@@ -335,10 +352,10 @@ fn test_dontfrag_opts() {
None,
)
.unwrap();
- setsockopt(fd4d, sockopt::IpDontFrag, &true).expect(
+ setsockopt(&fd4d, sockopt::IpDontFrag, &true).expect(
"setting IP_DONTFRAG on an inet datagram socket should succeed",
);
- setsockopt(fd4d, sockopt::IpDontFrag, &false).expect(
+ setsockopt(&fd4d, sockopt::IpDontFrag, &false).expect(
"unsetting IP_DONTFRAG on an inet datagram socket should succeed",
);
}
@@ -361,10 +378,10 @@ fn test_v6dontfrag_opts() {
SockProtocol::Tcp,
)
.unwrap();
- setsockopt(fd6, sockopt::Ipv6DontFrag, &true).expect(
+ setsockopt(&fd6, sockopt::Ipv6DontFrag, &true).expect(
"setting IPV6_DONTFRAG on an inet6 stream socket should succeed",
);
- setsockopt(fd6, sockopt::Ipv6DontFrag, &false).expect(
+ setsockopt(&fd6, sockopt::Ipv6DontFrag, &false).expect(
"unsetting IPV6_DONTFRAG on an inet6 stream socket should succeed",
);
let fd6d = socket(
@@ -374,10 +391,10 @@ fn test_v6dontfrag_opts() {
None,
)
.unwrap();
- setsockopt(fd6d, sockopt::Ipv6DontFrag, &true).expect(
+ setsockopt(&fd6d, sockopt::Ipv6DontFrag, &true).expect(
"setting IPV6_DONTFRAG on an inet6 datagram socket should succeed",
);
- setsockopt(fd6d, sockopt::Ipv6DontFrag, &false).expect(
+ setsockopt(&fd6d, sockopt::Ipv6DontFrag, &false).expect(
"unsetting IPV6_DONTFRAG on an inet6 datagram socket should succeed",
);
}
@@ -393,8 +410,8 @@ fn test_so_priority() {
)
.unwrap();
let priority = 3;
- setsockopt(fd, sockopt::Priority, &priority).unwrap();
- assert_eq!(getsockopt(fd, sockopt::Priority).unwrap(), priority);
+ setsockopt(&fd, sockopt::Priority, &priority).unwrap();
+ assert_eq!(getsockopt(&fd, sockopt::Priority).unwrap(), priority);
}
#[test]
@@ -408,8 +425,8 @@ fn test_ip_tos() {
)
.unwrap();
let tos = 0x80; // CS4
- setsockopt(fd, sockopt::IpTos, &tos).unwrap();
- assert_eq!(getsockopt(fd, sockopt::IpTos).unwrap(), tos);
+ setsockopt(&fd, sockopt::IpTos, &tos).unwrap();
+ assert_eq!(getsockopt(&fd, sockopt::IpTos).unwrap(), tos);
}
#[test]
@@ -426,6 +443,6 @@ fn test_ipv6_tclass() {
)
.unwrap();
let class = 0x80; // CS4
- setsockopt(fd, sockopt::Ipv6TClass, &class).unwrap();
- assert_eq!(getsockopt(fd, sockopt::Ipv6TClass).unwrap(), class);
+ setsockopt(&fd, sockopt::Ipv6TClass, &class).unwrap();
+ assert_eq!(getsockopt(&fd, sockopt::Ipv6TClass).unwrap(), class);
}
diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs
index aaf0008..8391937 100644
--- a/test/sys/test_termios.rs
+++ b/test/sys/test_termios.rs
@@ -1,17 +1,17 @@
-use std::os::unix::prelude::*;
+use std::os::unix::io::{AsFd, AsRawFd};
use tempfile::tempfile;
use nix::errno::Errno;
use nix::fcntl;
use nix::pty::openpty;
use nix::sys::termios::{self, tcgetattr, LocalFlags, OutputFlags};
-use nix::unistd::{close, read, write};
+use nix::unistd::{read, write};
-/// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s
-fn write_all(f: RawFd, buf: &[u8]) {
+/// Helper function analogous to `std::io::Write::write_all`, but for `Fd`s
+fn write_all<Fd: AsFd>(f: Fd, buf: &[u8]) {
let mut len = 0;
while len < buf.len() {
- len += write(f, &buf[len..]).unwrap();
+ len += write(f.as_fd().as_raw_fd(), &buf[len..]).unwrap();
}
}
@@ -22,25 +22,14 @@ fn test_tcgetattr_pty() {
let _m = crate::PTSNAME_MTX.lock();
let pty = openpty(None, None).expect("openpty failed");
- termios::tcgetattr(pty.slave).unwrap();
- close(pty.master).expect("closing the master failed");
- close(pty.slave).expect("closing the slave failed");
+ termios::tcgetattr(&pty.slave).unwrap();
}
// Test tcgetattr on something that isn't a terminal
#[test]
fn test_tcgetattr_enotty() {
let file = tempfile().unwrap();
- assert_eq!(
- termios::tcgetattr(file.as_raw_fd()).err(),
- Some(Errno::ENOTTY)
- );
-}
-
-// Test tcgetattr on an invalid file descriptor
-#[test]
-fn test_tcgetattr_ebadf() {
- assert_eq!(termios::tcgetattr(-1).err(), Some(Errno::EBADF));
+ assert_eq!(termios::tcgetattr(&file).err(), Some(Errno::ENOTTY));
}
// Test modifying output flags
@@ -52,12 +41,7 @@ fn test_output_flags() {
// Open one pty to get attributes for the second one
let mut termios = {
let pty = openpty(None, None).expect("openpty failed");
- assert!(pty.master > 0);
- assert!(pty.slave > 0);
- let termios = tcgetattr(pty.slave).expect("tcgetattr failed");
- close(pty.master).unwrap();
- close(pty.slave).unwrap();
- termios
+ tcgetattr(&pty.slave).expect("tcgetattr failed")
};
// Make sure postprocessing '\r' isn't specified by default or this test is useless.
@@ -73,19 +57,15 @@ fn test_output_flags() {
// Open a pty
let pty = openpty(None, &termios).unwrap();
- assert!(pty.master > 0);
- assert!(pty.slave > 0);
// Write into the master
let string = "foofoofoo\r";
- write_all(pty.master, string.as_bytes());
+ write_all(&pty.master, string.as_bytes());
// Read from the slave verifying that the output has been properly transformed
let mut buf = [0u8; 10];
- crate::read_exact(pty.slave, &mut buf);
+ crate::read_exact(&pty.slave, &mut buf);
let transformed_string = "foofoofoo\n";
- close(pty.master).unwrap();
- close(pty.slave).unwrap();
assert_eq!(&buf, transformed_string.as_bytes());
}
@@ -98,12 +78,7 @@ fn test_local_flags() {
// Open one pty to get attributes for the second one
let mut termios = {
let pty = openpty(None, None).unwrap();
- assert!(pty.master > 0);
- assert!(pty.slave > 0);
- let termios = tcgetattr(pty.slave).unwrap();
- close(pty.master).unwrap();
- close(pty.slave).unwrap();
- termios
+ tcgetattr(&pty.slave).unwrap()
};
// Make sure echo is specified by default or this test is useless.
@@ -114,23 +89,19 @@ fn test_local_flags() {
// Open a new pty with our modified termios settings
let pty = openpty(None, &termios).unwrap();
- assert!(pty.master > 0);
- assert!(pty.slave > 0);
// Set the master is in nonblocking mode or reading will never return.
- let flags = fcntl::fcntl(pty.master, fcntl::F_GETFL).unwrap();
+ let flags = fcntl::fcntl(pty.master.as_raw_fd(), fcntl::F_GETFL).unwrap();
let new_flags =
fcntl::OFlag::from_bits_truncate(flags) | fcntl::OFlag::O_NONBLOCK;
- fcntl::fcntl(pty.master, fcntl::F_SETFL(new_flags)).unwrap();
+ fcntl::fcntl(pty.master.as_raw_fd(), fcntl::F_SETFL(new_flags)).unwrap();
// Write into the master
let string = "foofoofoo\r";
- write_all(pty.master, string.as_bytes());
+ write_all(&pty.master, string.as_bytes());
// Try to read from the master, which should not have anything as echoing was disabled.
let mut buf = [0u8; 10];
- let read = read(pty.master, &mut buf).unwrap_err();
- close(pty.master).unwrap();
- close(pty.slave).unwrap();
+ let read = read(pty.master.as_raw_fd(), &mut buf).unwrap_err();
assert_eq!(read, Errno::EAGAIN);
}
diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs
index 0f4b8a6..fc09465 100644
--- a/test/sys/test_uio.rs
+++ b/test/sys/test_uio.rs
@@ -4,7 +4,7 @@ use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use std::fs::OpenOptions;
use std::io::IoSlice;
-use std::os::unix::io::AsRawFd;
+use std::os::unix::io::{FromRawFd, OwnedFd};
use std::{cmp, iter};
#[cfg(not(target_os = "redox"))]
@@ -40,12 +40,16 @@ fn test_writev() {
iovecs.push(IoSlice::new(b));
consumed += slice_len;
}
- let pipe_res = pipe();
- let (reader, writer) = pipe_res.expect("Couldn't create pipe");
+ let (reader, writer) = pipe().expect("Couldn't create pipe");
// FileDesc will close its filedesc (reader).
let mut read_buf: Vec<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 write_res = writev(&writer, &iovecs);
let written = write_res.expect("couldn't write");
// Check whether we written all data
assert_eq!(to_write.len(), written);
@@ -55,7 +59,6 @@ fn test_writev() {
assert_eq!(read, written);
// Check equality of written and read data
assert_eq!(&to_write, &read_buf);
- close(writer).expect("closed writer");
close(reader).expect("closed reader");
}
@@ -88,7 +91,12 @@ fn test_readv() {
let (reader, writer) = pipe().expect("couldn't create pipe");
// Blocking io, should write all data.
write(writer, &to_write).expect("write failed");
- let read = readv(reader, &mut iovecs[..]).expect("read failed");
+
+ // Temporary workaround to cope with the existing RawFd pipe(2), should be
+ // removed when pipe(2) becomes I/O-safe.
+ let reader = unsafe { OwnedFd::from_raw_fd(reader) };
+
+ let read = readv(&reader, &mut iovecs[..]).expect("read failed");
// Check whether we've read all data
assert_eq!(to_write.len(), read);
// Cccumulate data from iovecs
@@ -100,7 +108,6 @@ fn test_readv() {
assert_eq!(read_buf.len(), to_write.len());
// Check equality of written and read data
assert_eq!(&read_buf, &to_write);
- close(reader).expect("couldn't close reader");
close(writer).expect("couldn't close writer");
}
@@ -111,7 +118,7 @@ fn test_pwrite() {
let mut file = tempfile().unwrap();
let buf = [1u8; 8];
- assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8));
+ assert_eq!(Ok(8), pwrite(&file, &buf, 8));
let mut file_content = Vec::new();
file.read_to_end(&mut file_content).unwrap();
let mut expected = vec![0u8; 8];
@@ -137,7 +144,7 @@ fn test_pread() {
file.write_all(&file_content).unwrap();
let mut buf = [0u8; 16];
- assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16));
+ assert_eq!(Ok(16), pread(&file, &mut buf, 16));
let expected: Vec<_> = (16..32).collect();
assert_eq!(&buf[..], &expected[..]);
}
@@ -168,7 +175,7 @@ fn test_pwritev() {
.open(path)
.unwrap();
- let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap();
+ let written = pwritev(&file, &iovecs, 100).ok().unwrap();
assert_eq!(written, to_write.len());
// Read the data back and make sure it matches
@@ -206,7 +213,7 @@ fn test_preadv() {
.iter_mut()
.map(|buf| IoSliceMut::new(&mut buf[..]))
.collect();
- assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100));
+ assert_eq!(Ok(100), preadv(&file, &mut iovecs, 100));
}
let all = buffers.concat();
diff --git a/test/test.rs b/test/test.rs
index 6b42aad..7e73bb3 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -2,8 +2,6 @@
extern crate cfg_if;
#[cfg_attr(not(any(target_os = "redox", target_os = "haiku")), macro_use)]
extern crate nix;
-#[macro_use]
-extern crate lazy_static;
mod common;
mod sys;
@@ -66,37 +64,35 @@ mod test_unistd;
use nix::unistd::{chdir, getcwd, read};
use parking_lot::{Mutex, RwLock, RwLockWriteGuard};
-use std::os::unix::io::RawFd;
+use std::os::unix::io::{AsFd, AsRawFd};
use std::path::PathBuf;
-/// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s
-fn read_exact(f: RawFd, buf: &mut [u8]) {
+/// Helper function analogous to `std::io::Read::read_exact`, but for `Fd`s
+fn read_exact<Fd: AsFd>(f: Fd, buf: &mut [u8]) {
let mut len = 0;
while len < buf.len() {
// get_mut would be better than split_at_mut, but it requires nightly
let (_, remaining) = buf.split_at_mut(len);
- len += read(f, remaining).unwrap();
+ len += read(f.as_fd().as_raw_fd(), remaining).unwrap();
}
}
-lazy_static! {
- /// Any test that changes the process's current working directory must grab
- /// the RwLock exclusively. Any process that cares about the current
- /// working directory must grab it shared.
- pub static ref CWD_LOCK: RwLock<()> = RwLock::new(());
- /// Any test that creates child processes must grab this mutex, regardless
- /// of what it does with those children.
- pub static ref FORK_MTX: Mutex<()> = Mutex::new(());
- /// Any test that changes the process's supplementary groups must grab this
- /// mutex
- pub static ref GROUPS_MTX: Mutex<()> = Mutex::new(());
- /// Any tests that loads or unloads kernel modules must grab this mutex
- pub static ref KMOD_MTX: Mutex<()> = Mutex::new(());
- /// Any test that calls ptsname(3) must grab this mutex.
- pub static ref PTSNAME_MTX: Mutex<()> = Mutex::new(());
- /// Any test that alters signal handling must grab this mutex.
- pub static ref SIGNAL_MTX: Mutex<()> = Mutex::new(());
-}
+/// Any test that creates child processes must grab this mutex, regardless
+/// of what it does with those children.
+pub static FORK_MTX: std::sync::Mutex<()> = std::sync::Mutex::new(());
+/// Any test that changes the process's current working directory must grab
+/// the RwLock exclusively. Any process that cares about the current
+/// working directory must grab it shared.
+pub static CWD_LOCK: RwLock<()> = RwLock::new(());
+/// Any test that changes the process's supplementary groups must grab this
+/// mutex
+pub static GROUPS_MTX: Mutex<()> = Mutex::new(());
+/// Any tests that loads or unloads kernel modules must grab this mutex
+pub static KMOD_MTX: Mutex<()> = Mutex::new(());
+/// Any test that calls ptsname(3) must grab this mutex.
+pub static PTSNAME_MTX: Mutex<()> = Mutex::new(());
+/// Any test that alters signal handling must grab this mutex.
+pub static SIGNAL_MTX: Mutex<()> = Mutex::new(());
/// RAII object that restores a test's original directory on drop
struct DirRestore<'a> {
diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs
index e51044a..5fef04b 100644
--- a/test/test_fcntl.rs
+++ b/test/test_fcntl.rs
@@ -26,7 +26,7 @@ use std::io::prelude::*;
#[cfg(not(target_os = "redox"))]
use std::os::unix::fs;
#[cfg(not(target_os = "redox"))]
-use tempfile::{self, NamedTempFile};
+use tempfile::NamedTempFile;
#[test]
#[cfg(not(target_os = "redox"))]
@@ -227,6 +227,51 @@ fn test_readlink() {
);
}
+/// This test creates a temporary file containing the contents
+/// 'foobarbaz' and uses the `copy_file_range` call to transfer
+/// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The
+/// resulting file is read and should contain the contents `bar`.
+/// The from_offset should be updated by the call to reflect
+/// the 3 bytes read (6).
+#[cfg(any(
+ target_os = "linux",
+ // Not available until FreeBSD 13.0
+ all(target_os = "freebsd", fbsd14),
+ target_os = "android"
+))]
+#[test]
+// QEMU does not support copy_file_range. Skip under qemu
+#[cfg_attr(qemu, ignore)]
+fn test_copy_file_range() {
+ use nix::fcntl::copy_file_range;
+ use std::os::unix::io::AsFd;
+
+ const CONTENTS: &[u8] = b"foobarbaz";
+
+ let mut tmp1 = tempfile::tempfile().unwrap();
+ let mut tmp2 = tempfile::tempfile().unwrap();
+
+ tmp1.write_all(CONTENTS).unwrap();
+ tmp1.flush().unwrap();
+
+ let mut from_offset: i64 = 3;
+ copy_file_range(
+ tmp1.as_fd(),
+ Some(&mut from_offset),
+ tmp2.as_fd(),
+ None,
+ 3,
+ )
+ .unwrap();
+
+ let mut res: String = String::new();
+ tmp2.rewind().unwrap();
+ tmp2.read_to_string(&mut res).unwrap();
+
+ assert_eq!(res, String::from("bar"));
+ assert_eq!(from_offset, 6);
+}
+
#[cfg(any(target_os = "linux", target_os = "android"))]
mod linux_android {
use libc::loff_t;
@@ -238,47 +283,11 @@ mod linux_android {
use nix::unistd::{close, pipe, read, write};
use tempfile::tempfile;
- #[cfg(any(target_os = "linux"))]
+ #[cfg(target_os = "linux")]
use tempfile::NamedTempFile;
use crate::*;
- /// This test creates a temporary file containing the contents
- /// 'foobarbaz' and uses the `copy_file_range` call to transfer
- /// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The
- /// resulting file is read and should contain the contents `bar`.
- /// The from_offset should be updated by the call to reflect
- /// the 3 bytes read (6).
- #[test]
- // QEMU does not support copy_file_range. Skip under qemu
- #[cfg_attr(qemu, ignore)]
- fn test_copy_file_range() {
- const CONTENTS: &[u8] = b"foobarbaz";
-
- let mut tmp1 = tempfile().unwrap();
- let mut tmp2 = tempfile().unwrap();
-
- tmp1.write_all(CONTENTS).unwrap();
- tmp1.flush().unwrap();
-
- let mut from_offset: i64 = 3;
- copy_file_range(
- tmp1.as_raw_fd(),
- Some(&mut from_offset),
- tmp2.as_raw_fd(),
- None,
- 3,
- )
- .unwrap();
-
- let mut res: String = String::new();
- tmp2.rewind().unwrap();
- tmp2.read_to_string(&mut res).unwrap();
-
- assert_eq!(res, String::from("bar"));
- assert_eq!(from_offset, 6);
- }
-
#[test]
fn test_splice() {
const CONTENTS: &[u8] = b"abcdef123456";
@@ -340,7 +349,7 @@ mod linux_android {
let buf1 = b"abcdef";
let buf2 = b"defghi";
- let iovecs = vec![IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])];
+ let iovecs = [IoSlice::new(&buf1[0..3]), IoSlice::new(&buf2[0..3])];
let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap();
@@ -355,7 +364,7 @@ mod linux_android {
close(wr).unwrap();
}
- #[cfg(any(target_os = "linux"))]
+ #[cfg(target_os = "linux")]
#[test]
fn test_fallocate() {
let tmp = NamedTempFile::new().unwrap();
@@ -383,7 +392,7 @@ mod linux_android {
let tmp = NamedTempFile::new().unwrap();
let fd = tmp.as_raw_fd();
- let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap();
+ let statfs = nix::sys::statfs::fstatfs(tmp.as_file()).unwrap();
if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC {
// OverlayFS is a union file system. It returns one inode value in
// stat(2), but a different one shows up in /proc/locks. So we must
@@ -421,7 +430,7 @@ mod linux_android {
let tmp = NamedTempFile::new().unwrap();
let fd = tmp.as_raw_fd();
- let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap();
+ let statfs = nix::sys::statfs::fstatfs(tmp.as_file()).unwrap();
if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC {
// OverlayFS is a union file system. It returns one inode value in
// stat(2), but a different one shows up in /proc/locks. So we must
@@ -559,7 +568,7 @@ mod test_posix_fallocate {
let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err();
match err {
Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (),
- errno => panic!("unexpected errno {}", errno,),
+ errno => panic!("unexpected errno {errno}",),
}
}
}
diff --git a/test/test_mount.rs b/test/test_mount.rs
index 2fd612e..5cf0040 100644
--- a/test/test_mount.rs
+++ b/test/test_mount.rs
@@ -38,7 +38,7 @@ exit 23";
MsFlags::empty(),
NONE,
)
- .unwrap_or_else(|e| panic!("mount failed: {}", e));
+ .unwrap_or_else(|e| panic!("mount failed: {e}"));
let test_path = tempdir.path().join("test");
@@ -67,17 +67,17 @@ exit 23";
.unwrap();
process::exit(0);
} else {
- panic!("open failed: {}", e);
+ panic!("open failed: {e}");
}
})
.and_then(|mut f| f.write(SCRIPT_CONTENTS))
- .unwrap_or_else(|e| panic!("write failed: {}", e));
+ .unwrap_or_else(|e| panic!("write failed: {e}"));
// Verify read.
let mut buf = Vec::new();
File::open(&test_path)
.and_then(|mut f| f.read_to_end(&mut buf))
- .unwrap_or_else(|e| panic!("read failed: {}", e));
+ .unwrap_or_else(|e| panic!("read failed: {e}"));
assert_eq!(buf, SCRIPT_CONTENTS);
// Verify execute.
@@ -85,13 +85,12 @@ exit 23";
EXPECTED_STATUS,
Command::new(&test_path)
.status()
- .unwrap_or_else(|e| panic!("exec failed: {}", e))
+ .unwrap_or_else(|e| panic!("exec failed: {e}"))
.code()
.unwrap_or_else(|| panic!("child killed by signal"))
);
- umount(tempdir.path())
- .unwrap_or_else(|e| panic!("umount failed: {}", e));
+ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
}
pub fn test_mount_rdonly_disallows_write() {
@@ -104,7 +103,7 @@ exit 23";
MsFlags::MS_RDONLY,
NONE,
)
- .unwrap_or_else(|e| panic!("mount failed: {}", e));
+ .unwrap_or_else(|e| panic!("mount failed: {e}"));
// EROFS: Read-only file system
assert_eq!(
@@ -115,8 +114,7 @@ exit 23";
.unwrap()
);
- umount(tempdir.path())
- .unwrap_or_else(|e| panic!("umount failed: {}", e));
+ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
}
pub fn test_mount_noexec_disallows_exec() {
@@ -129,7 +127,7 @@ exit 23";
MsFlags::MS_NOEXEC,
NONE,
)
- .unwrap_or_else(|e| panic!("mount failed: {}", e));
+ .unwrap_or_else(|e| panic!("mount failed: {e}"));
let test_path = tempdir.path().join("test");
@@ -139,13 +137,13 @@ exit 23";
.mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
.open(&test_path)
.and_then(|mut f| f.write(SCRIPT_CONTENTS))
- .unwrap_or_else(|e| panic!("write failed: {}", e));
+ .unwrap_or_else(|e| panic!("write failed: {e}"));
// Verify that we cannot execute despite a+x permissions being set.
let mode = stat::Mode::from_bits_truncate(
fs::metadata(&test_path)
.map(|md| md.permissions().mode())
- .unwrap_or_else(|e| panic!("metadata failed: {}", e)),
+ .unwrap_or_else(|e| panic!("metadata failed: {e}")),
);
assert!(
@@ -164,8 +162,7 @@ exit 23";
.unwrap()
);
- umount(tempdir.path())
- .unwrap_or_else(|e| panic!("umount failed: {}", e));
+ umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {e}"));
}
pub fn test_mount_bind() {
@@ -182,7 +179,7 @@ exit 23";
MsFlags::MS_BIND,
NONE,
)
- .unwrap_or_else(|e| panic!("mount failed: {}", e));
+ .unwrap_or_else(|e| panic!("mount failed: {e}"));
fs::OpenOptions::new()
.create(true)
@@ -190,10 +187,10 @@ exit 23";
.mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
.open(mount_point.path().join(file_name))
.and_then(|mut f| f.write(SCRIPT_CONTENTS))
- .unwrap_or_else(|e| panic!("write failed: {}", e));
+ .unwrap_or_else(|e| panic!("write failed: {e}"));
umount(mount_point.path())
- .unwrap_or_else(|e| panic!("umount failed: {}", e));
+ .unwrap_or_else(|e| panic!("umount failed: {e}"));
}
// Verify the file written in the mount shows up in source directory, even
@@ -202,7 +199,7 @@ exit 23";
let mut buf = Vec::new();
File::open(tempdir.path().join(file_name))
.and_then(|mut f| f.read_to_end(&mut buf))
- .unwrap_or_else(|e| panic!("read failed: {}", e));
+ .unwrap_or_else(|e| panic!("read failed: {e}"));
assert_eq!(buf, SCRIPT_CONTENTS);
}
@@ -214,8 +211,7 @@ exit 23";
let stderr = io::stderr();
let mut handle = stderr.lock();
writeln!(handle,
- "unshare failed: {}. Are unprivileged user namespaces available?",
- e).unwrap();
+ "unshare failed: {e}. Are unprivileged user namespaces available?").unwrap();
writeln!(handle, "mount is not being tested").unwrap();
// Exit with success because not all systems support unprivileged user namespaces, and
// that's not what we're testing for.
@@ -226,8 +222,8 @@ exit 23";
fs::OpenOptions::new()
.write(true)
.open("/proc/self/uid_map")
- .and_then(|mut f| f.write(format!("1000 {} 1\n", uid).as_bytes()))
- .unwrap_or_else(|e| panic!("could not write uid map: {}", e));
+ .and_then(|mut f| f.write(format!("1000 {uid} 1\n").as_bytes()))
+ .unwrap_or_else(|e| panic!("could not write uid map: {e}"));
}
}
diff --git a/test/test_mq.rs b/test/test_mq.rs
index 7b48e7a..1fd8929 100644
--- a/test/test_mq.rs
+++ b/test/test_mq.rs
@@ -1,11 +1,14 @@
use cfg_if::cfg_if;
-use std::ffi::CString;
use std::str;
use nix::errno::Errno;
-use nix::mqueue::{mq_attr_member_t, mq_close, mq_open, mq_receive, mq_send};
+use nix::mqueue::{
+ mq_attr_member_t, mq_close, mq_open, mq_receive, mq_send, mq_timedreceive,
+};
use nix::mqueue::{MQ_OFlag, MqAttr};
use nix::sys::stat::Mode;
+use nix::sys::time::{TimeSpec, TimeValLike};
+use nix::time::{clock_gettime, ClockId};
// Defined as a macro such that the error source is reported as the caller's location.
macro_rules! assert_attr_eq {
@@ -30,7 +33,7 @@ macro_rules! assert_attr_eq {
fn test_mq_send_and_receive() {
const MSG_SIZE: mq_attr_member_t = 32;
let attr = MqAttr::new(0, 10, MSG_SIZE, 0);
- let mq_name = &CString::new(b"/a_nix_test_queue".as_ref()).unwrap();
+ let mq_name = "/a_nix_test_queue";
let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
@@ -56,11 +59,42 @@ fn test_mq_send_and_receive() {
}
#[test]
+fn test_mq_timedreceive() {
+ const MSG_SIZE: mq_attr_member_t = 32;
+ let attr = MqAttr::new(0, 10, MSG_SIZE, 0);
+ let mq_name = "/a_nix_test_queue";
+
+ let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
+ let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
+ let r0 = mq_open(mq_name, oflag0, mode, Some(&attr));
+ if let Err(Errno::ENOSYS) = r0 {
+ println!("message queues not supported or module not loaded?");
+ return;
+ };
+ let mqd0 = r0.unwrap();
+ let msg_to_send = "msg_1";
+ mq_send(&mqd0, msg_to_send.as_bytes(), 1).unwrap();
+
+ let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY;
+ let mqd1 = mq_open(mq_name, oflag1, mode, Some(&attr)).unwrap();
+ let mut buf = [0u8; 32];
+ let mut prio = 0u32;
+ let abstime =
+ clock_gettime(ClockId::CLOCK_REALTIME).unwrap() + TimeSpec::seconds(1);
+ let len = mq_timedreceive(&mqd1, &mut buf, &mut prio, &abstime).unwrap();
+ assert_eq!(prio, 1);
+
+ mq_close(mqd1).unwrap();
+ mq_close(mqd0).unwrap();
+ assert_eq!(msg_to_send, str::from_utf8(&buf[0..len]).unwrap());
+}
+
+#[test]
fn test_mq_getattr() {
use nix::mqueue::mq_getattr;
const MSG_SIZE: mq_attr_member_t = 32;
let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
- let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
+ let mq_name = "/attr_test_get_attr";
let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
@@ -85,7 +119,7 @@ fn test_mq_setattr() {
use nix::mqueue::{mq_getattr, mq_setattr};
const MSG_SIZE: mq_attr_member_t = 32;
let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
- let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
+ let mq_name = "/attr_test_get_attr";
let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
@@ -135,7 +169,7 @@ fn test_mq_set_nonblocking() {
use nix::mqueue::{mq_getattr, mq_remove_nonblock, mq_set_nonblock};
const MSG_SIZE: mq_attr_member_t = 32;
let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
- let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
+ let mq_name = "/attr_test_get_attr";
let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
@@ -159,10 +193,9 @@ fn test_mq_unlink() {
use nix::mqueue::mq_unlink;
const MSG_SIZE: mq_attr_member_t = 32;
let initial_attr = MqAttr::new(0, 10, MSG_SIZE, 0);
- let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap();
+ let mq_name_opened = "/mq_unlink_test";
#[cfg(not(any(target_os = "dragonfly", target_os = "netbsd")))]
- let mq_name_not_opened =
- &CString::new(b"/mq_unlink_test".as_ref()).unwrap();
+ let mq_name_not_opened = "/mq_unlink_test";
let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
let r = mq_open(mq_name_opened, oflag, mode, Some(&initial_attr));
diff --git a/test/test_poll.rs b/test/test_poll.rs
index 53964e2..045ccd3 100644
--- a/test/test_poll.rs
+++ b/test/test_poll.rs
@@ -1,8 +1,9 @@
use nix::{
errno::Errno,
poll::{poll, PollFd, PollFlags},
- unistd::{pipe, write},
+ unistd::{close, pipe, write},
};
+use std::os::unix::io::{BorrowedFd, FromRawFd, OwnedFd};
macro_rules! loop_while_eintr {
($poll_expr: expr) => {
@@ -19,7 +20,8 @@ macro_rules! loop_while_eintr {
#[test]
fn test_poll() {
let (r, w) = pipe().unwrap();
- let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
+ let r = unsafe { OwnedFd::from_raw_fd(r) };
+ let mut fds = [PollFd::new(&r, PollFlags::POLLIN)];
// Poll an idle pipe. Should timeout
let nfds = loop_while_eintr!(poll(&mut fds, 100));
@@ -32,6 +34,7 @@ fn test_poll() {
let nfds = poll(&mut fds, 100).unwrap();
assert_eq!(nfds, 1);
assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
+ close(w).unwrap();
}
// ppoll(2) is the same as poll except for how it handles timeouts and signals.
@@ -51,7 +54,8 @@ fn test_ppoll() {
let timeout = TimeSpec::milliseconds(1);
let (r, w) = pipe().unwrap();
- let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
+ let r = unsafe { OwnedFd::from_raw_fd(r) };
+ let mut fds = [PollFd::new(&r, PollFlags::POLLIN)];
// Poll an idle pipe. Should timeout
let sigset = SigSet::empty();
@@ -65,19 +69,13 @@ fn test_ppoll() {
let nfds = ppoll(&mut fds, Some(timeout), None).unwrap();
assert_eq!(nfds, 1);
assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
-}
-
-#[test]
-fn test_pollfd_fd() {
- use std::os::unix::io::AsRawFd;
-
- let pfd = PollFd::new(0x1234, PollFlags::empty());
- assert_eq!(pfd.as_raw_fd(), 0x1234);
+ close(w).unwrap();
}
#[test]
fn test_pollfd_events() {
- let mut pfd = PollFd::new(-1, PollFlags::POLLIN);
+ let fd_zero = unsafe { BorrowedFd::borrow_raw(0) };
+ let mut pfd = PollFd::new(&fd_zero, PollFlags::POLLIN);
assert_eq!(pfd.events(), PollFlags::POLLIN);
pfd.set_events(PollFlags::POLLOUT);
assert_eq!(pfd.events(), PollFlags::POLLOUT);
diff --git a/test/test_pty.rs b/test/test_pty.rs
index 5c27e2d..4cc6620 100644
--- a/test/test_pty.rs
+++ b/test/test_pty.rs
@@ -2,28 +2,13 @@ use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::prelude::*;
use std::path::Path;
-use tempfile::tempfile;
use libc::{_exit, STDOUT_FILENO};
use nix::fcntl::{open, OFlag};
use nix::pty::*;
use nix::sys::stat;
use nix::sys::termios::*;
-use nix::unistd::{close, pause, write};
-
-/// Regression test for Issue #659
-/// This is the correct way to explicitly close a `PtyMaster`
-#[test]
-fn test_explicit_close() {
- let mut f = {
- let m = posix_openpt(OFlag::O_RDWR).unwrap();
- close(m.into_raw_fd()).unwrap();
- tempfile().unwrap()
- };
- // This should work. But if there's been a double close, then it will
- // return EBADF
- f.write_all(b"whatever").unwrap();
-}
+use nix::unistd::{pause, write};
/// Test equivalence of `ptsname` and `ptsname_r`
#[test]
@@ -50,7 +35,6 @@ fn test_ptsname_copy() {
// Open a new PTTY master
let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
- assert!(master_fd.as_raw_fd() > 0);
// Get the name of the slave
let slave_name1 = unsafe { ptsname(&master_fd) }.unwrap();
@@ -67,7 +51,6 @@ fn test_ptsname_copy() {
fn test_ptsname_r_copy() {
// Open a new PTTY master
let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
- assert!(master_fd.as_raw_fd() > 0);
// Get the name of the slave
let slave_name1 = ptsname_r(&master_fd).unwrap();
@@ -84,11 +67,9 @@ fn test_ptsname_unique() {
// Open a new PTTY master
let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap();
- assert!(master1_fd.as_raw_fd() > 0);
// Open a second PTTY master
let master2_fd = posix_openpt(OFlag::O_RDWR).unwrap();
- assert!(master2_fd.as_raw_fd() > 0);
// Get the name of the slave
let slave_name1 = unsafe { ptsname(&master1_fd) }.unwrap();
@@ -147,26 +128,24 @@ fn open_ptty_pair() -> (PtyMaster, File) {
///
/// This uses a common `open_ptty_pair` because much of these functions aren't useful by
/// themselves. So for this test we perform the basic act of getting a file handle for a
-/// master/slave PTTY pair, then just sanity-check the raw values.
+/// master/slave PTTY pair.
#[test]
fn test_open_ptty_pair() {
- let (master, slave) = open_ptty_pair();
- assert!(master.as_raw_fd() > 0);
- assert!(slave.as_raw_fd() > 0);
+ let (_, _) = open_ptty_pair();
}
/// Put the terminal in raw mode.
-fn make_raw(fd: RawFd) {
- let mut termios = tcgetattr(fd).unwrap();
+fn make_raw<Fd: AsFd>(fd: Fd) {
+ let mut termios = tcgetattr(&fd).unwrap();
cfmakeraw(&mut termios);
- tcsetattr(fd, SetArg::TCSANOW, &termios).unwrap();
+ tcsetattr(&fd, SetArg::TCSANOW, &termios).unwrap();
}
/// Test `io::Read` on the PTTY master
#[test]
fn test_read_ptty_pair() {
let (mut master, mut slave) = open_ptty_pair();
- make_raw(slave.as_raw_fd());
+ make_raw(&slave);
let mut buf = [0u8; 5];
slave.write_all(b"hello").unwrap();
@@ -183,7 +162,7 @@ fn test_read_ptty_pair() {
#[test]
fn test_write_ptty_pair() {
let (mut master, mut slave) = open_ptty_pair();
- make_raw(slave.as_raw_fd());
+ make_raw(&slave);
let mut buf = [0u8; 5];
master.write_all(b"adios").unwrap();
@@ -202,33 +181,28 @@ fn test_openpty() {
let _m = crate::PTSNAME_MTX.lock();
let pty = openpty(None, None).unwrap();
- assert!(pty.master > 0);
- assert!(pty.slave > 0);
// Writing to one should be readable on the other one
let string = "foofoofoo\n";
let mut buf = [0u8; 10];
- write(pty.master, string.as_bytes()).unwrap();
- crate::read_exact(pty.slave, &mut buf);
+ write(pty.master.as_raw_fd(), string.as_bytes()).unwrap();
+ crate::read_exact(&pty.slave, &mut buf);
assert_eq!(&buf, string.as_bytes());
// Read the echo as well
let echoed_string = "foofoofoo\r\n";
let mut buf = [0u8; 11];
- crate::read_exact(pty.master, &mut buf);
+ crate::read_exact(&pty.master, &mut buf);
assert_eq!(&buf, echoed_string.as_bytes());
let string2 = "barbarbarbar\n";
let echoed_string2 = "barbarbarbar\r\n";
let mut buf = [0u8; 14];
- write(pty.slave, string2.as_bytes()).unwrap();
- crate::read_exact(pty.master, &mut buf);
+ write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap();
+ crate::read_exact(&pty.master, &mut buf);
assert_eq!(&buf, echoed_string2.as_bytes());
-
- close(pty.master).unwrap();
- close(pty.slave).unwrap();
}
#[test]
@@ -239,44 +213,34 @@ fn test_openpty_with_termios() {
// Open one pty to get attributes for the second one
let mut termios = {
let pty = openpty(None, None).unwrap();
- assert!(pty.master > 0);
- assert!(pty.slave > 0);
- let termios = tcgetattr(pty.slave).unwrap();
- close(pty.master).unwrap();
- close(pty.slave).unwrap();
- termios
+ tcgetattr(&pty.slave).unwrap()
};
// Make sure newlines are not transformed so the data is preserved when sent.
termios.output_flags.remove(OutputFlags::ONLCR);
let pty = openpty(None, &termios).unwrap();
// Must be valid file descriptors
- assert!(pty.master > 0);
- assert!(pty.slave > 0);
// Writing to one should be readable on the other one
let string = "foofoofoo\n";
let mut buf = [0u8; 10];
- write(pty.master, string.as_bytes()).unwrap();
- crate::read_exact(pty.slave, &mut buf);
+ write(pty.master.as_raw_fd(), string.as_bytes()).unwrap();
+ crate::read_exact(&pty.slave, &mut buf);
assert_eq!(&buf, string.as_bytes());
// read the echo as well
let echoed_string = "foofoofoo\n";
- crate::read_exact(pty.master, &mut buf);
+ crate::read_exact(&pty.master, &mut buf);
assert_eq!(&buf, echoed_string.as_bytes());
let string2 = "barbarbarbar\n";
let echoed_string2 = "barbarbarbar\n";
let mut buf = [0u8; 13];
- write(pty.slave, string2.as_bytes()).unwrap();
- crate::read_exact(pty.master, &mut buf);
+ write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap();
+ crate::read_exact(&pty.master, &mut buf);
assert_eq!(&buf, echoed_string2.as_bytes());
-
- close(pty.master).unwrap();
- close(pty.slave).unwrap();
}
#[test]
@@ -303,11 +267,10 @@ fn test_forkpty() {
Parent { child } => {
let mut buf = [0u8; 10];
assert!(child.as_raw() > 0);
- crate::read_exact(pty.master, &mut buf);
+ crate::read_exact(&pty.master, &mut buf);
kill(child, SIGTERM).unwrap();
wait().unwrap(); // keep other tests using generic wait from getting our child
assert_eq!(&buf, echoed_string.as_bytes());
- close(pty.master).unwrap();
}
}
}
diff --git a/test/test_ptymaster_drop.rs b/test/test_ptymaster_drop.rs
deleted file mode 100644
index ffbaa56..0000000
--- a/test/test_ptymaster_drop.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
-mod t {
- use nix::fcntl::OFlag;
- use nix::pty::*;
- use nix::unistd::close;
- use std::os::unix::io::AsRawFd;
-
- /// Regression test for Issue #659
- ///
- /// `PtyMaster` should panic rather than double close the file descriptor
- /// This must run in its own test process because it deliberately creates a
- /// race condition.
- #[test]
- #[should_panic(expected = "Closing an invalid file descriptor!")]
- fn test_double_close() {
- let m = posix_openpt(OFlag::O_RDWR).unwrap();
- close(m.as_raw_fd()).unwrap();
- drop(m); // should panic here
- }
-}
diff --git a/test/test_sendfile.rs b/test/test_sendfile.rs
index f73a3b5..b85e030 100644
--- a/test/test_sendfile.rs
+++ b/test/test_sendfile.rs
@@ -1,5 +1,6 @@
use std::io::prelude::*;
-use std::os::unix::prelude::*;
+#[cfg(any(target_os = "android", target_os = "linux"))]
+use std::os::unix::io::{FromRawFd, OwnedFd};
use libc::off_t;
use nix::sys::sendfile::*;
@@ -23,7 +24,12 @@ fn test_sendfile_linux() {
let (rd, wr) = pipe().unwrap();
let mut offset: off_t = 5;
- let res = sendfile(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap();
+ // The construct of this `OwnedFd` is a temporary workaround, when `pipe(2)`
+ // becomes I/O-safe:
+ // pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error>
+ // then it is no longer needed.
+ let wr = unsafe { OwnedFd::from_raw_fd(wr) };
+ let res = sendfile(&wr, &tmp, Some(&mut offset), 2).unwrap();
assert_eq!(2, res);
@@ -33,7 +39,6 @@ fn test_sendfile_linux() {
assert_eq!(7, offset);
close(rd).unwrap();
- close(wr).unwrap();
}
#[cfg(target_os = "linux")]
@@ -45,7 +50,12 @@ fn test_sendfile64_linux() {
let (rd, wr) = pipe().unwrap();
let mut offset: libc::off64_t = 5;
- let res = sendfile64(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap();
+ // The construct of this `OwnedFd` is a temporary workaround, when `pipe(2)`
+ // becomes I/O-safe:
+ // pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error>
+ // then it is no longer needed.
+ let wr = unsafe { OwnedFd::from_raw_fd(wr) };
+ let res = sendfile64(&wr, &tmp, Some(&mut offset), 2).unwrap();
assert_eq!(2, res);
@@ -55,7 +65,6 @@ fn test_sendfile64_linux() {
assert_eq!(7, offset);
close(rd).unwrap();
- close(wr).unwrap();
}
#[cfg(target_os = "freebsd")]
@@ -63,10 +72,10 @@ fn test_sendfile64_linux() {
fn test_sendfile_freebsd() {
// Declare the content
let header_strings =
- vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
+ ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
let body = "Xabcdef123456";
let body_offset = 1;
- let trailer_strings = vec!["\n", "Served by Make Believe\n"];
+ let trailer_strings = ["\n", "Served by Make Believe\n"];
// Write the body to a file
let mut tmp = tempfile().unwrap();
@@ -83,8 +92,8 @@ fn test_sendfile_freebsd() {
// Call the test method
let (res, bytes_written) = sendfile(
- tmp.as_raw_fd(),
- wr.as_raw_fd(),
+ &tmp,
+ &wr,
body_offset as off_t,
None,
Some(headers.as_slice()),
@@ -114,10 +123,10 @@ fn test_sendfile_freebsd() {
fn test_sendfile_dragonfly() {
// Declare the content
let header_strings =
- vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
+ ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
let body = "Xabcdef123456";
let body_offset = 1;
- let trailer_strings = vec!["\n", "Served by Make Believe\n"];
+ let trailer_strings = ["\n", "Served by Make Believe\n"];
// Write the body to a file
let mut tmp = tempfile().unwrap();
@@ -134,8 +143,8 @@ fn test_sendfile_dragonfly() {
// Call the test method
let (res, bytes_written) = sendfile(
- tmp.as_raw_fd(),
- wr.as_raw_fd(),
+ &tmp,
+ &wr,
body_offset as off_t,
None,
Some(headers.as_slice()),
@@ -183,8 +192,8 @@ fn test_sendfile_darwin() {
// Call the test method
let (res, bytes_written) = sendfile(
- tmp.as_raw_fd(),
- wr.as_raw_fd(),
+ &tmp,
+ &wr,
body_offset as off_t,
None,
Some(headers.as_slice()),
diff --git a/test/test_unistd.rs b/test/test_unistd.rs
index 9e20f97..10284e4 100644
--- a/test/test_unistd.rs
+++ b/test/test_unistd.rs
@@ -56,11 +56,11 @@ fn test_fork_and_waitpid() {
// panic, must never happen
s @ Ok(_) => {
- panic!("Child exited {:?}, should never happen", s)
+ panic!("Child exited {s:?}, should never happen")
}
// panic, waitpid should never fail
- Err(s) => panic!("Error: waitpid returned Err({:?}", s),
+ Err(s) => panic!("Error: waitpid returned Err({s:?}"),
}
}
}
@@ -94,7 +94,7 @@ fn test_mkstemp() {
close(fd).unwrap();
unlink(path.as_path()).unwrap();
}
- Err(e) => panic!("mkstemp failed: {}", e),
+ Err(e) => panic!("mkstemp failed: {e}"),
}
}
@@ -555,16 +555,13 @@ fn test_lseek() {
const CONTENTS: &[u8] = b"abcdef123456";
let mut tmp = tempfile().unwrap();
tmp.write_all(CONTENTS).unwrap();
- let tmpfd = tmp.into_raw_fd();
let offset: off_t = 5;
- lseek(tmpfd, offset, Whence::SeekSet).unwrap();
+ lseek(tmp.as_raw_fd(), offset, Whence::SeekSet).unwrap();
let mut buf = [0u8; 7];
- crate::read_exact(tmpfd, &mut buf);
+ crate::read_exact(&tmp, &mut buf);
assert_eq!(b"f123456", &buf);
-
- close(tmpfd).unwrap();
}
#[cfg(any(target_os = "linux", target_os = "android"))]
@@ -573,15 +570,12 @@ fn test_lseek64() {
const CONTENTS: &[u8] = b"abcdef123456";
let mut tmp = tempfile().unwrap();
tmp.write_all(CONTENTS).unwrap();
- let tmpfd = tmp.into_raw_fd();
- lseek64(tmpfd, 5, Whence::SeekSet).unwrap();
+ lseek64(tmp.as_raw_fd(), 5, Whence::SeekSet).unwrap();
let mut buf = [0u8; 7];
- crate::read_exact(tmpfd, &mut buf);
+ crate::read_exact(&tmp, &mut buf);
assert_eq!(b"f123456", &buf);
-
- close(tmpfd).unwrap();
}
cfg_if! {
@@ -778,15 +772,12 @@ fn test_ftruncate() {
let tempdir = tempdir().unwrap();
let path = tempdir.path().join("file");
- let tmpfd = {
- let mut tmp = File::create(&path).unwrap();
- const CONTENTS: &[u8] = b"12345678";
- tmp.write_all(CONTENTS).unwrap();
- tmp.into_raw_fd()
- };
+ let mut file = File::create(&path).unwrap();
+ const CONTENTS: &[u8] = b"12345678";
+ file.write_all(CONTENTS).unwrap();
- ftruncate(tmpfd, 2).unwrap();
- close(tmpfd).unwrap();
+ ftruncate(&file, 2).unwrap();
+ drop(file);
let metadata = fs::metadata(&path).unwrap();
assert_eq!(2, metadata.len());
@@ -799,12 +790,7 @@ static mut ALARM_CALLED: bool = false;
// Used in `test_alarm`.
#[cfg(not(target_os = "redox"))]
pub extern "C" fn alarm_signal_handler(raw_signal: libc::c_int) {
- assert_eq!(
- raw_signal,
- libc::SIGALRM,
- "unexpected signal: {}",
- raw_signal
- );
+ assert_eq!(raw_signal, libc::SIGALRM, "unexpected signal: {raw_signal}");
unsafe { ALARM_CALLED = true };
}