aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Galenson <jgalenson@google.com>2021-04-05 21:35:15 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-04-05 21:35:15 +0000
commit720f2e28efe9e2c2feec310517bcc1c91f8d8ec8 (patch)
tree26dcc75506c099ec150c6790879c824b6e4b1016
parentd0ce284484644b412e1f8e57be94f291d48362ec (diff)
parente0d64e1271234a1c646273626b7513d3189d767d (diff)
downloadnix-720f2e28efe9e2c2feec310517bcc1c91f8d8ec8.tar.gz
Upgrade rust/crates/nix to 0.20.0 am: 4727c11bc6 am: e0d64e1271
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/nix/+/1662521 Change-Id: I365944d87eb43e57860b0fe1cf546374a6fac124
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.cirrus.yml24
-rw-r--r--Android.bp5
-rw-r--r--CHANGELOG.md41
-rw-r--r--CONTRIBUTING.md10
-rw-r--r--Cargo.toml12
-rw-r--r--Cargo.toml.orig24
-rw-r--r--METADATA10
-rw-r--r--README.md9
-rw-r--r--TEST_MAPPING6
-rw-r--r--src/dir.rs86
-rw-r--r--src/errno.rs192
-rw-r--r--src/fcntl.rs4
-rw-r--r--src/features.rs2
-rw-r--r--src/lib.rs2
-rw-r--r--src/mqueue.rs21
-rw-r--r--src/pty.rs2
-rw-r--r--src/sys/mman.rs35
-rw-r--r--src/sys/mod.rs3
-rw-r--r--src/sys/personality.rs70
-rw-r--r--src/sys/signal.rs61
-rw-r--r--src/sys/signalfd.rs7
-rw-r--r--src/sys/socket/addr.rs8
-rw-r--r--src/sys/socket/mod.rs37
-rw-r--r--src/sys/socket/sockopt.rs2
-rw-r--r--src/sys/statfs.rs175
-rw-r--r--src/sys/sysinfo.rs8
-rw-r--r--src/sys/time.rs28
-rw-r--r--src/sys/timerfd.rs17
-rw-r--r--src/sys/wait.rs38
-rw-r--r--src/time.rs2
-rw-r--r--src/unistd.rs66
-rw-r--r--test/common/mod.rs127
-rw-r--r--test/sys/mod.rs4
-rw-r--r--test/sys/test_aio.rs10
-rw-r--r--test/sys/test_aio_drop.rs1
-rw-r--r--test/sys/test_mman.rs80
-rw-r--r--test/sys/test_ptrace.rs12
-rw-r--r--test/sys/test_signal.rs1
-rw-r--r--test/sys/test_socket.rs87
-rw-r--r--test/sys/test_sockopt.rs2
-rw-r--r--test/sys/test_uio.rs1
-rw-r--r--test/sys/test_wait.rs1
-rw-r--r--test/test.rs109
-rw-r--r--test/test_dir.rs2
-rw-r--r--test/test_fcntl.rs6
-rw-r--r--test/test_kmod/mod.rs1
-rw-r--r--test/test_mount.rs3
-rw-r--r--test/test_mq.rs18
-rw-r--r--test/test_poll.rs25
-rw-r--r--test/test_ptymaster_drop.rs2
-rw-r--r--test/test_unistd.rs134
52 files changed, 1140 insertions, 495 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 35cd54b..82a8727 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "c8e8deff0e26a05165e66db17732794c2cd67324"
+ "sha1": "4c7021787a174493bf1abb90a711d7464e6c80f6"
}
}
diff --git a/.cirrus.yml b/.cirrus.yml
deleted file mode 100644
index 3591c0e..0000000
--- a/.cirrus.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-freebsd_instance:
- image: freebsd-11-4-release-amd64
-
-# Test FreeBSD in a full VM on cirrus-ci.com. Test the i686 target too, in the
-# same VM. The binary will be built in 32-bit mode, but will execute on a
-# 64-bit kernel and in a 64-bit environment. Our tests don't execute any of
-# the system's binaries, so the environment shouldn't matter.
-task:
- name: FreeBSD 11.4
- cargo_cache:
- folder: $CARGO_HOME/registry
- fingerprint_script: cat Cargo.lock || echo ""
- # Install Rust
- setup_script:
- - fetch https://sh.rustup.rs -o rustup.sh
- - sh rustup.sh -y --profile=minimal --default-toolchain 1.36.0
- - $HOME/.cargo/bin/rustup target add i686-unknown-freebsd
- amd64_test_script:
- - . $HOME/.cargo/env
- - cargo test
- i386_test_script:
- - . $HOME/.cargo/env
- - cargo test --target i686-unknown-freebsd
- before_cache_script: rm -rf $CARGO_HOME/registry/index
diff --git a/Android.bp b/Android.bp
index affc10e..03f16a5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,7 +23,6 @@ license {
rust_library {
name: "libnix",
- // has rustc warnings
host_supported: true,
crate_name: "nix",
srcs: ["src/lib.rs"],
@@ -41,5 +40,5 @@ rust_library {
// dependent_library ["feature_list"]
// bitflags-1.2.1 "default"
-// cfg-if-0.1.10
-// libc-0.2.89 "default,extra_traits,std"
+// cfg-if-1.0.0
+// libc-0.2.92 "default,extra_traits,std"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e018ab2..1297ba7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,12 +3,49 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
-## [Unreleased] - ReleaseDate
+## [0.20.0] - 20 February 2021
### Added
+
+- Added a `passwd` field to `Group` (#[1338](https://github.com/nix-rust/nix/pull/1338))
+- Added `mremap` (#[1306](https://github.com/nix-rust/nix/pull/1306))
+- Added `personality` (#[1331](https://github.com/nix-rust/nix/pull/1331))
+- Added limited Fuchsia support (#[1285](https://github.com/nix-rust/nix/pull/1285))
+- Added `getpeereid` (#[1342](https://github.com/nix-rust/nix/pull/1342))
+- Implemented `IntoIterator` for `Dir`
+ (#[1333](https://github.com/nix-rust/nix/pull/1333)).
+
### Changed
+
+- Minimum supported Rust version is now 1.40.0.
+ ([#1356](https://github.com/nix-rust/nix/pull/1356))
+- i686-apple-darwin has been demoted to Tier 2 support, because it's deprecated
+ by Xcode.
+ (#[1350](https://github.com/nix-rust/nix/pull/1350))
+- Fixed calling `recvfrom` on an `AddrFamily::Packet` socket
+ (#[1344](https://github.com/nix-rust/nix/pull/1344))
+
### Fixed
+- `TimerFd` now closes the underlying fd on drop.
+ ([#1381](https://github.com/nix-rust/nix/pull/1381))
+- Define `*_MAGIC` filesystem constants on Linux s390x
+ (#[1372](https://github.com/nix-rust/nix/pull/1372))
+- mqueue, sysinfo, timespec, statfs, test_ptrace_syscall() on x32
+ (#[1366](https://github.com/nix-rust/nix/pull/1366))
+
### Removed
+- `Dir`, `SignalFd`, and `PtyMaster` are no longer `Clone`.
+ (#[1382](https://github.com/nix-rust/nix/pull/1382))
+- Removed `SockLevel`, which hasn't been used for a few years
+ (#[1362](https://github.com/nix-rust/nix/pull/1362))
+- Removed both `Copy` and `Clone` from `TimerFd`.
+ ([#1381](https://github.com/nix-rust/nix/pull/1381))
+
+## [0.19.1] - 28 November 2020
+### Fixed
+- Fixed bugs in `recvmmsg`.
+ (#[1341](https://github.com/nix-rust/nix/pull/1341))
+
## [0.19.0] - 6 October 2020
### Added
- Added Netlink protocol families to the `SockProtocol` enum
@@ -52,7 +89,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Derived `Ord`, `PartialOrd` for `unistd::Pid` (#[1189](https://github.com/nix-rust/nix/pull/1189))
- Added `select::FdSet::fds` method to iterate over file descriptors in a set.
([#1207](https://github.com/nix-rust/nix/pull/1207))
-- Added support for UDP generic segmentation offload (GSO) and generic
+- Added support for UDP generic segmentation offload (GSO) and generic
receive offload (GRO) ([#1209](https://github.com/nix-rust/nix/pull/1209))
- Added support for `sendmmsg` and `recvmmsg` calls
(#[1208](https://github.com/nix-rust/nix/pull/1208))
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 03a1f63..55990c4 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -76,21 +76,21 @@ add a test that would have failed without the fix.
After you've made your change, make sure the tests pass in your development
environment. We also have [continuous integration set up on
-Travis-CI][travis-ci], which might find some issues on other platforms. The CI
+Cirrus-CI][cirrus-ci], which might find some issues on other platforms. The CI
will run once you open a pull request.
There is also infrastructure for running tests for other targets
locally. More information is available in the [CI Readme][ci-readme].
-[travis-ci]: https://travis-ci.org/nix-rust/nix
+[cirrus-ci]: https://cirrus-ci.com/github/nix-rust/nix
[ci-readme]: ci/README.md
### Disabling a test in the CI environment
Sometimes there are features that cannot be tested in the CI environment.
-To stop a test from running under CI, add `#[cfg_attr(travis, ignore)]`
-to it. Please include a comment describing the reason it shouldn't run
-under CI, and a link to an upstream issue if possible!
+To stop a test from running under CI, add `skip_if_cirrus!()` to it. Please
+describe the reason it shouldn't run under CI, and a link to an issue if
+possible!
## bors, the bot who merges all the PRs
diff --git a/Cargo.toml b/Cargo.toml
index 3f08692..0562246 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,13 +13,15 @@
[package]
edition = "2018"
name = "nix"
-version = "0.19.0"
+version = "0.20.0"
authors = ["The nix-rust Project Developers"]
-exclude = ["/.gitignore", "/.travis.yml", "/ci/*", "/Cross.toml", "/RELEASE_PROCEDURE.md", "/bors.toml"]
+exclude = ["/.gitignore", "/.cirrus.yml", "/ci/*", "/Cross.toml", "/RELEASE_PROCEDURE.md", "/bors.toml"]
description = "Rust friendly bindings to *nix APIs"
categories = ["os::unix-apis"]
license = "MIT"
repository = "https://github.com/nix-rust/nix"
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu", "aarch64-linux-android", "x86_64-apple-darwin", "aarch64-apple-ios", "x86_64-unknown-freebsd", "x86_64-unknown-openbsd", "x86_64-unknown-netbsd", "x86_64-unknown-dragonfly", "x86_64-fuchsia", "x86_64-unknown-redox"]
[[test]]
name = "test"
@@ -49,10 +51,10 @@ path = "test/test_ptymaster_drop.rs"
version = "1.1"
[dependencies.cfg-if]
-version = "0.1.10"
+version = "1.0"
[dependencies.libc]
-version = "0.2.78"
+version = "0.2.82"
features = ["extra_traits"]
[dev-dependencies.bytes]
version = "0.4.8"
@@ -69,7 +71,7 @@ version = "0.9.0"
[dev-dependencies.tempfile]
version = "3.0.5"
[target."cfg(any(target_os = \"android\", target_os = \"linux\"))".dev-dependencies.caps]
-version = "0.3.1"
+version = "0.5.1"
[target."cfg(target_os = \"dragonfly\")".build-dependencies.cc]
version = "1"
[target."cfg(target_os = \"freebsd\")".dev-dependencies.sysctl]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 31c3d71..885fa10 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -2,24 +2,38 @@
name = "nix"
description = "Rust friendly bindings to *nix APIs"
edition = "2018"
-version = "0.19.0"
+version = "0.20.0"
authors = ["The nix-rust Project Developers"]
repository = "https://github.com/nix-rust/nix"
license = "MIT"
categories = ["os::unix-apis"]
exclude = [
"/.gitignore",
- "/.travis.yml",
+ "/.cirrus.yml",
"/ci/*",
"/Cross.toml",
"/RELEASE_PROCEDURE.md",
"/bors.toml"
]
+[package.metadata.docs.rs]
+targets = [
+ "x86_64-unknown-linux-gnu",
+ "aarch64-linux-android",
+ "x86_64-apple-darwin",
+ "aarch64-apple-ios",
+ "x86_64-unknown-freebsd",
+ "x86_64-unknown-openbsd",
+ "x86_64-unknown-netbsd",
+ "x86_64-unknown-dragonfly",
+ "x86_64-fuchsia",
+ "x86_64-unknown-redox"
+]
+
[dependencies]
-libc = { version = "0.2.78", features = [ "extra_traits" ] }
+libc = { version = "0.2.82", features = [ "extra_traits" ] }
bitflags = "1.1"
-cfg-if = "0.1.10"
+cfg-if = "1.0"
[target.'cfg(target_os = "dragonfly")'.build-dependencies]
cc = "1"
@@ -32,7 +46,7 @@ tempfile = "3.0.5"
semver = "0.9.0"
[target.'cfg(any(target_os = "android", target_os = "linux"))'.dev-dependencies]
-caps = "0.3.1"
+caps = "0.5.1"
[target.'cfg(target_os = "freebsd")'.dev-dependencies]
sysctl = "0.1"
diff --git a/METADATA b/METADATA
index d8c25cb..a71ef07 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/nix/nix-0.19.0.crate"
+ value: "https://static.crates.io/crates/nix/nix-0.20.0.crate"
}
- version: "0.19.0"
+ version: "0.20.0"
license_type: NOTICE
last_upgrade_date {
- year: 2020
- month: 10
- day: 13
+ year: 2021
+ month: 4
+ day: 2
}
}
diff --git a/README.md b/README.md
index 43c47e1..167d192 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
# Rust bindings to *nix APIs
-[![Travis Build Status](https://travis-ci.org/nix-rust/nix.svg?branch=master)](https://travis-ci.org/nix-rust/nix)
[![Cirrus Build Status](https://api.cirrus-ci.com/github/nix-rust/nix.svg)](https://cirrus-ci.com/github/nix-rust/nix)
[![crates.io](http://meritbadge.herokuapp.com/nix)](https://crates.io/crates/nix)
@@ -51,7 +50,6 @@ Tier 1:
* aarch64-unknown-linux-gnu
* arm-unknown-linux-gnueabi
* armv7-unknown-linux-gnueabihf
- * i686-apple-darwin
* i686-unknown-freebsd
* i686-unknown-linux-gnu
* i686-unknown-linux-musl
@@ -74,6 +72,7 @@ Tier 2:
* armv7-linux-androideabi
* armv7s-apple-ios
* i386-apple-ios
+ * i686-apple-darwin
* i686-linux-android
* powerpc-unknown-linux-gnu
* s390x-unknown-linux-gnu
@@ -82,17 +81,19 @@ Tier 2:
* x86_64-unknown-netbsd
Tier 3:
+ * x86_64-fuchsia
* x86_64-unknown-redox
+ * x86_64-unknown-linux-gnux32
## Usage
-`nix` requires Rust 1.36.0 or newer.
+`nix` requires Rust 1.40.0 or newer.
To use `nix`, add this to your `Cargo.toml`:
```toml
[dependencies]
-nix = "0.19.0"
+nix = "0.20.0"
```
## Contributing
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 7397f01..5d7fef5 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,13 +2,13 @@
{
"presubmit": [
{
- "name": "keystore2_crypto_test_rust"
+ "name": "keystore2_test"
},
{
- "name": "vpnprofilestore_test"
+ "name": "keystore2_crypto_test_rust"
},
{
- "name": "keystore2_test"
+ "name": "vpnprofilestore_test"
}
]
}
diff --git a/src/dir.rs b/src/dir.rs
index 1d48f18..7d4ab82 100644
--- a/src/dir.rs
+++ b/src/dir.rs
@@ -25,7 +25,7 @@ use libc::{dirent, readdir_r};
/// * returns entries for `.` (current directory) and `..` (parent directory).
/// * returns entries' names as a `CStr` (no allocation or conversion beyond whatever libc
/// does).
-#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+#[derive(Debug, Eq, Hash, PartialEq)]
pub struct Dir(
ptr::NonNull<libc::DIR>
);
@@ -85,7 +85,32 @@ impl AsRawFd for Dir {
impl Drop for Dir {
fn drop(&mut self) {
- unsafe { libc::closedir(self.0.as_ptr()) };
+ let e = Errno::result(unsafe { libc::closedir(self.0.as_ptr()) });
+ if !std::thread::panicking() && e == Err(Error::Sys(Errno::EBADF)) {
+ panic!("Closing an invalid file descriptor!");
+ };
+ }
+}
+
+fn next(dir: &mut Dir) -> Option<Result<Entry>> {
+ unsafe {
+ // Note: POSIX specifies that portable applications should dynamically allocate a
+ // buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1
+ // for the NUL byte. It doesn't look like the std library does this; it just uses
+ // fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate).
+ // Probably fine here too then.
+ let mut ent = std::mem::MaybeUninit::<dirent>::uninit();
+ let mut result = ptr::null_mut();
+ if let Err(e) = Errno::result(
+ readdir_r(dir.0.as_ptr(), ent.as_mut_ptr(), &mut result))
+ {
+ return Some(Err(e));
+ }
+ if result.is_null() {
+ return None;
+ }
+ assert_eq!(result, ent.as_mut_ptr());
+ Some(Ok(Entry(ent.assume_init())))
}
}
@@ -96,25 +121,7 @@ impl<'d> Iterator for Iter<'d> {
type Item = Result<Entry>;
fn next(&mut self) -> Option<Self::Item> {
- unsafe {
- // Note: POSIX specifies that portable applications should dynamically allocate a
- // buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1
- // for the NUL byte. It doesn't look like the std library does this; it just uses
- // fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate).
- // Probably fine here too then.
- let mut ent = std::mem::MaybeUninit::<dirent>::uninit();
- let mut result = ptr::null_mut();
- if let Err(e) = Errno::result(
- readdir_r((self.0).0.as_ptr(), ent.as_mut_ptr(), &mut result))
- {
- return Some(Err(e));
- }
- if result.is_null() {
- return None;
- }
- assert_eq!(result, ent.as_mut_ptr());
- Some(Ok(Entry(ent.assume_init())))
- }
+ next(self.0)
}
}
@@ -124,6 +131,43 @@ impl<'d> Drop for Iter<'d> {
}
}
+/// The return type of [Dir::into_iter]
+#[derive(Debug, Eq, Hash, PartialEq)]
+pub struct OwningIter(Dir);
+
+impl Iterator for OwningIter {
+ type Item = Result<Entry>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ next(&mut self.0)
+ }
+}
+
+impl IntoIterator for Dir {
+ type Item = Result<Entry>;
+ type IntoIter = OwningIter;
+
+ /// Creates a owning iterator, that is, one that takes ownership of the
+ /// `Dir`. The `Dir` cannot be used after calling this. This can be useful
+ /// when you have a function that both creates a `Dir` instance and returns
+ /// an `Iterator`.
+ ///
+ /// Example:
+ ///
+ /// ```
+ /// use nix::{dir::Dir, fcntl::OFlag, sys::stat::Mode};
+ /// use std::{iter::Iterator, string::String};
+ ///
+ /// fn ls_upper(dirname: &str) -> impl Iterator<Item=String> {
+ /// let d = Dir::open(dirname, OFlag::O_DIRECTORY, Mode::S_IXUSR).unwrap();
+ /// d.into_iter().map(|x| x.unwrap().file_name().as_ref().to_string_lossy().to_ascii_uppercase())
+ /// }
+ /// ```
+ fn into_iter(self) -> Self::IntoIter {
+ OwningIter(self)
+ }
+}
+
/// A directory entry, similar to `std::fs::DirEntry`.
///
/// Note that unlike the std version, this may represent the `.` or `..` entries.
diff --git a/src/errno.rs b/src/errno.rs
index 03a7f0e..e5c7092 100644
--- a/src/errno.rs
+++ b/src/errno.rs
@@ -20,7 +20,8 @@ cfg_if! {
}
} else if #[cfg(any(target_os = "linux",
target_os = "redox",
- target_os = "dragonfly"))] {
+ target_os = "dragonfly",
+ target_os = "fuchsia"))] {
unsafe fn errno_location() -> *mut c_int {
libc::__errno_location()
}
@@ -188,192 +189,254 @@ fn desc(errno: Errno) -> &'static str {
EHOSTDOWN => "Host is down",
EHOSTUNREACH => "No route to host",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ECHRNG => "Channel number out of range",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EL2NSYNC => "Level 2 not synchronized",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EL3HLT => "Level 3 halted",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EL3RST => "Level 3 reset",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ELNRNG => "Link number out of range",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EUNATCH => "Protocol driver not attached",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENOCSI => "No CSI structure available",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EL2HLT => "Level 2 halted",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EBADE => "Invalid exchange",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EBADR => "Invalid request descriptor",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EXFULL => "Exchange full",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENOANO => "No anode",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EBADRQC => "Invalid request code",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EBADSLT => "Invalid slot",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EBFONT => "Bad font file format",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENOSTR => "Device not a stream",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENODATA => "No data available",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ETIME => "Timer expired",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENOSR => "Out of streams resources",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENONET => "Machine is not on the network",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENOPKG => "Package not installed",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EREMOTE => "Object is remote",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENOLINK => "Link has been severed",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EADV => "Advertise error",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ESRMNT => "Srmount error",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ECOMM => "Communication error on send",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EPROTO => "Protocol error",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EMULTIHOP => "Multihop attempted",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EDOTDOT => "RFS specific error",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EBADMSG => "Not a data message",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EOVERFLOW => "Value too large for defined data type",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENOTUNIQ => "Name not unique on network",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EBADFD => "File descriptor in bad state",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EREMCHG => "Remote address changed",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ELIBACC => "Can not access a needed shared library",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ELIBBAD => "Accessing a corrupted shared library",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ELIBSCN => ".lib section in a.out corrupted",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ELIBMAX => "Attempting to link in too many shared libraries",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ELIBEXEC => "Cannot exec a shared library directly",
- #[cfg(any(target_os = "linux", target_os = "android", target_os = "openbsd"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia", target_os = "openbsd"))]
EILSEQ => "Illegal byte sequence",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ERESTART => "Interrupted system call should be restarted",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ESTRPIPE => "Streams pipe error",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EUSERS => "Too many users",
#[cfg(any(target_os = "linux", target_os = "android",
- target_os = "netbsd", target_os = "redox"))]
+ target_os = "fuchsia", target_os = "netbsd",
+ target_os = "redox"))]
EOPNOTSUPP => "Operation not supported on transport endpoint",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ESTALE => "Stale file handle",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EUCLEAN => "Structure needs cleaning",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENOTNAM => "Not a XENIX named type file",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENAVAIL => "No XENIX semaphores available",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EISNAM => "Is a named type file",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EREMOTEIO => "Remote I/O error",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EDQUOT => "Quota exceeded",
#[cfg(any(target_os = "linux", target_os = "android",
- target_os = "openbsd", target_os = "dragonfly"))]
+ target_os = "fuchsia", target_os = "openbsd",
+ target_os = "dragonfly"))]
ENOMEDIUM => "No medium found",
- #[cfg(any(target_os = "linux", target_os = "android", target_os = "openbsd"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia", target_os = "openbsd"))]
EMEDIUMTYPE => "Wrong medium type",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ECANCELED => "Operation canceled",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENOKEY => "Required key not available",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EKEYEXPIRED => "Key has expired",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EKEYREVOKED => "Key has been revoked",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EKEYREJECTED => "Key was rejected by service",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
EOWNERDEAD => "Owner died",
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
ENOTRECOVERABLE => "State not recoverable",
- #[cfg(all(target_os = "linux", not(target_arch="mips")))]
+ #[cfg(any(all(target_os = "linux", not(target_arch="mips")),
+ target_os = "fuchsia"))]
ERFKILL => "Operation not possible due to RF-kill",
- #[cfg(all(target_os = "linux", not(target_arch="mips")))]
+ #[cfg(any(all(target_os = "linux", not(target_arch="mips")),
+ target_os = "fuchsia"))]
EHWPOISON => "Memory page has hardware error",
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
@@ -567,7 +630,8 @@ fn desc(errno: Errno) -> &'static str {
}
}
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "fuchsia"))]
mod consts {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(i32)]
diff --git a/src/fcntl.rs b/src/fcntl.rs
index 1581d3a..d2242da 100644
--- a/src/fcntl.rs
+++ b/src/fcntl.rs
@@ -20,7 +20,7 @@ use crate::sys::uio::IoVec; // For vmsplice
target_os = "fuchsia",
any(target_os = "wasi", target_env = "wasi"),
target_env = "uclibc",
- target_env = "freebsd"
+ target_os = "freebsd"
))]
pub use self::posix_fadvise::*;
@@ -587,7 +587,7 @@ pub fn fallocate(
target_os = "fuchsia",
any(target_os = "wasi", target_env = "wasi"),
target_env = "uclibc",
- target_env = "freebsd"
+ target_os = "freebsd"
))]
mod posix_fadvise {
use crate::errno::Errno;
diff --git a/src/features.rs b/src/features.rs
index c3a53fb..6b1cff5 100644
--- a/src/features.rs
+++ b/src/features.rs
@@ -97,7 +97,7 @@ mod os {
#[cfg(any(target_os = "macos", target_os = "freebsd",
target_os = "dragonfly", target_os = "ios",
target_os = "openbsd", target_os = "netbsd",
- target_os = "redox"))]
+ target_os = "redox", target_os = "fuchsia"))]
mod os {
/// Check if the OS supports atomic close-on-exec for sockets
pub fn socket_atomic_cloexec() -> bool {
diff --git a/src/lib.rs b/src/lib.rs
index da517b5..e62c158 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -57,7 +57,7 @@ pub mod net;
#[deny(missing_docs)]
pub mod poll;
#[deny(missing_docs)]
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
pub mod pty;
pub mod sched;
pub mod sys;
diff --git a/src/mqueue.rs b/src/mqueue.rs
index 122705a..0215de5 100644
--- a/src/mqueue.rs
+++ b/src/mqueue.rs
@@ -5,7 +5,7 @@
use crate::Result;
use crate::errno::Errno;
-use libc::{self, c_char, c_long, mqd_t, size_t};
+use libc::{self, c_char, mqd_t, size_t};
use std::ffi::CString;
use crate::sys::stat::Mode;
use std::mem;
@@ -34,11 +34,18 @@ pub struct MqAttr {
mq_attr: libc::mq_attr,
}
+// x32 compatibility
+// See https://sourceware.org/bugzilla/show_bug.cgi?id=21279
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
+pub type mq_attr_member_t = i64;
+#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
+pub type mq_attr_member_t = libc::c_long;
+
impl MqAttr {
- pub fn new(mq_flags: c_long,
- mq_maxmsg: c_long,
- mq_msgsize: c_long,
- mq_curmsgs: c_long)
+ pub fn new(mq_flags: mq_attr_member_t,
+ mq_maxmsg: mq_attr_member_t,
+ mq_msgsize: mq_attr_member_t,
+ mq_curmsgs: mq_attr_member_t)
-> MqAttr
{
let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
@@ -52,7 +59,7 @@ impl MqAttr {
}
}
- pub fn flags(&self) -> c_long {
+ pub fn flags(&self) -> mq_attr_member_t {
self.mq_attr.mq_flags
}
}
@@ -150,7 +157,7 @@ pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr> {
/// Returns the old attributes
pub fn mq_set_nonblock(mqd: mqd_t) -> Result<MqAttr> {
let oldattr = mq_getattr(mqd)?;
- let newattr = MqAttr::new(c_long::from(MQ_OFlag::O_NONBLOCK.bits()),
+ let newattr = MqAttr::new(mq_attr_member_t::from(MQ_OFlag::O_NONBLOCK.bits()),
oldattr.mq_attr.mq_maxmsg,
oldattr.mq_attr.mq_msgsize,
oldattr.mq_attr.mq_curmsgs);
diff --git a/src/pty.rs b/src/pty.rs
index 3a6a923..d67518f 100644
--- a/src/pty.rs
+++ b/src/pty.rs
@@ -43,7 +43,7 @@ pub struct ForkptyResult {
/// 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(Clone, Debug, Eq, Hash, PartialEq)]
+#[derive(Debug, Eq, Hash, PartialEq)]
pub struct PtyMaster(RawFd);
impl AsRawFd for PtyMaster {
diff --git a/src/sys/mman.rs b/src/sys/mman.rs
index b2bed6e..63a0779 100644
--- a/src/sys/mman.rs
+++ b/src/sys/mman.rs
@@ -139,6 +139,17 @@ libc_bitflags!{
}
}
+#[cfg(target_os = "linux")]
+libc_bitflags!{
+ /// Options for `mremap()`.
+ pub struct MRemapFlags: c_int {
+ /// Permit the kernel to relocate the mapping to a new virtual address, if necessary.
+ MREMAP_MAYMOVE;
+ /// Place the mapping at exactly the address specified in `new_address`.
+ MREMAP_FIXED;
+ }
+}
+
libc_enum!{
/// Usage information for a range of memory to allow for performance optimizations by the kernel.
///
@@ -315,6 +326,30 @@ pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: Ma
}
}
+/// Expands (or shrinks) an existing memory mapping, potentially moving it at
+/// the same time.
+///
+/// # Safety
+///
+/// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for
+/// detailed requirements.
+#[cfg(target_os = "linux")]
+pub unsafe fn mremap(
+ addr: *mut c_void,
+ old_size: size_t,
+ new_size: size_t,
+ flags: MRemapFlags,
+ new_address: Option<* mut c_void>,
+) -> Result<*mut c_void> {
+ let ret = libc::mremap(addr, old_size, new_size, flags.bits(), new_address.unwrap_or(std::ptr::null_mut()));
+
+ if ret == libc::MAP_FAILED {
+ Err(Error::Sys(Errno::last()))
+ } else {
+ Ok(ret)
+ }
+}
+
/// remove a mapping
///
/// # Safety
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index b8b9e6f..02edfd7 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -38,6 +38,9 @@ pub mod memfd;
#[cfg(not(target_os = "redox"))]
pub mod mman;
+#[cfg(target_os = "linux")]
+pub mod personality;
+
pub mod pthread;
#[cfg(any(target_os = "android",
diff --git a/src/sys/personality.rs b/src/sys/personality.rs
new file mode 100644
index 0000000..6548b65
--- /dev/null
+++ b/src/sys/personality.rs
@@ -0,0 +1,70 @@
+use crate::Result;
+use crate::errno::Errno;
+
+use libc::{self, c_int, c_ulong};
+
+libc_bitflags! {
+ /// Flags used and returned by [`get()`](fn.get.html) and
+ /// [`set()`](fn.set.html).
+ pub struct Persona: c_int {
+ ADDR_COMPAT_LAYOUT;
+ ADDR_NO_RANDOMIZE;
+ ADDR_LIMIT_32BIT;
+ ADDR_LIMIT_3GB;
+ #[cfg(not(target_env = "musl"))]
+ FDPIC_FUNCPTRS;
+ MMAP_PAGE_ZERO;
+ READ_IMPLIES_EXEC;
+ SHORT_INODE;
+ STICKY_TIMEOUTS;
+ #[cfg(not(target_env = "musl"))]
+ UNAME26;
+ WHOLE_SECONDS;
+ }
+}
+
+/// Retrieve the current process personality.
+///
+/// Returns a Result containing a Persona instance.
+///
+/// Example:
+///
+/// ```
+/// # use nix::sys::personality::{self, Persona};
+/// let pers = personality::get().unwrap();
+/// assert!(!pers.contains(Persona::WHOLE_SECONDS));
+/// ```
+pub fn get() -> Result<Persona> {
+ let res = unsafe {
+ libc::personality(0xFFFFFFFF)
+ };
+
+ Errno::result(res).map(|r| Persona::from_bits_truncate(r))
+}
+
+/// Set the current process personality.
+///
+/// Returns a Result containing the *previous* personality for the
+/// process, as a Persona.
+///
+/// For more information, see [personality(2)](https://man7.org/linux/man-pages/man2/personality.2.html)
+///
+/// **NOTE**: This call **replaces** the current personality entirely.
+/// To **update** the personality, first call `get()` and then `set()`
+/// with the modified persona.
+///
+/// Example:
+///
+/// ```
+/// # use nix::sys::personality::{self, Persona};
+/// let mut pers = personality::get().unwrap();
+/// assert!(!pers.contains(Persona::ADDR_NO_RANDOMIZE));
+/// personality::set(pers | Persona::ADDR_NO_RANDOMIZE);
+/// ```
+pub fn set(persona: Persona) -> Result<Persona> {
+ let res = unsafe {
+ libc::personality(persona.bits() as c_ulong)
+ };
+
+ Errno::result(res).map(|r| Persona::from_bits_truncate(r))
+}
diff --git a/src/sys/signal.rs b/src/sys/signal.rs
index 710e65f..2f8b5fa 100644
--- a/src/sys/signal.rs
+++ b/src/sys/signal.rs
@@ -39,8 +39,10 @@ libc_enum!{
SIGPIPE,
SIGALRM,
SIGTERM,
- #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
- not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
+ #[cfg(all(any(target_os = "android", target_os = "emscripten",
+ target_os = "fuchsia", target_os = "linux"),
+ not(any(target_arch = "mips", target_arch = "mips64",
+ target_arch = "sparc64"))))]
SIGSTKFLT,
SIGCHLD,
SIGCONT,
@@ -55,14 +57,17 @@ libc_enum!{
SIGPROF,
SIGWINCH,
SIGIO,
- #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "emscripten",
+ target_os = "fuchsia", target_os = "linux"))]
SIGPWR,
SIGSYS,
#[cfg(not(any(target_os = "android", target_os = "emscripten",
- target_os = "linux", target_os = "redox")))]
+ target_os = "fuchsia", target_os = "linux",
+ target_os = "redox")))]
SIGEMT,
#[cfg(not(any(target_os = "android", target_os = "emscripten",
- target_os = "linux", target_os = "redox")))]
+ target_os = "fuchsia", target_os = "linux",
+ target_os = "redox")))]
SIGINFO,
}
}
@@ -86,8 +91,10 @@ impl FromStr for Signal {
"SIGPIPE" => Signal::SIGPIPE,
"SIGALRM" => Signal::SIGALRM,
"SIGTERM" => Signal::SIGTERM,
- #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
- not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
+ #[cfg(all(any(target_os = "android", target_os = "emscripten",
+ target_os = "fuchsia", target_os = "linux"),
+ not(any(target_arch = "mips", target_arch = "mips64",
+ target_arch = "sparc64"))))]
"SIGSTKFLT" => Signal::SIGSTKFLT,
"SIGCHLD" => Signal::SIGCHLD,
"SIGCONT" => Signal::SIGCONT,
@@ -102,14 +109,17 @@ impl FromStr for Signal {
"SIGPROF" => Signal::SIGPROF,
"SIGWINCH" => Signal::SIGWINCH,
"SIGIO" => Signal::SIGIO,
- #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "emscripten",
+ target_os = "fuchsia", target_os = "linux"))]
"SIGPWR" => Signal::SIGPWR,
"SIGSYS" => Signal::SIGSYS,
#[cfg(not(any(target_os = "android", target_os = "emscripten",
- target_os = "linux", target_os = "redox")))]
+ target_os = "fuchsia", target_os = "linux",
+ target_os = "redox")))]
"SIGEMT" => Signal::SIGEMT,
#[cfg(not(any(target_os = "android", target_os = "emscripten",
- target_os = "linux", target_os = "redox")))]
+ target_os = "fuchsia", target_os = "linux",
+ target_os = "redox")))]
"SIGINFO" => Signal::SIGINFO,
_ => return Err(Error::invalid_argument()),
})
@@ -139,7 +149,8 @@ impl Signal {
Signal::SIGPIPE => "SIGPIPE",
Signal::SIGALRM => "SIGALRM",
Signal::SIGTERM => "SIGTERM",
- #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
+ #[cfg(all(any(target_os = "android", target_os = "emscripten",
+ target_os = "fuchsia", target_os = "linux"),
not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
Signal::SIGSTKFLT => "SIGSTKFLT",
Signal::SIGCHLD => "SIGCHLD",
@@ -155,14 +166,17 @@ impl Signal {
Signal::SIGPROF => "SIGPROF",
Signal::SIGWINCH => "SIGWINCH",
Signal::SIGIO => "SIGIO",
- #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "emscripten",
+ target_os = "fuchsia", target_os = "linux"))]
Signal::SIGPWR => "SIGPWR",
Signal::SIGSYS => "SIGSYS",
#[cfg(not(any(target_os = "android", target_os = "emscripten",
- target_os = "linux", target_os = "redox")))]
+ target_os = "fuchsia", target_os = "linux",
+ target_os = "redox")))]
Signal::SIGEMT => "SIGEMT",
#[cfg(not(any(target_os = "android", target_os = "emscripten",
- target_os = "linux", target_os = "redox")))]
+ target_os = "fuchsia", target_os = "linux",
+ target_os = "redox")))]
Signal::SIGINFO => "SIGINFO",
}
}
@@ -213,7 +227,10 @@ const SIGNALS: [Signal; 29] = [
SIGWINCH,
SIGIO,
SIGSYS];
-#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
+#[cfg(all(any(target_os = "linux", target_os = "android",
+ target_os = "emscripten", target_os = "fuchsia"),
+ not(any(target_arch = "mips", target_arch = "mips64",
+ target_arch = "sparc64"))))]
const SIGNALS: [Signal; 31] = [
SIGHUP,
SIGINT,
@@ -246,7 +263,10 @@ const SIGNALS: [Signal; 31] = [
SIGIO,
SIGPWR,
SIGSYS];
-#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")))]
+#[cfg(all(any(target_os = "linux", target_os = "android",
+ target_os = "emscripten", target_os = "fuchsia"),
+ any(target_arch = "mips", target_arch = "mips64",
+ target_arch = "sparc64")))]
const SIGNALS: [Signal; 30] = [
SIGHUP,
SIGINT,
@@ -279,7 +299,8 @@ const SIGNALS: [Signal; 30] = [
SIGPWR,
SIGSYS];
#[cfg(not(any(target_os = "linux", target_os = "android",
- target_os = "emscripten", target_os = "redox")))]
+ target_os = "fuchsia", target_os = "emscripten",
+ target_os = "redox")))]
const SIGNALS: [Signal; 31] = [
SIGHUP,
SIGINT,
@@ -749,6 +770,7 @@ pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
/// If `pgrp` less then or equal 1, the behavior is platform-specific.
/// If `signal` is `None`, `killpg` will only preform error checking and won't
/// send any signal.
+#[cfg(not(target_os = "fuchsia"))]
pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
let res = unsafe { libc::killpg(pgrp.into(),
match signal.into() {
@@ -829,7 +851,10 @@ mod sigevent {
/// `SIGEV_SIGNAL`. That field is part of a union that shares space with the
/// more genuinely useful `sigev_notify_thread_id`
pub fn new(sigev_notify: SigevNotify) -> SigEvent {
- let mut sev = unsafe { mem::zeroed::<libc::sigevent>()};
+ // NB: This uses MaybeUninit rather than mem::zeroed because libc::sigevent contains a
+ // function pointer on Fuchsia as of https://github.com/rust-lang/libc/commit/2f59370,
+ // and function pointers must not be null.
+ 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,
diff --git a/src/sys/signalfd.rs b/src/sys/signalfd.rs
index e3ded1f..c43b450 100644
--- a/src/sys/signalfd.rs
+++ b/src/sys/signalfd.rs
@@ -79,7 +79,7 @@ pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> {
/// Err(err) => (), // some error happend
/// }
/// ```
-#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+#[derive(Debug, Eq, Hash, PartialEq)]
pub struct SignalFd(RawFd);
impl SignalFd {
@@ -116,7 +116,10 @@ impl SignalFd {
impl Drop for SignalFd {
fn drop(&mut self) {
- let _ = unistd::close(self.0);
+ let e = unistd::close(self.0);
+ if !std::thread::panicking() && e == Err(Error::Sys(Errno::EBADF)) {
+ panic!("Closing an invalid file descriptor!");
+ };
}
}
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index 8784a37..2299c57 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -21,7 +21,8 @@ use crate::sys::socket::addr::sys_control::SysControlAddr;
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
- target_os = "openbsd"))]
+ target_os = "openbsd",
+ target_os = "fuchsia"))]
pub use self::datalink::LinkAddr;
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use self::vsock::VsockAddr;
@@ -41,7 +42,7 @@ pub enum AddressFamily {
#[cfg(any(target_os = "android", target_os = "linux"))]
Netlink = libc::AF_NETLINK,
/// Low level packet interface (see [`packet(7)`](http://man7.org/linux/man-pages/man7/packet.7.html))
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))]
Packet = libc::AF_PACKET,
/// KEXT Controls and Notifications
#[cfg(any(target_os = "ios", target_os = "macos"))]
@@ -718,6 +719,7 @@ impl SockAddr {
///
/// unsafe because it takes a raw pointer as argument. The caller must
/// ensure that the pointer is valid.
+ #[cfg(not(target_os = "fuchsia"))]
pub(crate) unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option<SockAddr> {
if addr.is_null() {
None
@@ -1045,7 +1047,7 @@ pub mod sys_control {
}
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))]
mod datalink {
use super::{fmt, AddressFamily};
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index 5e5fb8d..11ed329 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -847,12 +847,13 @@ impl<'a> ControlMessage<'a> {
}
#[cfg(any(target_os = "android", target_os = "linux"))]
ControlMessage::AlgSetIv(iv) => {
+ #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501
let af_alg_iv = libc::af_alg_iv {
ivlen: iv.len() as u32,
iv: [0u8; 0],
};
- let size = mem::size_of::<libc::af_alg_iv>();
+ let size = mem::size_of_val(&af_alg_iv);
unsafe {
ptr::copy_nonoverlapping(
@@ -915,7 +916,7 @@ impl<'a> ControlMessage<'a> {
}
#[cfg(any(target_os = "android", target_os = "linux"))]
ControlMessage::AlgSetIv(iv) => {
- mem::size_of::<libc::af_alg_iv>() + iv.len()
+ mem::size_of_val(&iv) + iv.len()
},
#[cfg(any(target_os = "android", target_os = "linux"))]
ControlMessage::AlgSetOp(op) => {
@@ -1216,17 +1217,18 @@ pub fn recvmmsg<'a, I>(
let ret = unsafe { libc::recvmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _, timeout) };
- let r = Errno::result(ret)?;
+ let _ = Errno::result(ret)?;
Ok(output
.into_iter()
+ .take(ret as usize)
.zip(addresses.iter().map(|addr| unsafe{addr.assume_init()}))
.zip(results.into_iter())
.map(|((mmsghdr, address), (msg_controllen, cmsg_buffer))| {
unsafe {
read_mhdr(
mmsghdr.msg_hdr,
- r as isize,
+ mmsghdr.msg_len as isize,
msg_controllen,
address,
cmsg_buffer
@@ -1574,24 +1576,6 @@ pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
*
*/
-/// The protocol level at which to get / set socket options. Used as an
-/// argument to `getsockopt` and `setsockopt`.
-///
-/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
-#[repr(i32)]
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-pub enum SockLevel {
- Socket = libc::SOL_SOCKET,
- Tcp = libc::IPPROTO_TCP,
- Ip = libc::IPPROTO_IP,
- Ipv6 = libc::IPPROTO_IPV6,
- Udp = libc::IPPROTO_UDP,
- #[cfg(any(target_os = "android", target_os = "linux"))]
- Netlink = libc::SOL_NETLINK,
- #[cfg(any(target_os = "android", target_os = "linux"))]
- Alg = libc::SOL_ALG,
-}
-
/// Represents a socket option that can be accessed or set. Used as an argument
/// to `getsockopt`
pub trait GetSockOpt : Copy {
@@ -1718,6 +1702,15 @@ pub fn sockaddr_storage_to_addr(
Ok(SockAddr::Unix(UnixAddr(sun, pathlen)))
}
#[cfg(any(target_os = "android", target_os = "linux"))]
+ libc::AF_PACKET => {
+ use libc::sockaddr_ll;
+ assert_eq!(len as usize, mem::size_of::<sockaddr_ll>());
+ let sll = unsafe {
+ *(addr as *const _ as *const sockaddr_ll)
+ };
+ Ok(SockAddr::Link(LinkAddr(sll)))
+ }
+ #[cfg(any(target_os = "android", target_os = "linux"))]
libc::AF_NETLINK => {
use libc::sockaddr_nl;
let snl = unsafe {
diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs
index e41a472..5b7b4fe 100644
--- a/src/sys/socket/sockopt.rs
+++ b/src/sys/socket/sockopt.rs
@@ -252,7 +252,9 @@ sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
target_os = "linux",
target_os = "nacl"))]
sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
+#[cfg(not(target_os = "openbsd"))]
sockopt_impl!(Both, TcpKeepCount, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32);
+#[cfg(not(target_os = "openbsd"))]
sockopt_impl!(Both, TcpKeepInterval, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32);
sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs
index 8e90a58..27b7259 100644
--- a/src/sys/statfs.rs
+++ b/src/sys/statfs.rs
@@ -16,79 +16,85 @@ pub type fsid_t = libc::fsid_t;
pub struct Statfs(libc::statfs);
#[cfg(target_os = "freebsd")]
-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
-pub struct FsType(pub u32);
+type fs_type_t = u32;
#[cfg(target_os = "android")]
-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
-pub struct FsType(pub libc::c_ulong);
+type fs_type_t = libc::c_ulong;
#[cfg(all(target_os = "linux", target_arch = "s390x"))]
-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
-pub struct FsType(pub u32);
+type fs_type_t = libc::c_uint;
#[cfg(all(target_os = "linux", target_env = "musl"))]
-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
-pub struct FsType(pub libc::c_ulong);
+type fs_type_t = libc::c_ulong;
#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
+type fs_type_t = libc::__fsword_t;
+
+#[cfg(any(
+ target_os = "freebsd",
+ target_os = "android",
+ all(target_os = "linux", target_arch = "s390x"),
+ all(target_os = "linux", target_env = "musl"),
+ all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))),
+))]
#[derive(Eq, Copy, Clone, PartialEq, Debug)]
-pub struct FsType(pub libc::c_long);
-
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const OVERLAYFS_SUPER_MAGIC: FsType = FsType(libc::OVERLAYFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC);
+pub struct FsType(pub fs_type_t);
+
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const OVERLAYFS_SUPER_MAGIC: FsType = FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t);
+
impl Statfs {
/// Magic code defining system type
@@ -138,7 +144,7 @@ impl Statfs {
/// Optimal transfer block size
#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
- pub fn optimal_transfer_size(&self) -> libc::c_long {
+ pub fn optimal_transfer_size(&self) -> libc::__fsword_t {
self.0.f_bsize
}
@@ -177,7 +183,7 @@ impl Statfs {
/// Size of a block
// f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
- pub fn block_size(&self) -> libc::c_long {
+ pub fn block_size(&self) -> libc::__fsword_t {
self.0.f_bsize
}
@@ -219,7 +225,7 @@ impl Statfs {
/// Maximum length of filenames
#[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
- pub fn maximum_name_length(&self) -> libc::c_long {
+ pub fn maximum_name_length(&self) -> libc::__fsword_t {
self.0.f_namelen
}
@@ -248,7 +254,7 @@ impl Statfs {
}
/// Total data blocks in filesystem
- #[cfg(all(target_os = "linux", target_env = "musl"))]
+ #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
pub fn blocks(&self) -> u64 {
self.0.f_blocks
}
@@ -261,7 +267,7 @@ impl Statfs {
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
- all(target_os = "linux", target_env = "musl")
+ all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
)))]
pub fn blocks(&self) -> libc::c_ulong {
self.0.f_blocks
@@ -286,7 +292,7 @@ impl Statfs {
}
/// Free blocks in filesystem
- #[cfg(all(target_os = "linux", target_env = "musl"))]
+ #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
pub fn blocks_free(&self) -> u64 {
self.0.f_bfree
}
@@ -299,7 +305,7 @@ impl Statfs {
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
- all(target_os = "linux", target_env = "musl")
+ all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
)))]
pub fn blocks_free(&self) -> libc::c_ulong {
self.0.f_bfree
@@ -324,7 +330,7 @@ impl Statfs {
}
/// Free blocks available to unprivileged user
- #[cfg(all(target_os = "linux", target_env = "musl"))]
+ #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
pub fn blocks_available(&self) -> u64 {
self.0.f_bavail
}
@@ -337,7 +343,7 @@ impl Statfs {
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
- all(target_os = "linux", target_env = "musl")
+ all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
)))]
pub fn blocks_available(&self) -> libc::c_ulong {
self.0.f_bavail
@@ -362,8 +368,8 @@ impl Statfs {
}
/// Total file nodes in filesystem
- #[cfg(all(target_os = "linux", target_env = "musl"))]
- pub fn files(&self) -> u64 {
+ #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
+ pub fn files(&self) -> libc::fsfilcnt_t {
self.0.f_files
}
@@ -375,7 +381,7 @@ impl Statfs {
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
- all(target_os = "linux", target_env = "musl")
+ all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
)))]
pub fn files(&self) -> libc::c_ulong {
self.0.f_files
@@ -385,7 +391,6 @@ impl Statfs {
#[cfg(any(
target_os = "android",
target_os = "ios",
- all(target_os = "linux", target_env = "musl"),
target_os = "macos",
target_os = "openbsd"
))]
@@ -406,6 +411,12 @@ impl Statfs {
}
/// Free file nodes in filesystem
+ #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
+ pub fn files_free(&self) -> libc::fsfilcnt_t {
+ self.0.f_ffree
+ }
+
+ /// Free file nodes in filesystem
#[cfg(not(any(
target_os = "ios",
target_os = "macos",
@@ -413,7 +424,7 @@ impl Statfs {
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
- all(target_os = "linux", target_env = "musl")
+ all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
)))]
pub fn files_free(&self) -> libc::c_ulong {
self.0.f_ffree
diff --git a/src/sys/sysinfo.rs b/src/sys/sysinfo.rs
index f4b8279..222a2fc 100644
--- a/src/sys/sysinfo.rs
+++ b/src/sys/sysinfo.rs
@@ -10,6 +10,12 @@ use crate::errno::Errno;
#[repr(transparent)]
pub struct SysInfo(libc::sysinfo);
+// The fields are c_ulong on 32-bit linux, u64 on 64-bit linux; x32's ulong is u32
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
+type mem_blocks_t = u64;
+#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
+type mem_blocks_t = libc::c_ulong;
+
impl SysInfo {
/// Returns the load average tuple.
///
@@ -58,7 +64,7 @@ impl SysInfo {
self.scale_mem(self.0.freeram)
}
- fn scale_mem(&self, units: libc::c_ulong) -> u64 {
+ fn scale_mem(&self, units: mem_blocks_t) -> u64 {
units as u64 * self.0.mem_unit as u64
}
}
diff --git a/src/sys/time.rs b/src/sys/time.rs
index 269b425..7546d1b 100644
--- a/src/sys/time.rs
+++ b/src/sys/time.rs
@@ -1,7 +1,8 @@
use std::{cmp, fmt, ops};
use std::time::Duration;
use std::convert::From;
-use libc::{c_long, timespec, timeval};
+use libc::{timespec, timeval};
+#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
pub use libc::{time_t, suseconds_t};
pub trait TimeValLike: Sized {
@@ -61,6 +62,13 @@ const TS_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS;
+// x32 compatibility
+// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
+type timespec_tv_nsec_t = i64;
+#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
+type timespec_tv_nsec_t = libc::c_long;
+
impl From<timespec> for TimeSpec {
fn from(ts: timespec) -> Self {
Self(ts)
@@ -69,9 +77,10 @@ impl From<timespec> for TimeSpec {
impl From<Duration> for TimeSpec {
fn from(duration: Duration) -> Self {
+ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
TimeSpec(timespec {
tv_sec: duration.as_secs() as time_t,
- tv_nsec: duration.subsec_nanos() as c_long
+ tv_nsec: duration.subsec_nanos() as timespec_tv_nsec_t
})
}
}
@@ -117,6 +126,7 @@ impl TimeValLike for TimeSpec {
fn seconds(seconds: i64) -> TimeSpec {
assert!(seconds >= TS_MIN_SECONDS && seconds <= TS_MAX_SECONDS,
"TimeSpec out of bounds; seconds={}", seconds);
+ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 })
}
@@ -143,8 +153,9 @@ impl TimeValLike for TimeSpec {
let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
assert!(secs >= TS_MIN_SECONDS && secs <= TS_MAX_SECONDS,
"TimeSpec out of bounds");
+ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
TimeSpec(timespec {tv_sec: secs as time_t,
- tv_nsec: nanos as c_long })
+ tv_nsec: nanos as timespec_tv_nsec_t })
}
fn num_seconds(&self) -> i64 {
@@ -171,19 +182,20 @@ impl TimeValLike for TimeSpec {
}
impl TimeSpec {
- fn nanos_mod_sec(&self) -> c_long {
+ fn nanos_mod_sec(&self) -> timespec_tv_nsec_t {
if self.tv_sec() < 0 && self.tv_nsec() > 0 {
- self.tv_nsec() - NANOS_PER_SEC as c_long
+ self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t
} else {
self.tv_nsec()
}
}
+ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
pub fn tv_sec(&self) -> time_t {
self.0.tv_sec
}
- pub fn tv_nsec(&self) -> c_long {
+ pub fn tv_nsec(&self) -> timespec_tv_nsec_t {
self.0.tv_nsec
}
}
@@ -315,6 +327,7 @@ impl TimeValLike for TimeVal {
fn seconds(seconds: i64) -> TimeVal {
assert!(seconds >= TV_MIN_SECONDS && seconds <= TV_MAX_SECONDS,
"TimeVal out of bounds; seconds={}", seconds);
+ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 })
}
@@ -332,6 +345,7 @@ impl TimeValLike for TimeVal {
let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
"TimeVal out of bounds");
+ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
TimeVal(timeval {tv_sec: secs as time_t,
tv_usec: micros as suseconds_t })
}
@@ -344,6 +358,7 @@ impl TimeValLike for TimeVal {
let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
"TimeVal out of bounds");
+ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
TimeVal(timeval {tv_sec: secs as time_t,
tv_usec: micros as suseconds_t })
}
@@ -380,6 +395,7 @@ impl TimeVal {
}
}
+ #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
pub fn tv_sec(&self) -> time_t {
self.0.tv_sec
}
diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs
index 3086309..4a24719 100644
--- a/src/sys/timerfd.rs
+++ b/src/sys/timerfd.rs
@@ -37,7 +37,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
/// A timerfd 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 TimerFd {
fd: RawFd,
}
@@ -166,7 +166,7 @@ pub enum Expiration {
impl TimerFd {
/// Creates a new timer based on the clock defined by `clockid`. The
/// underlying fd can be assigned specific flags with `flags` (CLOEXEC,
- /// NONBLOCK).
+ /// NONBLOCK). The underlying fd will be closed on drop.
pub fn new(clockid: ClockId, flags: TimerFlags) -> Result<Self> {
Errno::result(unsafe { libc::timerfd_create(clockid as i32, flags.bits()) })
.map(|fd| Self { fd })
@@ -270,3 +270,16 @@ 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(Error::Sys(Errno::EBADF)) = result {
+ panic!("close of TimerFd encountered EBADF");
+ }
+ }
+ }
+}
diff --git a/src/sys/wait.rs b/src/sys/wait.rs
index 0c04042..faf8543 100644
--- a/src/sys/wait.rs
+++ b/src/sys/wait.rs
@@ -1,9 +1,9 @@
-use cfg_if::cfg_if;
-use libc::{self, c_int};
-use crate::Result;
use crate::errno::Errno;
-use crate::unistd::Pid;
use crate::sys::signal::Signal;
+use crate::unistd::Pid;
+use crate::Result;
+use cfg_if::cfg_if;
+use libc::{self, c_int};
use std::convert::TryFrom;
libc_bitflags!(
@@ -108,8 +108,7 @@ impl WaitStatus {
pub fn pid(&self) -> Option<Pid> {
use self::WaitStatus::*;
match *self {
- Exited(p, _) | Signaled(p, _, _) |
- Stopped(p, _) | Continued(p) => Some(p),
+ Exited(p, _) | Signaled(p, _, _) | Stopped(p, _) | Continued(p) => Some(p),
StillAlive => None,
#[cfg(any(target_os = "android", target_os = "linux"))]
PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p),
@@ -117,49 +116,41 @@ impl WaitStatus {
}
}
-#[allow(unused_unsafe)]
fn exited(status: i32) -> bool {
- unsafe { libc::WIFEXITED(status) }
+ libc::WIFEXITED(status)
}
-#[allow(unused_unsafe)]
fn exit_status(status: i32) -> i32 {
- unsafe { libc::WEXITSTATUS(status) }
+ libc::WEXITSTATUS(status)
}
-#[allow(unused_unsafe)]
fn signaled(status: i32) -> bool {
- unsafe { libc::WIFSIGNALED(status) }
+ libc::WIFSIGNALED(status)
}
-#[allow(unused_unsafe)]
fn term_signal(status: i32) -> Result<Signal> {
- Signal::try_from(unsafe { libc::WTERMSIG(status) })
+ Signal::try_from(libc::WTERMSIG(status))
}
-#[allow(unused_unsafe)]
fn dumped_core(status: i32) -> bool {
- unsafe { libc::WCOREDUMP(status) }
+ libc::WCOREDUMP(status)
}
-#[allow(unused_unsafe)]
fn stopped(status: i32) -> bool {
- unsafe { libc::WIFSTOPPED(status) }
+ libc::WIFSTOPPED(status)
}
-#[allow(unused_unsafe)]
fn stop_signal(status: i32) -> Result<Signal> {
- Signal::try_from(unsafe { libc::WSTOPSIG(status) })
+ Signal::try_from(libc::WSTOPSIG(status))
}
#[cfg(any(target_os = "android", target_os = "linux"))]
-#[allow(unused_unsafe)]
fn syscall_stop(status: i32) -> bool {
// From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect
// of delivering SIGTRAP | 0x80 as the signal number for syscall
// stops. This allows easily distinguishing syscall stops from
// genuine SIGTRAP signals.
- unsafe { libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 }
+ libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80
}
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -167,9 +158,8 @@ fn stop_additional(status: i32) -> c_int {
(status >> 16) as c_int
}
-#[allow(unused_unsafe)]
fn continued(status: i32) -> bool {
- unsafe { libc::WIFCONTINUED(status) }
+ libc::WIFCONTINUED(status)
}
impl WaitStatus {
diff --git a/src/time.rs b/src/time.rs
index 54989c2..e6c3f8d 100644
--- a/src/time.rs
+++ b/src/time.rs
@@ -37,6 +37,7 @@ impl ClockId {
}
/// Returns resolution of the clock id
+ #[cfg(not(target_os = "redox"))]
pub fn res(self) -> Result<TimeSpec> {
clock_getres(self)
}
@@ -204,6 +205,7 @@ impl std::fmt::Display for ClockId {
/// Get the resolution of the specified clock, (see
/// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)).
+#[cfg(not(target_os = "redox"))]
pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> {
let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
let ret = unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) };
diff --git a/src/unistd.rs b/src/unistd.rs
index 04031e3..7a4517e 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -12,9 +12,9 @@ use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t,
uid_t, gid_t, mode_t, PATH_MAX};
use std::{fmt, mem, ptr};
use std::convert::Infallible;
-use std::ffi::{CStr, CString, OsString};
+use std::ffi::{CStr, OsString};
#[cfg(not(target_os = "redox"))]
-use std::ffi::{OsStr};
+use std::ffi::{CString, OsStr};
use std::os::unix::ffi::OsStringExt;
#[cfg(not(target_os = "redox"))]
use std::os::unix::ffi::OsStrExt;
@@ -426,6 +426,7 @@ pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
/// This function may fail in a number of different scenarios. See the man
/// pages for additional details on possible failure cases.
#[inline]
+#[cfg(not(target_os = "fuchsia"))]
pub fn fchdir(dirfd: RawFd) -> Result<()> {
let res = unsafe { libc::fchdir(dirfd) };
@@ -1095,7 +1096,7 @@ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
///
/// See also
/// [truncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html)
-#[cfg(not(target_os = "redox"))]
+#[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 {
@@ -1232,6 +1233,7 @@ pub fn unlinkat<P: ?Sized + NixPath>(
#[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()) }
@@ -1633,7 +1635,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")]
//! use std::time::{Duration, Instant};
//!
//! use nix::unistd::{alarm, pause};
@@ -1642,14 +1645,23 @@ pub mod alarm {
//! // We need to setup an empty signal handler to catch the alarm signal,
//! // otherwise the program will be terminated once the signal is delivered.
//! extern fn signal_handler(_: nix::libc::c_int) { }
- //! unsafe { sigaction(Signal::SIGALRM, &SigAction::new(SigHandler::Handler(signal_handler), SaFlags::empty(), SigSet::empty())); }
+ //! let sa = SigAction::new(
+ //! SigHandler::Handler(signal_handler),
+ //! SaFlags::empty(),
+ //! SigSet::empty()
+ //! );
+ //! unsafe {
+ //! sigaction(Signal::SIGALRM, &sa);
+ //! }
//!
//! // Set an alarm for 1 second from now.
//! alarm::set(1);
//!
//! let start = Instant::now();
//! // Pause the process until the alarm signal is received.
- //! pause();
+ //! let mut sigset = SigSet::empty();
+ //! sigset.add(Signal::SIGALRM);
+ //! sigset.wait();
//!
//! assert!(start.elapsed() >= Duration::from_secs(1));
//! ```
@@ -2536,13 +2548,16 @@ pub struct User {
/// Path to shell
pub shell: PathBuf,
/// Login class
- #[cfg(not(any(target_os = "android", target_os = "linux")))]
+ #[cfg(not(any(target_os = "android", target_os = "fuchsia",
+ target_os = "linux")))]
pub class: CString,
/// Last password change
- #[cfg(not(any(target_os = "android", target_os = "linux")))]
+ #[cfg(not(any(target_os = "android", target_os = "fuchsia",
+ target_os = "linux")))]
pub change: libc::time_t,
/// Expiration time of account
- #[cfg(not(any(target_os = "android", target_os = "linux")))]
+ #[cfg(not(any(target_os = "android", target_os = "fuchsia",
+ target_os = "linux")))]
pub expire: libc::time_t
}
@@ -2559,11 +2574,14 @@ impl From<&libc::passwd> for User {
shell: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_shell).to_bytes())),
uid: Uid::from_raw((*pw).pw_uid),
gid: Gid::from_raw((*pw).pw_gid),
- #[cfg(not(any(target_os = "android", target_os = "linux")))]
+ #[cfg(not(any(target_os = "android", target_os = "fuchsia",
+ target_os = "linux")))]
class: CString::new(CStr::from_ptr((*pw).pw_class).to_bytes()).unwrap(),
- #[cfg(not(any(target_os = "android", target_os = "linux")))]
+ #[cfg(not(any(target_os = "android", target_os = "fuchsia",
+ target_os = "linux")))]
change: (*pw).pw_change,
- #[cfg(not(any(target_os = "android", target_os = "linux")))]
+ #[cfg(not(any(target_os = "android", target_os = "fuchsia",
+ target_os = "linux")))]
expire: (*pw).pw_expire
}
}
@@ -2653,6 +2671,8 @@ impl User {
pub struct Group {
/// Group name
pub name: String,
+ /// Group password
+ pub passwd: CString,
/// Group ID
pub gid: Gid,
/// List of Group members
@@ -2665,6 +2685,7 @@ impl From<&libc::group> for Group {
unsafe {
Group {
name: CStr::from_ptr((*gr).gr_name).to_string_lossy().into_owned(),
+ passwd: CString::new(CStr::from_ptr((*gr).gr_passwd).to_bytes()).unwrap(),
gid: Gid::from_raw((*gr).gr_gid),
mem: Group::members((*gr).gr_mem)
}
@@ -2771,6 +2792,7 @@ impl Group {
/// Get the name of the terminal device that is open on file descriptor fd
/// (see [`ttyname(3)`](http://man7.org/linux/man-pages/man3/ttyname.3.html)).
+#[cfg(not(target_os = "fuchsia"))]
pub fn ttyname(fd: RawFd) -> Result<PathBuf> {
const PATH_MAX: usize = libc::PATH_MAX as usize;
let mut buf = vec![0_u8; PATH_MAX];
@@ -2785,3 +2807,23 @@ pub fn ttyname(fd: RawFd) -> Result<PathBuf> {
buf.truncate(nul);
Ok(OsString::from_vec(buf).into())
}
+
+/// Get the effective user ID and group ID associated with a Unix domain socket.
+///
+/// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid)
+#[cfg(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+))]
+pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> {
+ let mut uid = 1;
+ let mut gid = 1;
+
+ let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) };
+
+ Errno::result(ret).map(|_| (Uid(uid), Gid(gid)))
+}
diff --git a/test/common/mod.rs b/test/common/mod.rs
new file mode 100644
index 0000000..a871b47
--- /dev/null
+++ b/test/common/mod.rs
@@ -0,0 +1,127 @@
+use cfg_if::cfg_if;
+
+#[macro_export] macro_rules! skip {
+ ($($reason: expr),+) => {
+ use ::std::io::{self, Write};
+
+ let stderr = io::stderr();
+ let mut handle = stderr.lock();
+ writeln!(handle, $($reason),+).unwrap();
+ return;
+ }
+}
+
+cfg_if! {
+ if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ #[macro_export] macro_rules! require_capability {
+ ($capname:ident) => {
+ use ::caps::{Capability, CapSet, has_cap};
+
+ if !has_cap(None, CapSet::Effective, Capability::$capname)
+ .unwrap()
+ {
+ skip!("Insufficient capabilities. Skipping test.");
+ }
+ }
+ }
+ } else if #[cfg(not(target_os = "redox"))] {
+ #[macro_export] macro_rules! require_capability {
+ ($capname:ident) => {}
+ }
+ }
+}
+
+#[cfg(any(target_os = "linux", target_os= "android"))]
+#[macro_export] macro_rules! skip_if_cirrus {
+ ($reason:expr) => {
+ if std::env::var_os("CIRRUS_CI").is_some() {
+ skip!("{}", $reason);
+ }
+ }
+}
+
+#[cfg(target_os = "freebsd")]
+#[macro_export] macro_rules! skip_if_jailed {
+ ($name:expr) => {
+ use ::sysctl::CtlValue;
+
+ if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed")
+ .unwrap()
+ {
+ skip!("{} cannot run in a jail. Skipping test.", $name);
+ }
+ }
+}
+
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+#[macro_export] macro_rules! skip_if_not_root {
+ ($name:expr) => {
+ use nix::unistd::Uid;
+
+ if !Uid::current().is_root() {
+ skip!("{} requires root privileges. Skipping test.", $name);
+ }
+ };
+}
+
+cfg_if! {
+ if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ #[macro_export] macro_rules! skip_if_seccomp {
+ ($name:expr) => {
+ if let Ok(s) = std::fs::read_to_string("/proc/self/status") {
+ for l in s.lines() {
+ let mut fields = l.split_whitespace();
+ if fields.next() == Some("Seccomp:") &&
+ fields.next() != Some("0")
+ {
+ skip!("{} cannot be run in Seccomp mode. Skipping test.",
+ stringify!($name));
+ }
+ }
+ }
+ }
+ }
+ } else if #[cfg(not(target_os = "redox"))] {
+ #[macro_export] macro_rules! skip_if_seccomp {
+ ($name:expr) => {}
+ }
+ }
+}
+
+cfg_if! {
+ if #[cfg(target_os = "linux")] {
+ #[macro_export] macro_rules! require_kernel_version {
+ ($name:expr, $version_requirement:expr) => {
+ use semver::{Version, VersionReq};
+
+ let version_requirement = VersionReq::parse($version_requirement)
+ .expect("Bad match_version provided");
+
+ let uname = nix::sys::utsname::uname();
+ println!("{}", uname.sysname());
+ println!("{}", uname.nodename());
+ println!("{}", uname.release());
+ println!("{}", uname.version());
+ println!("{}", uname.machine());
+
+ // Fix stuff that the semver parser can't handle
+ let fixed_release = &uname.release().to_string()
+ // Fedora 33 reports version as 4.18.el8_2.x86_64 or
+ // 5.18.200-fc33.x86_64. Remove the underscore.
+ .replace("_", "-")
+ // Cirrus-CI reports version as 4.19.112+ . Remove the +
+ .replace("+", "");
+ let mut version = Version::parse(fixed_release).unwrap();
+
+ //Keep only numeric parts
+ version.pre.clear();
+ version.build.clear();
+
+ if !version_requirement.matches(&version) {
+ skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`",
+ stringify!($name), version, version_requirement);
+ }
+ }
+ }
+ }
+}
diff --git a/test/sys/mod.rs b/test/sys/mod.rs
index c4391c7..14b0378 100644
--- a/test/sys/mod.rs
+++ b/test/sys/mod.rs
@@ -21,9 +21,9 @@ mod test_sockopt;
mod test_select;
#[cfg(any(target_os = "android", target_os = "linux"))]
mod test_sysinfo;
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
mod test_termios;
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
mod test_ioctl;
mod test_wait;
mod test_uio;
diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs
index 6b9bd91..3878da9 100644
--- a/test/sys/test_aio.rs
+++ b/test/sys/test_aio.rs
@@ -137,6 +137,9 @@ fn test_fsync_error() {
// in Travis's version of glibc or Linux. Either way, we must skip the test.
// https://github.com/nix-rust/nix/issues/1099
#[cfg_attr(target_os = "linux", ignore)]
+// On Cirrus, aio_suspend is failing with EINVAL
+// https://github.com/nix-rust/nix/issues/1361
+#[cfg_attr(target_os = "macos", ignore)]
fn test_aio_suspend() {
const INITIAL: &[u8] = b"abcdef123456";
const WBUF: &[u8] = b"CDEFG";
@@ -164,7 +167,12 @@ fn test_aio_suspend() {
loop {
{
let cbbuf = [&wcb, &rcb];
- assert!(aio_suspend(&cbbuf[..], Some(timeout)).is_ok());
+ let r = aio_suspend(&cbbuf[..], Some(timeout));
+ match r {
+ Err(Error::Sys(Errno::EINTR)) => continue,
+ Err(e) => panic!("aio_suspend returned {:?}", e),
+ Ok(_) => ()
+ };
}
if rcb.error() != Err(Error::from(Errno::EINPROGRESS)) &&
wcb.error() != Err(Error::from(Errno::EINPROGRESS)) {
diff --git a/test/sys/test_aio_drop.rs b/test/sys/test_aio_drop.rs
index 71a2183..784ee3e 100644
--- a/test/sys/test_aio_drop.rs
+++ b/test/sys/test_aio_drop.rs
@@ -9,6 +9,7 @@
target_os = "macos",
target_os = "freebsd",
target_os = "netbsd")))]
+#[cfg_attr(target_env = "gnu", ignore = "Occasionally fails in Travis; glibc bug suspected")]
fn test_drop() {
use nix::sys::aio::*;
use nix::sys::signal::*;
diff --git a/test/sys/test_mman.rs b/test/sys/test_mman.rs
new file mode 100644
index 0000000..152fff6
--- /dev/null
+++ b/test/sys/test_mman.rs
@@ -0,0 +1,80 @@
+use nix::Error;
+use nix::libc::{c_void, size_t};
+use nix::sys::mman::{mmap, MapFlags, ProtFlags};
+
+#[cfg(target_os = "linux")]
+use nix::sys::mman::{mremap, MRemapFlags};
+
+#[test]
+fn test_mmap_anonymous() {
+ let ref mut byte = unsafe {
+ let ptr = mmap(std::ptr::null_mut(), 1,
+ ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
+ MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, -1, 0)
+ .unwrap();
+ *(ptr as * mut u8)
+ };
+ assert_eq !(*byte, 0x00u8);
+ *byte = 0xffu8;
+ assert_eq !(*byte, 0xffu8);
+}
+
+#[test]
+#[cfg(target_os = "linux")]
+fn test_mremap_grow() {
+ const ONE_K : size_t = 1024;
+ let slice : &mut[u8] = unsafe {
+ let mem = mmap(std::ptr::null_mut(), ONE_K,
+ ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
+ MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0)
+ .unwrap();
+ std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
+ };
+ assert_eq !(slice[ONE_K - 1], 0x00);
+ slice[ONE_K - 1] = 0xFF;
+ assert_eq !(slice[ONE_K - 1], 0xFF);
+
+ let slice : &mut[u8] = unsafe {
+ let mem = mremap(slice.as_mut_ptr() as * mut c_void, ONE_K, 10 * ONE_K,
+ MRemapFlags::MREMAP_MAYMOVE, None)
+ .unwrap();
+ std::slice::from_raw_parts_mut(mem as * mut u8, 10 * ONE_K)
+ };
+
+ // The first KB should still have the old data in it.
+ assert_eq !(slice[ONE_K - 1], 0xFF);
+
+ // The additional range should be zero-init'd and accessible.
+ assert_eq !(slice[10 * ONE_K - 1], 0x00);
+ slice[10 * ONE_K - 1] = 0xFF;
+ assert_eq !(slice[10 * ONE_K - 1], 0xFF);
+}
+
+#[test]
+#[cfg(target_os = "linux")]
+fn test_mremap_shrink() {
+ const ONE_K : size_t = 1024;
+ let slice : &mut[u8] = unsafe {
+ let mem = mmap(std::ptr::null_mut(), 10 * ONE_K,
+ ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
+ MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0)
+ .unwrap();
+ std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
+ };
+ assert_eq !(slice[ONE_K - 1], 0x00);
+ slice[ONE_K - 1] = 0xFF;
+ assert_eq !(slice[ONE_K - 1], 0xFF);
+
+ let slice : &mut[u8] = unsafe {
+ let mem = mremap(slice.as_mut_ptr() as * mut c_void, 10 * ONE_K, ONE_K,
+ MRemapFlags::empty(), None)
+ .unwrap();
+ // Since we didn't supply MREMAP_MAYMOVE, the address should be the
+ // same.
+ assert_eq !(mem, slice.as_mut_ptr() as * mut c_void);
+ std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
+ };
+
+ // The first KB should still be accessible and have the old data in it.
+ assert_eq !(slice[ONE_K - 1], 0xFF);
+}
diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs
index 3b60dd7..b9793b3 100644
--- a/test/sys/test_ptrace.rs
+++ b/test/sys/test_ptrace.rs
@@ -8,6 +8,8 @@ use nix::sys::ptrace::Options;
#[cfg(any(target_os = "android", target_os = "linux"))]
use std::mem;
+use crate::*;
+
#[test]
fn test_ptrace() {
// Just make sure ptrace can be called at all, for now.
@@ -98,7 +100,7 @@ fn test_ptrace_cont() {
ptrace::cont(child, Some(Signal::SIGKILL)).unwrap();
match waitpid(child, None) {
Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => {
- // FIXME It's been observed on some systems (apple) the
+ // FIXME It's been observed on some systems (apple) the
// tracee may not be killed but remain as a zombie process
// affecting other wait based tests. Add an extra kill just
// to make sure there are no zombies.
@@ -148,11 +150,11 @@ fn test_ptrace_syscall() {
// set this option to recognize syscall-stops
ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap();
- #[cfg(target_pointer_width = "64")]
- let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as i64;
+ #[cfg(target_arch = "x86_64")]
+ let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as libc::c_long;
- #[cfg(target_pointer_width = "32")]
- let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as i32;
+ #[cfg(target_arch = "x86")]
+ let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as libc::c_long;
// kill entry
ptrace::syscall(child, None).unwrap();
diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs
index 5e0b276..ae22527 100644
--- a/test/sys/test_signal.rs
+++ b/test/sys/test_signal.rs
@@ -12,6 +12,7 @@ fn test_kill_none() {
}
#[test]
+#[cfg(not(target_os = "fuchsia"))]
fn test_killpg_none() {
killpg(getpgrp(), None)
.expect("Should be able to send signal to my process group.");
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs
index 1003598..7eab28c 100644
--- a/test/sys/test_socket.rs
+++ b/test/sys/test_socket.rs
@@ -1,4 +1,3 @@
-use nix::ifaddrs::InterfaceAddress;
use nix::sys::socket::{AddressFamily, InetAddr, UnixAddr, getsockname};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
@@ -9,6 +8,8 @@ use std::slice;
use std::str::FromStr;
use libc::c_char;
use tempfile;
+#[cfg(any(target_os = "linux", target_os= "android"))]
+use crate::*;
#[test]
pub fn test_inetv4_addr_to_sock_addr() {
@@ -237,6 +238,9 @@ mod recvfrom {
use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment};
#[test]
+ // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU
+ // support is suspected.
+ #[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)]
pub fn gso() {
require_kernel_version!(udp_offload::gso, ">= 4.18");
@@ -288,6 +292,9 @@ mod recvfrom {
}
#[test]
+ // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU
+ // support is suspected.
+ #[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)]
pub fn gro() {
require_kernel_version!(udp_offload::gro, ">= 5.3");
@@ -437,6 +444,76 @@ mod recvfrom {
send_thread.join().unwrap();
}
+
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ ))]
+ #[test]
+ pub fn udp_recvmmsg_dontwait_short_read() {
+ use nix::sys::uio::IoVec;
+ use nix::sys::socket::{MsgFlags, recvmmsg};
+
+ const NUM_MESSAGES_SENT: usize = 2;
+ const DATA: [u8; 4] = [1,2,3,4];
+
+ let std_sa = SocketAddr::from_str("127.0.0.1:6799").unwrap();
+ let inet_addr = InetAddr::from_std(&std_sa);
+ let sock_addr = SockAddr::new_inet(inet_addr);
+
+ let rsock = socket(AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None
+ ).unwrap();
+ bind(rsock, &sock_addr).unwrap();
+ let ssock = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ ).expect("send socket failed");
+
+ let send_thread = thread::spawn(move || {
+ for _ in 0..NUM_MESSAGES_SENT {
+ sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()).unwrap();
+ }
+ });
+ // Ensure we've sent all the messages before continuing so `recvmmsg`
+ // will return right away
+ send_thread.join().unwrap();
+
+ let mut msgs = std::collections::LinkedList::new();
+
+ // Buffers to receive >`NUM_MESSAGES_SENT` messages to ensure `recvmmsg`
+ // will return when there are fewer than requested messages in the
+ // kernel buffers when using `MSG_DONTWAIT`.
+ let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2];
+ let iovs: Vec<_> = receive_buffers.iter_mut().map(|buf| {
+ [IoVec::from_mut_slice(&mut buf[..])]
+ }).collect();
+
+ for iov in &iovs {
+ msgs.push_back(RecvMmsgData {
+ iov: iov,
+ cmsg_buffer: None,
+ })
+ };
+
+ let res = recvmmsg(rsock, &mut msgs, MsgFlags::MSG_DONTWAIT, None).expect("recvmmsg");
+ assert_eq!(res.len(), NUM_MESSAGES_SENT);
+
+ for RecvMsg { address, bytes, .. } in res.into_iter() {
+ assert_eq!(AddressFamily::Inet, address.unwrap().family());
+ assert_eq!(DATA.len(), bytes);
+ }
+
+ for buf in &receive_buffers[..NUM_MESSAGES_SENT] {
+ assert_eq!(&buf[..DATA.len()], DATA);
+ }
+ }
}
// Test error handling of our recvmsg wrapper
@@ -522,12 +599,13 @@ pub fn test_af_alg_cipher() {
ControlMessage, MsgFlags};
use nix::sys::socket::sockopt::AlgSetKey;
+ skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352");
// Travis's seccomp profile blocks AF_ALG
// https://docs.docker.com/engine/security/seccomp/
skip_if_seccomp!(test_af_alg_cipher);
let alg_type = "skcipher";
- let alg_name = "ctr(aes)";
+ let alg_name = "ctr-aes-aesni";
// 256-bits secret key
let key = vec![0u8; 32];
// 16-bytes IV
@@ -590,6 +668,7 @@ pub fn test_af_alg_aead() {
ControlMessage, MsgFlags};
use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize};
+ skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352");
// Travis's seccomp profile blocks AF_ALG
// https://docs.docker.com/engine/security/seccomp/
skip_if_seccomp!(test_af_alg_aead);
@@ -948,7 +1027,7 @@ fn test_too_large_cmsgspace() {
fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
use libc::ucred;
use nix::sys::uio::IoVec;
- use nix::unistd::{pipe, read, write, close, getpid, getuid, getgid};
+ use nix::unistd::{pipe, write, close, getpid, getuid, getgid};
use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt,
SockType, SockFlag,
ControlMessage, ControlMessageOwned, MsgFlags};
@@ -1081,7 +1160,7 @@ pub fn test_syscontrol() {
target_os = "netbsd",
target_os = "openbsd",
))]
-fn loopback_address(family: AddressFamily) -> Option<InterfaceAddress> {
+fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddress> {
use std::io;
use std::io::Write;
use nix::ifaddrs::getifaddrs;
diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs
index 8e2adce..5606593 100644
--- a/test/sys/test_sockopt.rs
+++ b/test/sys/test_sockopt.rs
@@ -1,5 +1,7 @@
use rand::{thread_rng, Rng};
use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, SockType, SockFlag, SockProtocol};
+#[cfg(any(target_os = "android", target_os = "linux"))]
+use crate::*;
#[cfg(target_os = "linux")]
#[test]
diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs
index 4fa838c..8d22bf1 100644
--- a/test/sys/test_uio.rs
+++ b/test/sys/test_uio.rs
@@ -203,6 +203,7 @@ fn test_process_vm_readv() {
use nix::unistd::ForkResult::*;
use nix::sys::signal::*;
use nix::sys::wait::*;
+ use crate::*;
require_capability!(CAP_SYS_PTRACE);
let _ = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs
index d105625..5bb298e 100644
--- a/test/sys/test_wait.rs
+++ b/test/sys/test_wait.rs
@@ -67,6 +67,7 @@ mod ptrace {
use nix::unistd::*;
use nix::unistd::ForkResult::*;
use libc::_exit;
+ use crate::*;
fn ptrace_child() -> ! {
ptrace::traceme().unwrap();
diff --git a/test/test.rs b/test/test.rs
index 8ad09b6..5a5330b 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -5,111 +5,7 @@ extern crate nix;
#[macro_use]
extern crate lazy_static;
-macro_rules! skip {
- ($($reason: expr),+) => {
- use ::std::io::{self, Write};
-
- let stderr = io::stderr();
- let mut handle = stderr.lock();
- writeln!(handle, $($reason),+).unwrap();
- return;
- }
-}
-
-cfg_if! {
- if #[cfg(any(target_os = "android", target_os = "linux"))] {
- macro_rules! require_capability {
- ($capname:ident) => {
- use ::caps::{Capability, CapSet, has_cap};
-
- if !has_cap(None, CapSet::Effective, Capability::$capname)
- .unwrap()
- {
- skip!("Insufficient capabilities. Skipping test.");
- }
- }
- }
- } else if #[cfg(not(target_os = "redox"))] {
- macro_rules! require_capability {
- ($capname:ident) => {}
- }
- }
-}
-
-#[cfg(target_os = "freebsd")]
-macro_rules! skip_if_jailed {
- ($name:expr) => {
- use ::sysctl::CtlValue;
-
- if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed")
- .unwrap()
- {
- skip!("{} cannot run in a jail. Skipping test.", $name);
- }
- }
-}
-
-#[cfg(not(target_os = "redox"))]
-macro_rules! skip_if_not_root {
- ($name:expr) => {
- use nix::unistd::Uid;
-
- if !Uid::current().is_root() {
- skip!("{} requires root privileges. Skipping test.", $name);
- }
- };
-}
-
-cfg_if! {
- if #[cfg(any(target_os = "android", target_os = "linux"))] {
- macro_rules! skip_if_seccomp {
- ($name:expr) => {
- if let Ok(s) = std::fs::read_to_string("/proc/self/status") {
- for l in s.lines() {
- let mut fields = l.split_whitespace();
- if fields.next() == Some("Seccomp:") &&
- fields.next() != Some("0")
- {
- skip!("{} cannot be run in Seccomp mode. Skipping test.",
- stringify!($name));
- }
- }
- }
- }
- }
- } else if #[cfg(not(target_os = "redox"))] {
- macro_rules! skip_if_seccomp {
- ($name:expr) => {}
- }
- }
-}
-
-cfg_if! {
- if #[cfg(target_os = "linux")] {
- macro_rules! require_kernel_version {
- ($name:expr, $version_requirement:expr) => {
- use semver::{Version, VersionReq};
-
- let version_requirement = VersionReq::parse($version_requirement)
- .expect("Bad match_version provided");
-
- let uname = nix::sys::utsname::uname();
-
- let mut version = Version::parse(uname.release()).unwrap();
-
- //Keep only numeric parts
- version.pre.clear();
- version.build.clear();
-
- if !version_requirement.matches(&version) {
- skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`",
- stringify!($name), version, version_requirement);
- }
- }
- }
- }
-}
-
+mod common;
mod sys;
#[cfg(not(target_os = "redox"))]
mod test_dir;
@@ -127,7 +23,7 @@ mod test_mq;
mod test_net;
mod test_nix_path;
mod test_poll;
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
mod test_pty;
#[cfg(any(target_os = "android",
target_os = "linux"))]
@@ -147,6 +43,7 @@ use std::path::PathBuf;
use std::sync::{Mutex, RwLock, RwLockWriteGuard};
use nix::unistd::{chdir, getcwd, read};
+
/// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s
fn read_exact(f: RawFd, buf: &mut [u8]) {
let mut len = 0;
diff --git a/test/test_dir.rs b/test/test_dir.rs
index c5f9c51..505277e 100644
--- a/test/test_dir.rs
+++ b/test/test_dir.rs
@@ -34,7 +34,9 @@ fn rewind() {
Mode::empty()).unwrap();
let entries1: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect();
let entries2: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect();
+ let entries3: Vec<_> = dir.into_iter().map(|e| e.unwrap().file_name().to_owned()).collect();
assert_eq!(entries1, entries2);
+ assert_eq!(entries2, entries3);
}
#[test]
diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs
index 2971907..5d1bafe 100644
--- a/test/test_fcntl.rs
+++ b/test/test_fcntl.rs
@@ -19,6 +19,8 @@ use std::io::prelude::*;
#[cfg(not(target_os = "redox"))]
use std::os::unix::fs;
+use crate::*;
+
#[test]
#[cfg(not(target_os = "redox"))]
fn test_openat() {
@@ -93,6 +95,8 @@ mod linux_android {
use tempfile::{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
@@ -328,7 +332,7 @@ mod linux_android {
target_os = "fuchsia",
any(target_os = "wasi", target_env = "wasi"),
target_env = "uclibc",
- target_env = "freebsd"))]
+ target_os = "freebsd"))]
mod test_posix_fadvise {
use tempfile::NamedTempFile;
diff --git a/test/test_kmod/mod.rs b/test/test_kmod/mod.rs
index e7472ab..fb7260b 100644
--- a/test/test_kmod/mod.rs
+++ b/test/test_kmod/mod.rs
@@ -2,6 +2,7 @@ use std::fs::copy;
use std::path::PathBuf;
use std::process::Command;
use tempfile::{tempdir, TempDir};
+use crate::*;
fn compile_kernel_module() -> (PathBuf, String, TempDir) {
let _m = crate::FORK_MTX
diff --git a/test/test_mount.rs b/test/test_mount.rs
index 605276b..c1b6c8a 100644
--- a/test/test_mount.rs
+++ b/test/test_mount.rs
@@ -1,3 +1,5 @@
+mod common;
+
// Impelmentation note: to allow unprivileged users to run it, this test makes
// use of user and mount namespaces. On systems that allow unprivileged user
// namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run
@@ -222,6 +224,7 @@ fn main() {
use test_mount::{setup_namespaces, test_mount_tmpfs_without_flags_allows_rwx,
test_mount_rdonly_disallows_write, test_mount_noexec_disallows_exec,
test_mount_bind};
+ skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1351");
setup_namespaces();
run_tests!(test_mount_tmpfs_without_flags_allows_rwx,
diff --git a/test/test_mq.rs b/test/test_mq.rs
index ecee200..1667a35 100644
--- a/test/test_mq.rs
+++ b/test/test_mq.rs
@@ -1,17 +1,15 @@
-use libc::c_long;
-
use std::ffi::CString;
use std::str;
use nix::errno::Errno::*;
use nix::Error::Sys;
-use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive};
+use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive, mq_attr_member_t};
use nix::mqueue::{MqAttr, MQ_OFlag};
use nix::sys::stat::Mode;
#[test]
fn test_mq_send_and_receive() {
- const MSG_SIZE: c_long = 32;
+ 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();
@@ -43,7 +41,7 @@ fn test_mq_send_and_receive() {
#[cfg(not(any(target_os = "netbsd")))]
fn test_mq_getattr() {
use nix::mqueue::mq_getattr;
- const MSG_SIZE: c_long = 32;
+ 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 oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
@@ -66,7 +64,7 @@ fn test_mq_getattr() {
#[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)]
fn test_mq_setattr() {
use nix::mqueue::{mq_getattr, mq_setattr};
- const MSG_SIZE: c_long = 32;
+ 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 oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
@@ -87,7 +85,7 @@ fn test_mq_setattr() {
// O_NONBLOCK can be set (see tests below)
assert_ne!(new_attr_get, new_attr);
- let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as c_long, 10, MSG_SIZE, 0);
+ let new_attr_non_blocking = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t, 10, MSG_SIZE, 0);
mq_setattr(mqd, &new_attr_non_blocking).unwrap();
let new_attr_get = mq_getattr(mqd).unwrap();
@@ -103,7 +101,7 @@ fn test_mq_setattr() {
#[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)]
fn test_mq_set_nonblocking() {
use nix::mqueue::{mq_getattr, mq_set_nonblock, mq_remove_nonblock};
- const MSG_SIZE: c_long = 32;
+ 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 oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
@@ -116,7 +114,7 @@ fn test_mq_set_nonblocking() {
let mqd = r.unwrap();
mq_set_nonblock(mqd).unwrap();
let new_attr = mq_getattr(mqd);
- assert_eq!(new_attr.unwrap().flags(), MQ_OFlag::O_NONBLOCK.bits() as c_long);
+ assert_eq!(new_attr.unwrap().flags(), MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t);
mq_remove_nonblock(mqd).unwrap();
let new_attr = mq_getattr(mqd);
assert_eq!(new_attr.unwrap().flags(), 0);
@@ -127,7 +125,7 @@ fn test_mq_set_nonblocking() {
#[cfg(not(any(target_os = "netbsd")))]
fn test_mq_unlink() {
use nix::mqueue::mq_unlink;
- const MSG_SIZE: c_long = 32;
+ 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_not_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap();
diff --git a/test/test_poll.rs b/test/test_poll.rs
index d1974ac..a5e2d25 100644
--- a/test/test_poll.rs
+++ b/test/test_poll.rs
@@ -1,5 +1,21 @@
-use nix::poll::{PollFlags, poll, PollFd};
-use nix::unistd::{write, pipe};
+use nix::{
+ Error,
+ errno::Errno,
+ poll::{PollFlags, poll, PollFd},
+ unistd::{write, pipe}
+};
+
+macro_rules! loop_while_eintr {
+ ($poll_expr: expr) => {
+ loop {
+ match $poll_expr {
+ Ok(nfds) => break nfds,
+ Err(Error::Sys(Errno::EINTR)) => (),
+ Err(e) => panic!(e)
+ }
+ }
+ }
+}
#[test]
fn test_poll() {
@@ -7,7 +23,7 @@ fn test_poll() {
let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
// Poll an idle pipe. Should timeout
- let nfds = poll(&mut fds, 100).unwrap();
+ let nfds = loop_while_eintr!(poll(&mut fds, 100));
assert_eq!(nfds, 0);
assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
@@ -37,7 +53,8 @@ fn test_ppoll() {
let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
// Poll an idle pipe. Should timeout
- let nfds = ppoll(&mut fds, Some(timeout), SigSet::empty()).unwrap();
+ let sigset = SigSet::empty();
+ let nfds = loop_while_eintr!(ppoll(&mut fds, Some(timeout), sigset));
assert_eq!(nfds, 0);
assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
diff --git a/test/test_ptymaster_drop.rs b/test/test_ptymaster_drop.rs
index 5a5c55d..ff939b9 100644
--- a/test/test_ptymaster_drop.rs
+++ b/test/test_ptymaster_drop.rs
@@ -1,4 +1,4 @@
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
mod t {
use nix::fcntl::OFlag;
use nix::pty::*;
diff --git a/test/test_unistd.rs b/test/test_unistd.rs
index c7a75fb..16a8a05 100644
--- a/test/test_unistd.rs
+++ b/test/test_unistd.rs
@@ -7,7 +7,7 @@ use nix::unistd::ForkResult::*;
use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction};
use nix::sys::wait::*;
use nix::sys::stat::{self, Mode, SFlag};
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
use nix::pty::{posix_openpt, grantpt, unlockpt, ptsname};
use nix::errno::Errno;
#[cfg(not(target_os = "redox"))]
@@ -19,13 +19,14 @@ use std::ffi::CString;
use std::fs::DirBuilder;
use std::fs::{self, File};
use std::io::Write;
-use std::mem;
use std::os::unix::prelude::*;
#[cfg(not(target_os = "redox"))]
use std::path::Path;
use tempfile::{tempdir, tempfile};
use libc::{_exit, off_t};
+use crate::*;
+
#[test]
#[cfg(not(any(target_os = "netbsd")))]
fn test_fork_and_waitpid() {
@@ -200,7 +201,7 @@ mod linux_android {
#[test]
// `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
-#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
+#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "fuchsia")))]
fn test_setgroups() {
// Skip this test when not run as root as `setgroups()` requires root.
skip_if_not_root!("test_setgroups");
@@ -223,7 +224,7 @@ fn test_setgroups() {
#[test]
// `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
-#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
+#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "fuchsia")))]
fn test_initgroups() {
// Skip this test when not run as root as `initgroups()` and `setgroups()`
// require root.
@@ -259,18 +260,24 @@ macro_rules! execve_test_factory(
#[cfg(test)]
mod $test_name {
+ use std::ffi::CStr;
use super::*;
+ const EMPTY: &'static [u8] = b"\0";
+ const DASH_C: &'static [u8] = b"-c\0";
+ const BIGARG: &'static [u8] = b"echo nix!!! && echo foo=$foo && echo baz=$baz\0";
+ const FOO: &'static [u8] = b"foo=bar\0";
+ const BAZ: &'static [u8] = b"baz=quux\0";
+
fn syscall_cstr_ref() -> Result<std::convert::Infallible, nix::Error> {
$syscall(
$exe,
$(CString::new($pathname).unwrap().as_c_str(), )*
- &[CString::new(b"".as_ref()).unwrap().as_c_str(),
- CString::new(b"-c".as_ref()).unwrap().as_c_str(),
- CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz"
- .as_ref()).unwrap().as_c_str()],
- &[CString::new(b"foo=bar".as_ref()).unwrap().as_c_str(),
- CString::new(b"baz=quux".as_ref()).unwrap().as_c_str()]
+ &[CStr::from_bytes_with_nul(EMPTY).unwrap(),
+ CStr::from_bytes_with_nul(DASH_C).unwrap(),
+ CStr::from_bytes_with_nul(BIGARG).unwrap()],
+ &[CStr::from_bytes_with_nul(FOO).unwrap(),
+ CStr::from_bytes_with_nul(BAZ).unwrap()]
$(, $flags)*)
}
@@ -278,12 +285,11 @@ macro_rules! execve_test_factory(
$syscall(
$exe,
$(CString::new($pathname).unwrap().as_c_str(), )*
- &[CString::new(b"".as_ref()).unwrap(),
- CString::new(b"-c".as_ref()).unwrap(),
- CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz"
- .as_ref()).unwrap()],
- &[CString::new(b"foo=bar".as_ref()).unwrap(),
- CString::new(b"baz=quux".as_ref()).unwrap()]
+ &[CString::from(CStr::from_bytes_with_nul(EMPTY).unwrap()),
+ CString::from(CStr::from_bytes_with_nul(DASH_C).unwrap()),
+ CString::from(CStr::from_bytes_with_nul(BIGARG).unwrap())],
+ &[CString::from(CStr::from_bytes_with_nul(FOO).unwrap()),
+ CString::from(CStr::from_bytes_with_nul(BAZ).unwrap())]
$(, $flags)*)
}
@@ -329,11 +335,17 @@ macro_rules! execve_test_factory(
}
}
+ // These tests frequently fail on musl, probably due to
+ // https://github.com/nix-rust/nix/issues/555
+ #[cfg_attr(target_env = "musl", ignore)]
#[test]
fn test_cstr_ref() {
common_test(syscall_cstr_ref);
}
+ // These tests frequently fail on musl, probably due to
+ // https://github.com/nix-rust/nix/issues/555
+ #[cfg_attr(target_env = "musl", ignore)]
#[test]
fn test_cstring() {
common_test(syscall_cstring);
@@ -349,6 +361,8 @@ cfg_if!{
execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd());
} else if #[cfg(any(target_os = "freebsd",
target_os = "linux"))] {
+ // These tests frequently fail on musl, probably due to
+ // https://github.com/nix-rust/nix/issues/555
execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str());
execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd());
} else if #[cfg(any(target_os = "dragonfly",
@@ -371,13 +385,16 @@ execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap());
cfg_if!{
if #[cfg(target_os = "android")] {
use nix::fcntl::AtFlags;
- execve_test_factory!(test_execveat_empty, execveat, File::open("/system/bin/sh").unwrap().into_raw_fd(),
+ execve_test_factory!(test_execveat_empty, execveat,
+ File::open("/system/bin/sh").unwrap().into_raw_fd(),
"", AtFlags::AT_EMPTY_PATH);
- execve_test_factory!(test_execveat_relative, execveat, File::open("/system/bin/").unwrap().into_raw_fd(),
+ execve_test_factory!(test_execveat_relative, execveat,
+ File::open("/system/bin/").unwrap().into_raw_fd(),
"./sh", AtFlags::empty());
- execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(),
+ execve_test_factory!(test_execveat_absolute, execveat,
+ File::open("/").unwrap().into_raw_fd(),
"/system/bin/sh", AtFlags::empty());
- } else if #[cfg(all(target_os = "linux"), any(target_arch ="x86_64", target_arch ="x86"))] {
+ } else if #[cfg(all(target_os = "linux", any(target_arch ="x86_64", target_arch ="x86")))] {
use nix::fcntl::AtFlags;
execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(),
"", AtFlags::AT_EMPTY_PATH);
@@ -389,6 +406,7 @@ cfg_if!{
}
#[test]
+#[cfg(not(target_os = "fuchsia"))]
fn test_fchdir() {
// fchdir changes the process's cwd
let _dr = crate::DirRestore::new();
@@ -459,9 +477,7 @@ fn test_fchown() {
fchown(fd, uid, gid).unwrap();
fchown(fd, uid, None).unwrap();
fchown(fd, None, gid).unwrap();
-
- mem::drop(path);
- fchown(fd, uid, gid).unwrap_err();
+ fchown(999999999, uid, gid).unwrap_err();
}
#[test]
@@ -537,7 +553,7 @@ cfg_if!{
skip_if_jailed!("test_acct");
}
}
- } else if #[cfg(not(target_os = "redox"))] {
+ } else if #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] {
macro_rules! require_acct{
() => {
skip_if_not_root!("test_acct");
@@ -547,7 +563,7 @@ cfg_if!{
}
#[test]
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
fn test_acct() {
use tempfile::NamedTempFile;
use std::process::Command;
@@ -634,7 +650,7 @@ fn test_pipe2() {
}
#[test]
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
fn test_truncate() {
let tempdir = tempdir().unwrap();
let path = tempdir.path().join("file");
@@ -684,6 +700,12 @@ pub extern fn alarm_signal_handler(raw_signal: libc::c_int) {
#[test]
#[cfg(not(target_os = "redox"))]
fn test_alarm() {
+ use std::{
+ time::{Duration, Instant,},
+ thread
+ };
+
+ // Maybe other tests that fork interfere with this one?
let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
let handler = SigHandler::Handler(alarm_signal_handler);
@@ -701,8 +723,16 @@ fn test_alarm() {
// We should be woken up after 1 second by the alarm, so we'll sleep for 2
// seconds to be sure.
- sleep(2);
- assert_eq!(unsafe { ALARM_CALLED }, true, "expected our alarm signal handler to be called");
+ let starttime = Instant::now();
+ loop {
+ thread::sleep(Duration::from_millis(100));
+ if unsafe { ALARM_CALLED} {
+ break;
+ }
+ if starttime.elapsed() > Duration::from_secs(3) {
+ panic!("Timeout waiting for SIGALRM");
+ }
+ }
// Reset the signal.
unsafe {
@@ -976,8 +1006,9 @@ fn test_setfsuid() {
let nobody = User::from_name("nobody").unwrap().unwrap();
// create a temporary file with permissions '-rw-r-----'
- let file = tempfile::NamedTempFile::new().unwrap();
+ let file = tempfile::NamedTempFile::new_in("/var/tmp").unwrap();
let temp_path = file.into_temp_path();
+ dbg!(&temp_path);
let temp_path_2 = (&temp_path).to_path_buf();
let mut permissions = fs::metadata(&temp_path).unwrap().permissions();
permissions.set_mode(640);
@@ -1003,7 +1034,7 @@ fn test_setfsuid() {
}
#[test]
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
fn test_ttyname() {
let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed");
assert!(fd.as_raw_fd() > 0);
@@ -1026,7 +1057,7 @@ fn test_ttyname() {
}
#[test]
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
fn test_ttyname_not_pty() {
let fd = File::open("/dev/zero").unwrap();
assert!(fd.as_raw_fd() > 0);
@@ -1034,13 +1065,46 @@ fn test_ttyname_not_pty() {
}
#[test]
-#[cfg(all(not(target_os = "redox"), not(target_env = "musl")))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
fn test_ttyname_invalid_fd() {
assert_eq!(ttyname(-1), Err(Error::Sys(Errno::EBADF)));
}
#[test]
-#[cfg(all(not(target_os = "redox"), target_env = "musl"))]
-fn test_ttyname_invalid_fd() {
- assert_eq!(ttyname(-1), Err(Error::Sys(Errno::ENOTTY)));
+#[cfg(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+))]
+fn test_getpeereid() {
+ use std::os::unix::net::UnixStream;
+ let (sock_a, sock_b) = UnixStream::pair().unwrap();
+
+ let (uid_a, gid_a) = getpeereid(sock_a.as_raw_fd()).unwrap();
+ let (uid_b, gid_b) = getpeereid(sock_b.as_raw_fd()).unwrap();
+
+ let uid = geteuid();
+ let gid = getegid();
+
+ assert_eq!(uid, uid_a);
+ assert_eq!(gid, gid_a);
+ assert_eq!(uid_a, uid_b);
+ assert_eq!(gid_a, gid_b);
+}
+
+#[test]
+#[cfg(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+))]
+fn test_getpeereid_invalid_fd() {
+ // getpeereid is not POSIX, so error codes are inconsistent between different Unices.
+ assert!(getpeereid(-1).is_err());
}